/**
 * Confidence Engine — 답변 확신도 0~100 결정론적 산출.
 *
 * Self-Evolving OS 마스터 플랜 Phase 2 / Track 1-1. 신뢰 조건 T4
 * "확신이 없으면 사람에게 묻는다" 의 측정 기반 — Escalation Engine 의 입력.
 *
 * 설계 원칙 (termValidator 와 동일): LLM 호출 없음. 검색 그라운딩 신호(턴 컨텍스트)와
 * 답변 텍스트 신호(정규식)만으로 산출 — 매 turn 안전 실행, latency 0.
 *
 * 점수는 "모델이 얼마나 자신 있나" 가 아니라 "이 답변을 검증 없이 신뢰해도 되는
 * 근거가 얼마나 갖춰졌나" 를 측정한다. 따라서 모델이 솔직하게 "(확인 필요)" 를
 * 표시하면 점수가 *내려가는* 것이 올바른 동작 — 사용자 검토를 유도해야 하므로.
 *
 * 구간 (설계서 7.5):
 *   90+    높음        — 그대로 신뢰 가능
 *   70~89  보통        — 일반 업무 통과
 *   50~69  낮음        — 업무 산출물이면 검토 권장
 *   <50    매우 낮음   — 추가 조사 / 인간 검토 필요 (Escalation)
 */

/** 검색(pre-answer) 신호 — memoryContext 가 turn 마다 채움. */
export interface RetrievalConfidenceSignals {
    /** 선택된 검색 청크 수 (brain-trace 제외). */
    chunkCount: number;
    /** 최고 청크 score (0~1 정규화). 청크 없으면 0. */
    topScore: number;
    /** conflictSeverity 가 NONE 이 아닌 청크 수. */
    conflictCount: number;
    /** Intent Clarification 이 모호성을 감지했는가. */
    ambiguityDetected: boolean;
}

export interface ConfidenceFactor {
    /** 점수에 기여한 요인 설명 (footer 표시용). */
    label: string;
    /** 기여 점수 (±). */
    delta: number;
}

export type ConfidenceBand = 'high' | 'medium' | 'low' | 'very-low';

export interface ConfidenceResult {
    score: number;            // 0~100
    band: ConfidenceBand;
    bandLabel: string;        // 높음/보통/낮음/매우 낮음
    factors: ConfidenceFactor[];
}

const BAND_LABELS: Record<ConfidenceBand, string> = {
    'high': '높음',
    'medium': '보통',
    'low': '낮음',
    'very-low': '매우 낮음',
};

export function toBand(score: number): ConfidenceBand {
    if (score >= 90) return 'high';
    if (score >= 70) return 'medium';
    if (score >= 50) return 'low';
    return 'very-low';
}

/** 답변 텍스트에서 추출하는 신호. */
export interface AnswerConfidenceSignals {
    /** 헤지 마커 수 — "(확인 필요)", "추정", "확실하지 않" 등. */
    hedgeCount: number;
    /** 답변 끝 출처 라인이 검색 출처를 인용하는가. */
    hasCitation: boolean;
    /** 출처 라인이 "모델 지식" 만 표기하는가 (검색 출처 미사용). */
    modelKnowledgeOnly: boolean;
    /** Requirement 커버리지 — 검사 안 했으면 null. */
    coverageMissing: number | null;
}

const HEDGE_PATTERN = /\(확인 필요\)|\(담당자 미정\)|\(기한 미정\)|추정(?:치|입니다|됩니다)?|확실하지 않|정확하지 않을 수|모르겠|알 수 없/g;

/** 답변 텍스트 → 신호 추출 (결정론적). coverageMissing 은 호출자가 채움. */
export function extractAnswerSignals(assistantAnswer: string, coverageMissing: number | null): AnswerConfidenceSignals {
    const text = assistantAnswer || '';
    const hedges = text.match(HEDGE_PATTERN);
    const citationLine = /\*?출처:?\*?\s*(.+)/.exec(text);
    const citationBody = citationLine ? citationLine[1] : '';
    const modelKnowledgeOnly = /모델 지식/.test(citationBody);
    return {
        hedgeCount: hedges ? hedges.length : 0,
        hasCitation: !!citationLine && !modelKnowledgeOnly,
        modelKnowledgeOnly,
        coverageMissing,
    };
}

