// engine/estimator/history.ts — Historical adjustment and accuracy calculation
import { calibrateEstimate } from '../calibrator.js';
import { roundTo, determineConfidence, buildReasoning } from '../estimator-helpers.js';
import { DEFAULT_CONFIG, REVIEW_RATIO } from './constants.js';
import { calculateEstimation } from './calculations.js';
// === Difficulty inference ===
/**
 * Infer difficulty from type and scope when not explicitly provided.
 */
export function inferDifficulty(type, scope) {
    const matrix = {
        trivial: {
            feature: 1,
            refactor: 1,
            bugfix: 1,
            infra: 1,
            docs: 1,
            project: 2,
            agent: 2,
            'tech-debt': 2,
        },
        feature: {
            feature: 2,
            refactor: 2,
            bugfix: 2,
            infra: 3,
            docs: 1,
            project: 3,
            agent: 3,
            'tech-debt': 2,
        },
        'cross-module': {
            feature: 3,
            refactor: 3,
            bugfix: 3,
            infra: 4,
            docs: 2,
            project: 4,
            agent: 4,
            'tech-debt': 3,
        },
        architectural: {
            feature: 4,
            refactor: 4,
            bugfix: 4,
            infra: 5,
            docs: 3,
            project: 5,
            agent: 5,
            'tech-debt': 4,
        },
    };
    return matrix[scope][type];
}
// === Accuracy calculation ===
/**
 * Calculate accuracy score comparing estimation vs actuals.
 * Returns 0-100 where 100 = perfectly accurate.
 */
export function calculateAccuracy(estimated, actualHours) {
    if (actualHours === 0) {
        return 100;
    }
    const totalEstimated = estimated.devHours + estimated.reviewHours;
    const ratio = totalEstimated / actualHours;
    const deviation = Math.abs(1 - ratio);
    const score = Math.max(0, 100 - deviation * 100);
    return roundTo(score, 1);
}
// === History-based adjustment ===
function findSimilarSpecs(spec, history) {
    return history.filter((entry) => {
        const diffDelta = Math.abs(entry.difficulty - spec.difficulty);
        return diffDelta <= 1;
    });
}
function adjustFromHistory(estimation, similar) {
    if (similar.length < 3) {
        return estimation;
    }
    const ratios = similar.map((s) => {
        const estimatedTotal = s.estimated.devHours + s.estimated.reviewHours;
        const actualTotal = s.actual.devHours + s.actual.reviewHours;
        return actualTotal > 0 ? estimatedTotal / actualTotal : 1;
    });
    const avgRatio = ratios.reduce((a, b) => a + b, 0) / ratios.length;
    if (Math.abs(1 - avgRatio) < 0.1) {
        return estimation;
    }
    const adjustmentFactor = 1 / avgRatio;
    const adjustedDevHours = roundTo(estimation.devHours * adjustmentFactor, 1);
    const adjustedReviewHours = roundTo(estimation.reviewHours * adjustmentFactor, 1);
    return {
        ...estimation,
        devHours: adjustedDevHours,
        reviewHours: adjustedReviewHours,
        humanCostUsd: roundTo((adjustedDevHours + adjustedReviewHours) * estimation.hourlyRate, 2),
        totalCostUsd: roundTo(estimation.apiCostUsd + (adjustedDevHours + adjustedReviewHours) * estimation.hourlyRate, 2),
    };
}
// === Main estimator ===
/**
 * Estimate effort, tokens, and cost for a spec.
 * TEMPLATE METHOD PATTERN: fixed algorithm with optional calibration hook (SPEC-011).
 */
export function estimateSpec(spec, config = {}, history = [], calibration = null) {
    const cfg = { ...DEFAULT_CONFIG, ...config };
    const difficulty = spec.difficulty;
    const estimation = calculateEstimation(spec.type, spec.scope, difficulty, cfg);
    const similarSpecs = findSimilarSpecs(spec, history);
    const confidence = determineConfidence(difficulty, spec.scope, similarSpecs.length);
    let adjusted = adjustFromHistory(estimation, similarSpecs);
    if (calibration) {
        const { adjustedHours, adjustmentFactor } = calibrateEstimate(adjusted.devHours, spec.type, spec.scope, calibration);
        if (adjustmentFactor !== 1.0) {
            const reviewHours = roundTo(adjustedHours * REVIEW_RATIO[difficulty], 1);
            adjusted = {
                ...adjusted,
                devHours: adjustedHours,
                reviewHours,
                humanCostUsd: roundTo((adjustedHours + reviewHours) * cfg.hourlyRate, 2),
                totalCostUsd: roundTo(adjusted.apiCostUsd + (adjustedHours + reviewHours) * cfg.hourlyRate, 2),
            };
        }
    }
    const reasoning = buildReasoning(spec, adjusted, confidence, similarSpecs.length);
    return {
        difficulty,
        estimation: adjusted,
        confidence,
        reasoning,
        similarSpecs: similarSpecs.map((s) => s.specId),
    };
}
//# sourceMappingURL=history.js.map