/**
 * Gap Detector — Gap = Requirement − Knowledge (설계서 7.4).
 *
 * Self-Evolving OS 마스터 플랜 Phase 3 / Track 3-2. 업무 turn 마다 "필요한 것"
 * (Requirement Graph 의 필수 요소)과 "가진 것"(검색 그라운딩 + 산출물 커버리지)을
 * 비교해 부족 지식·영향도·긴급도를 산출한다.
 *
 * v1 신호 체계 (결정론적, LLM 없음):
 *   - 요소 갭: 커버리지 검사에서 누락된 필수 요소
 *   - 그라운딩 갭: 검색 근거가 없거나(chunkCount=0) 약한(topScore 낮음) 상태에서
 *     업무를 수행한 것 — "지식이 없어서 모델 일반 지식으로 때운" 신호
 *   - 영향도: 업무 유형 가중치 (고영향 업무 누락 = 더 심각)
 *   - 긴급도: 같은 갭의 반복 (Reflection 의 recurrentMisses 와 결합)
 *
 * 출력은 Reflection 에 기록되어 Need Engine 의 입력이 된다.
 */

import type { CoverageResult } from './requirementGraph';
import type { RetrievalConfidenceSignals } from './confidenceEngine';

export type GapSeverity = 'none' | 'low' | 'medium' | 'high';

export interface GapReport {
    /** 산출물에서 누락된 필수 요소 (요소 갭). */
    missingElements: string[];
    /** 검색 근거 없이/약하게 수행 — 지식 갭 신호. */
    weakGrounding: boolean;
    severity: GapSeverity;
    /** 사람이 읽는 갭 설명 (Need Engine·리포트용). */
    summary: string;
}

/** 고영향 업무 — 갭 severity 한 단계 상향. escalationEngine 과 동일 기준. */
const HIGH_IMPACT_TASKS = new Set(['meeting-minutes', 'market-research', 'schedule']);

const SEVERITY_ORDER: GapSeverity[] = ['none', 'low', 'medium', 'high'];

function bump(s: GapSeverity): GapSeverity {
    const i = SEVERITY_ORDER.indexOf(s);
    return SEVERITY_ORDER[Math.min(i + 1, SEVERITY_ORDER.length - 1)];
}

export function detectGaps(inputs: {
    coverage: CoverageResult;
    signals: RetrievalConfidenceSignals;
    taskId: string | null;
}): GapReport {
    const { coverage, signals, taskId } = inputs;
    const missingElements = coverage.ran ? coverage.missing.slice() : [];
    const weakGrounding = signals.chunkCount === 0 || (signals.chunkCount > 0 && signals.topScore < 0.3);

    let severity: GapSeverity = 'none';
    if (missingElements.length >= 3) severity = 'high';
    else if (missingElements.length > 0) severity = 'medium';
    else if (weakGrounding) severity = 'low';
    if (severity !== 'none' && taskId && HIGH_IMPACT_TASKS.has(taskId) && weakGrounding) {
        severity = bump(severity);
    }

    const parts: string[] = [];
    if (missingElements.length > 0) parts.push(`필수 요소 ${missingElements.length}개 누락(${missingElements.join(', ')})`);
    if (weakGrounding) {
        parts.push(signals.chunkCount === 0
            ? '검색 근거 0건 — 모델 일반 지식으로 수행'
            : `검색 근거 약함 (top score ${signals.topScore.toFixed(2)})`);
    }
    return {
        missingElements,
        weakGrounding,
        severity,
        summary: parts.length > 0 ? parts.join(' · ') : '갭 없음',
    };
}