/**
 * 확신도 산출. 가중치는 휴리스틱 v1 — Phase 3 Self Evaluation 골든셋이 쌓이면
 * 사람 평가와의 상관으로 보정한다 (KPI: Need Accuracy).
 */
export function computeConfidence(
    retrieval: RetrievalConfidenceSignals,
    answer: AnswerConfidenceSignals,
): ConfidenceResult {
    const factors: ConfidenceFactor[] = [];
    let score = 55; // 중립 출발점 — 신호가 전무하면 "낮음" 상단

    // ─── 그라운딩 (최대 +25 / -15) ───
    if (retrieval.chunkCount >= 3 && retrieval.topScore >= 0.5) {
        factors.push({ label: `검색 근거 ${retrieval.chunkCount}건(강)`, delta: +25 });
    } else if (retrieval.chunkCount >= 1) {
        factors.push({ label: `검색 근거 ${retrieval.chunkCount}건`, delta: +12 });
    } else {
        factors.push({ label: '검색 근거 없음 (모델 일반 지식)', delta: -15 });
    }

    // ─── 출처 인용 (+8 / -5) ───
    if (answer.hasCitation) {
        factors.push({ label: '출처 인용 있음', delta: +8 });
    } else if (answer.modelKnowledgeOnly) {
        factors.push({ label: '모델 지식만 사용 명시', delta: -5 });
    }

    // ─── 지식 충돌 (건당 -8, 최대 -16) ───
    if (retrieval.conflictCount > 0) {
        const d = -Math.min(16, retrieval.conflictCount * 8);
        factors.push({ label: `출처 간 충돌 ${retrieval.conflictCount}건`, delta: d });
    }

    // ─── 요청 모호성 (-10) ───
    if (retrieval.ambiguityDetected) {
        factors.push({ label: '요청 모호성 감지', delta: -10 });
    }

    // ─── Requirement 커버리지 (+10 / 누락당 -6, 최대 -18) ───
    if (answer.coverageMissing !== null) {
        if (answer.coverageMissing === 0) {
            factors.push({ label: '필수 요소 전부 충족', delta: +10 });
        } else {
            const d = -Math.min(18, answer.coverageMissing * 6);
            factors.push({ label: `필수 요소 ${answer.coverageMissing}개 누락 가능`, delta: d });
        }
    }

    // ─── 헤지 표현 (개당 -4, 최대 -12) — 솔직한 불확실 표시 = 검토 유도 ───
    if (answer.hedgeCount > 0) {
        const d = -Math.min(12, answer.hedgeCount * 4);
        factors.push({ label: `불확실 표시 ${answer.hedgeCount}곳`, delta: d });
    }

    for (const f of factors) score += f.delta;
    score = Math.max(0, Math.min(100, Math.round(score)));
    const band = toBand(score);
    return { score, band, bandLabel: BAND_LABELS[band], factors };
}

/**
 * 확신도 footer 한 줄. 항상 표시 (사용자가 매 답변의 신뢰 수준을 보도록) —
 * 끄려면 g1nation.confidenceEngineEnabled=false.
 */
export function formatConfidenceFooter(result: ConfidenceResult): string {
    const icon = result.band === 'high' ? '🟢' : result.band === 'medium' ? '🔵' : result.band === 'low' ? '🟡' : '🔴';
    const top = result.factors
        .slice()
        .sort((a, b) => Math.abs(b.delta) - Math.abs(a.delta))
        .slice(0, 3)
        .map((f) => f.label)
        .join(' · ');
    return `\n\n> ${icon} **확신도 ${result.score}/100 (${result.bandLabel})** — ${top}`;
}
