// tools/estimate.ts — Estimate difficulty, hours, tokens, costs for a spec
// Uses the estimator engine with historical metrics for calibration.
import { specStore, metricsStore, globalStore, knowledgeStore } from '../storage/index.js';
import { computeCorrectionFactors, applyCorrection } from '../engine/estimation-predictor.js';
import { getCalibration, listActuals } from '../storage/actuals-store.js';
import { applyCalibration } from '../engine/estimation-calibrator.js';
import { estimateSpec } from '../engine/estimator.js';
import { classifyOperation, recommendModel } from '../engine/token-tracker.js';
import { buildEstimateSummary } from '../engine/human-summary.js';
import { ti } from '../i18n/index.js';
import { createBasicPhaseEvent, formatByLevel } from '../engine/phase-tracker.js';
import { enrichEstimationWithVelocity } from './create-spec/adapters/velocity-estimation.js';
export async function handleEstimate(args) {
    const { specId, projectId } = args;
    // 1. Load spec
    const spec = await specStore.getSpec(projectId, specId);
    if (!spec) {
        return {
            content: [{ type: 'text', text: ti('spec.notFound', { id: specId }) }],
            isError: true,
        };
    }
    // 2. Load global config for pricing/hourly rate
    const globalConfig = await globalStore.getGlobalConfig();
    // 3. Load project knowledge for potential overrides
    const knowledge = await knowledgeStore.getKnowledge(projectId);
    const configOverrides = {
        ...globalConfig,
        ...(knowledge?.experienceLevel === 'beginner'
            ? { hourlyRate: globalConfig.hourlyRate * 0.7 }
            : {}),
        ...(knowledge?.experienceLevel === 'expert'
            ? { hourlyRate: globalConfig.hourlyRate * 1.3 }
            : {}),
    };
    // 4. Load historical metrics for calibration
    const metricsHistory = await metricsStore.getMetricsHistory(projectId);
    // 5. Run estimation engine
    const result = estimateSpec(spec, configOverrides, metricsHistory.entries);
    // 5a. SPEC-287: Apply SPEC-287 calibration factors on top of existing estimation
    const calibrationFactors = await getCalibration(projectId).catch(() => null);
    let calibrationNote = null;
    if (calibrationFactors) {
        const rawHours = result.estimation.devHours + result.estimation.reviewHours;
        const calibratedHours = applyCalibration(rawHours, spec.scope, spec.type, calibrationFactors);
        if (calibratedHours !== rawHours) {
            const ratio = calibratedHours / rawHours;
            result.estimation.devHours = Math.round(result.estimation.devHours * ratio * 10) / 10;
            result.estimation.reviewHours = Math.round(result.estimation.reviewHours * ratio * 10) / 10;
            result.estimation.humanCostUsd =
                Math.round((result.estimation.devHours + result.estimation.reviewHours) *
                    result.estimation.hourlyRate *
                    100) / 100;
            result.estimation.totalCostUsd =
                Math.round((result.estimation.apiCostUsd + result.estimation.humanCostUsd) * 100) / 100;
            calibrationNote = `Calibration applied (${spec.scope}/${spec.type}): ${String(rawHours)}h → ${String(calibratedHours)}h`;
        }
    }
    // 5b. SPEC-570: Predictive correction from historical actuals (bucket-level bias)
    const allActuals = await listActuals(projectId).catch(() => []);
    const buckets = computeCorrectionFactors(allActuals);
    const predBucketKey = `${spec.scope}:${spec.type}`;
    const matchedBucket = buckets.find((b) => b.key === predBucketKey);
    if (matchedBucket !== undefined && matchedBucket.sampleSize >= 3) {
        const baseHours = result.estimation.devHours + result.estimation.reviewHours;
        const predictionResult = applyCorrection(baseHours, matchedBucket);
        result.correctedHours = predictionResult.correctedHours;
        result.confidenceInterval = predictionResult.confidenceInterval;
        result.calibrationBasis = predictionResult.calibrationBasis;
    }
    // 6. Update spec with estimation data
    await specStore.updateSpec(projectId, specId, {
        estimation: result.estimation,
        difficulty: result.difficulty,
    });
    // 7. Build output
    const est = result.estimation;
    // SPEC-012: Enrich output with token optimization and model recommendation
    const tokenMode = classifyOperation('estimate');
    const suggestedModel = recommendModel('estimate');
    // SPEC-555: Enrich with calendar days from velocity profile (best-effort)
    const projectPath = knowledge?.projectPath ?? '';
    const velocityEnrichment = await enrichEstimationWithVelocity(projectPath, est.devHours);
    const output = {
        specId,
        difficulty: result.difficulty,
        confidence: result.confidence,
        estimation: {
            devHours: est.devHours,
            reviewHours: est.reviewHours,
            totalHours: Math.round((est.devHours + est.reviewHours) * 10) / 10,
            recommendedModel: est.recommendedModel,
            tokensOpus: est.tokensOpus,
            tokensSonnet: est.tokensSonnet,
            apiCostUsd: est.apiCostUsd,
            humanCostUsd: est.humanCostUsd,
            totalCostUsd: est.totalCostUsd,
            tokenOptimization: est.tokenOptimization,
            calendarDays: velocityEnrichment.calendarDays,
            velocityNote: velocityEnrichment.velocityNote,
        },
        tokenStrategy: {
            operationMode: tokenMode,
            suggestedAiModel: suggestedModel,
            modelRationale: `Use ${suggestedModel} for estimation — moderate reasoning, spec analysis`,
        },
        reasoning: result.reasoning,
        similarSpecs: result.similarSpecs,
        historyUsed: metricsHistory.entries.length > 0,
        calibrationApplied: calibrationNote,
        correctedHours: result.correctedHours,
        confidenceInterval: result.confidenceInterval,
        calibrationBasis: result.calibrationBasis,
    };
    const level = knowledge?.experienceLevel ?? 'intermediate';
    const summary = formatByLevel(ti('tools.estimate.success', {
        specId,
        devHours: String(est.devHours),
        totalCostUsd: String(est.totalCostUsd),
    }), ti('tools.estimate.success', {
        specId,
        devHours: String(est.devHours),
        totalCostUsd: String(est.totalCostUsd),
    }), `${specId}: ${est.devHours}h dev | $${est.totalCostUsd} USD | confidence: ${result.confidence}`, level);
    const totalHours = Math.round((est.devHours + est.reviewHours) * 10) / 10;
    const humanSummary = buildEstimateSummary(spec.title, totalHours, 0);
    return {
        phaseEvent: createBasicPhaseEvent('estimate', 'completed', 100, 'analyzing'),
        content: [
            { type: 'text', text: summary },
            { type: 'text', text: humanSummary },
        ],
        // structuredContent requires Record<string,unknown>; output is a typed JSON-serializable object.
        structuredContent: { ...output, humanSummary },
    };
}
//# sourceMappingURL=estimate.js.map