import { z } from 'zod';
import { createCommand } from "../../../types.js";
import * as tui from "../../../tui.js";
import { getCommand } from "../../../command-prefix.js";
import { getExecutingAgent } from "../../../agent-detection.js";
import { createPublicAIGatewayService, getAIGatewayUrl } from "./util.js";
import { getCachedAIGatewayModels, setCachedAIGatewayModels } from "./model-cache.js";
const ModelRowSchema = z.object({
    provider: z.string(),
    id: z.string(),
    name: z.string(),
    api: z.string().optional(),
    inputModalities: z.array(z.string()).optional(),
    outputModalities: z.array(z.string()).optional(),
    pricingUnit: z.string().optional(),
    pricingInput: z.number().optional(),
    pricingOutput: z.number().optional(),
    reasoning: z.boolean().optional(),
    recommended: z.boolean().optional(),
    defaultFor: z.array(z.string()).optional(),
    rank: z.number().optional(),
    contextWindow: z.number().optional(),
    maxOutputTokens: z.number().optional(),
});
const ModelsResponseSchema = z.object({
    models: z.array(ModelRowSchema),
    count: z.number(),
    model: ModelRowSchema.nullable().optional(),
    recommendations: z
        .array(z.object({
        use: z.string(),
        model: z.string(),
        name: z.string(),
        rank: z.number().optional(),
    }))
        .optional(),
});
function isAgentOutputMode() {
    return Boolean(getExecutingAgent()) && process.env.AGENTUITY_AIGATEWAY_AGENT_OUTPUT !== 'false';
}
function getRecommendations(rows) {
    const recommendations = new Map();
    for (const row of rows) {
        if (!row.recommended || !row.defaultFor || row.defaultFor.length === 0) {
            continue;
        }
        for (const use of row.defaultFor) {
            const existing = recommendations.get(use);
            if (!existing ||
                (row.rank ?? Number.MAX_SAFE_INTEGER) < (existing.rank ?? Number.MAX_SAFE_INTEGER)) {
                recommendations.set(use, row);
            }
        }
    }
    return Array.from(recommendations.entries())
        .sort(([a], [b]) => a.localeCompare(b))
        .map(([use, model]) => {
        return {
            use,
            model: model.id.startsWith(`${model.provider}/`)
                ? model.id
                : `${model.provider}/${model.id}`,
            name: model.name,
            rank: model.rank,
        };
    });
}
function matchesProviderFilter(provider, modelId, providerFilter) {
    if (!providerFilter) {
        return true;
    }
    return provider === providerFilter || modelId.startsWith(`${providerFilter}/`);
}
function matchesModelFilter(provider, modelId, modelFilter) {
    if (!modelFilter) {
        return true;
    }
    return modelId === modelFilter || `${provider}/${modelId}` === modelFilter;
}
function matchesNameFilter(modelId, modelName, nameFilter) {
    if (!nameFilter) {
        return true;
    }
    const normalized = nameFilter.toLowerCase();
    return (modelId.toLowerCase() === normalized ||
        modelId.split('/').pop()?.toLowerCase() === normalized ||
        modelName.toLowerCase() === normalized);
}
export const modelsSubcommand = createCommand({
    name: 'models',
    aliases: ['list', 'ls'],
    description: 'List AI Gateway models',
    tags: ['read-only', 'fast'],
    idempotent: true,
    examples: [
        { command: getCommand('cloud aigateway models'), description: 'List all models' },
        {
            command: getCommand('cloud aigateway models --provider openai'),
            description: 'List OpenAI models',
        },
        {
            command: getCommand('cloud aigateway models --model anthropic/claude-opus-4-7'),
            description: 'Show one model by id',
        },
    ],
    schema: {
        options: z.object({
            model: z.string().optional().describe('show one model by full provider/id'),
            provider: z.string().optional().describe('filter by provider'),
            name: z
                .string()
                .optional()
                .describe('show one model by id or display name with --provider'),
            reasoning: z.boolean().optional().describe('only show reasoning models'),
            inputModality: z
                .string()
                .optional()
                .describe('filter by input modality, such as text or image'),
            outputModality: z
                .string()
                .optional()
                .describe('filter by output modality, such as text or image'),
            input: z.string().optional().describe('deprecated alias for --input-modality'),
            output: z.string().optional().describe('deprecated alias for --output-modality'),
            ids: z.boolean().optional().describe('only print model ids'),
            simple: z.boolean().optional().describe('print a compact model list'),
            recommended: z.boolean().optional().describe('show recommended models for common uses'),
            refreshModels: z
                .boolean()
                .optional()
                .describe('refresh the cached AI Gateway model catalog'),
        }),
        response: ModelsResponseSchema,
    },
    async handler(ctx) {
        const service = createPublicAIGatewayService(ctx);
        const profile = ctx.config?.name ?? 'default';
        const cacheKey = getAIGatewayUrl(ctx.region, ctx.config?.overrides);
        const cached = ctx.opts.refreshModels
            ? null
            : await getCachedAIGatewayModels(profile, cacheKey);
        const catalog = cached ?? (await service.listModels());
        if (!cached) {
            await setCachedAIGatewayModels(profile, cacheKey, catalog);
        }
        const inputModality = ctx.opts.inputModality ?? ctx.opts.input;
        const outputModality = ctx.opts.outputModality ?? ctx.opts.output;
        const rows = Object.entries(catalog).flatMap(([provider, models]) => models
            .filter((model) => matchesProviderFilter(provider, model.id, ctx.opts.provider))
            .filter((model) => matchesModelFilter(provider, model.id, ctx.opts.model))
            .filter((model) => matchesNameFilter(model.id, model.name, ctx.opts.name))
            .filter((model) => !ctx.opts.reasoning || model.reasoning)
            .filter((model) => !inputModality || model.input_modalities?.includes(inputModality))
            .filter((model) => !outputModality || model.output_modalities?.includes(outputModality))
            .map((model) => ({
            provider,
            id: model.id,
            name: model.name,
            api: model.api,
            inputModalities: model.input_modalities,
            outputModalities: model.output_modalities,
            pricingUnit: model.pricing?.unit,
            pricingInput: model.pricing?.input,
            pricingOutput: model.pricing?.output,
            reasoning: model.reasoning,
            recommended: model.recommended,
            defaultFor: model.default_for,
            rank: model.rank,
            contextWindow: model.context_window,
            maxOutputTokens: model.max_output_tokens,
        })));
        const singleLookup = Boolean(ctx.opts.model || ctx.opts.name);
        const selectedModel = singleLookup ? (rows[0] ?? null) : undefined;
        const agentOutput = isAgentOutputMode();
        if (ctx.options.json || agentOutput) {
            if (agentOutput && !ctx.options.json) {
                if (ctx.opts.ids) {
                    console.log(JSON.stringify({ ids: rows.map((row) => row.id), count: rows.length }, null, 2));
                }
                else if (ctx.opts.recommended) {
                    console.log(JSON.stringify({ recommendations: getRecommendations(rows) }, null, 2));
                }
                else if (singleLookup) {
                    console.log(JSON.stringify({ model: selectedModel, models: rows, count: rows.length }, null, 2));
                }
                else {
                    console.log(JSON.stringify({ models: rows, count: rows.length }, null, 2));
                }
            }
        }
        else {
            if (rows.length === 0) {
                tui.info('No AI Gateway models found');
            }
            else if (ctx.opts.ids) {
                for (const row of rows) {
                    console.log(row.id);
                }
            }
            else if (ctx.opts.recommended) {
                const recommendations = getRecommendations(rows).map((row) => ({
                    Use: row.use,
                    Model: row.model,
                    Name: row.name,
                    Rank: row.rank ?? '-',
                }));
                if (recommendations.length === 0) {
                    tui.info('No recommended AI Gateway models found');
                }
                else {
                    tui.table(recommendations, ['Use', 'Model', 'Name', 'Rank']);
                }
            }
            else if (ctx.opts.simple) {
                tui.table(rows.map((row) => ({
                    Model: row.id,
                    Name: row.name,
                })), ['Model', 'Name']);
            }
            else {
                tui.info(`Found ${rows.length} AI Gateway model(s):`);
                tui.table(rows.map((row) => ({
                    Provider: row.provider,
                    Model: row.id,
                    Name: row.name,
                    API: row.api ?? '-',
                    Input: row.inputModalities?.join(',') ?? '-',
                    Output: row.outputModalities?.join(',') ?? '-',
                    Unit: row.pricingUnit ?? '-',
                    Reasoning: row.reasoning ? 'yes' : 'no',
                    Default: row.defaultFor?.join(',') ?? '-',
                    Context: row.contextWindow ?? '-',
                })), [
                    'Provider',
                    'Model',
                    'Name',
                    'API',
                    'Input',
                    'Output',
                    'Unit',
                    'Reasoning',
                    'Default',
                    'Context',
                ]);
            }
        }
        return {
            models: rows,
            count: rows.length,
            model: selectedModel,
            ...(ctx.opts.recommended ? { recommendations: getRecommendations(rows) } : {}),
        };
    },
});
//# sourceMappingURL=models.js.map