// engine/ai-cost-estimator/core.ts — Orchestrates AI cost estimation for specs.
// Coordinates token-estimator + model-pricing to produce AiCostEstimateResult.
import { loadPricingConfig, getAllModels, calculateCost, calculateAgentTurns, isPricingStale, } from './model-pricing.js';
import { buildTokenEstimate } from './token-estimator.js';
import { loadSpecContent, countAcceptanceCriteria, readUsageAvgTokensPerCall, } from './spec-loader.js';
import { selectRecommendedModel, buildRecommendationReason, formatMarkdownTable, } from './recommender.js';
// ---------------------------------------------------------------------------
// Complexity thresholds
// ---------------------------------------------------------------------------
const LOW_COMPLEXITY_MAX_AC = 5;
const MEDIUM_COMPLEXITY_MAX_AC = 12;
/** Returns the confidence range percentage based on number of acceptance criteria. */
function getConfidenceRangePct(acCount) {
    if (acCount <= LOW_COMPLEXITY_MAX_AC) {
        return 20;
    }
    if (acCount <= MEDIUM_COMPLEXITY_MAX_AC) {
        return 30;
    }
    return 40;
}
/** Returns the complexity level label for a given AC count. */
function getComplexityLevel(acCount) {
    if (acCount <= LOW_COMPLEXITY_MAX_AC) {
        return 'low';
    }
    if (acCount <= MEDIUM_COMPLEXITY_MAX_AC) {
        return 'medium';
    }
    return 'high';
}
// ---------------------------------------------------------------------------
// Main orchestrator
// ---------------------------------------------------------------------------
/**
 * Estimates the AI cost for implementing a spec.
 * Reads the spec from planu/specs/ (or legacy docs/sdd/specs/), loads pricing from config JSON,
 * and returns a full AiCostEstimateResult with per-model breakdown.
 */
export async function estimateAiCost(input) {
    const { specId, projectPath } = input;
    // 1. Load spec content
    const { content: specContent } = await loadSpecContent(specId);
    const acCount = countAcceptanceCriteria(specContent);
    // 2. Load pricing config
    const config = await loadPricingConfig();
    const models = await getAllModels();
    // 3. Build token estimate
    const usageAvg = await readUsageAvgTokensPerCall();
    const tokenEstimate = await buildTokenEstimate(specContent, 0, // No pre-existing LOC estimate — use AC-based fallback
    acCount, projectPath, config, usageAvg);
    // 4. Determine complexity + confidence
    const complexity = getComplexityLevel(acCount);
    const confidenceRangePct = getConfidenceRangePct(acCount);
    // 5. Calculate per-model estimates
    const estimates = models.map((model) => {
        const estimatedCostUsd = calculateCost(model, tokenEstimate.inputTokens, tokenEstimate.outputTokens);
        const agentTurns = calculateAgentTurns(model, tokenEstimate.locToGenerate);
        return {
            modelId: model.id,
            displayName: model.displayName,
            inputTokens: tokenEstimate.inputTokens,
            outputTokens: tokenEstimate.outputTokens,
            estimatedCostUsd,
            confidenceRangePct,
            agentTurns,
        };
    });
    // 6. Determine recommendation
    const recommendedModel = selectRecommendedModel(models, complexity);
    // Calculate savings vs most expensive model
    const maxCost = Math.max(...estimates.map((e) => e.estimatedCostUsd));
    const recommendedEstimate = estimates.find((e) => e.modelId === recommendedModel.id);
    const recommendedCost = recommendedEstimate?.estimatedCostUsd ?? 0;
    const savingsVsExpensiveModel = Math.max(0, maxCost - recommendedCost);
    const recommendationReason = buildRecommendationReason(recommendedModel, complexity, savingsVsExpensiveModel);
    // 7. Check if pricing is stale
    const staleWarning = isPricingStale(config.lastUpdated)
        ? `Los precios del modelo pueden estar desactualizados (última actualización: ${config.lastUpdated}). ` +
            'Verifica los precios actuales en la documentación de cada proveedor.'
        : '';
    // 8. Format markdown table
    const markdownTable = formatMarkdownTable(estimates, recommendedModel.id, recommendationReason, staleWarning);
    return {
        specId,
        estimates,
        recommendedModelId: recommendedModel.id,
        recommendationReason,
        savingsVsExpensiveModel,
        markdownTable,
    };
}
//# sourceMappingURL=core.js.map