/**
 * Requirement Graph — 업무 유형별 필수 요소 정의 + 감지 + 커버리지 검사.
 *
 * Self-Evolving Digital Employee OS 마스터 플랜(docs/SELF_EVOLVING_OS_MASTER_PLAN.md)
 * Phase 1 / Track 2-1. 신뢰 조건 T3 "품질이 일관적이다 — 필수 요소 누락 없음" 담당.
 *
 * 동작 2단계:
 *   1. *Instructional* — 사용자 요청에서 업무 유형(회의록/시장조사/업무조사/일정) 감지 시
 *      [TASK REQUIREMENTS] 블록을 시스템 프롬프트에 주입 → 모델이 필수 요소를 빠짐없이 작성.
 *      정보가 없어 채울 수 없는 요소는 "(확인 필요)" 로 명시하게 강제 — 조용한 생략 금지
 *      (Anti-Hallucination T1 과 연결).
 *   2. *Deterministic* — 답변 완료 후 post-answer hook 이 필수 요소 커버리지를 정규식으로
 *      스캔, 누락 가능 요소를 footer 로 표시 (termValidator 와 같은 패턴, LLM 호출 없음).
 *
 * Gap Detector (Phase 3) 가 이 모듈의 Requirement 정의를 입력으로 사용한다:
 * Gap = Requirement − Knowledge.
 */

export interface RequirementElement {
    /** 안정적 식별자 (Failure Pattern DB 가 누락 카운트 키로 사용 예정). */
    id: string;
    /** 사람이 읽는 요소명 — 블록·footer 에 표시. */
    label: string;
    /** 모델에게 주는 작성 힌트. */
    hint: string;
    /** 커버리지 검사용 정규식 소스 (OR 결합, i+u 플래그). */
    detectPatterns: string[];
}

export interface TaskRequirement {
    /** 업무 유형 ID (예: 'meeting-minutes'). */
    id: string;
    /** 사람이 읽는 업무명 (예: '회의록'). */
    label: string;
    /** 사용자 요청에서 업무 유형을 감지하는 정규식 소스 (OR). */
    detectKeywords: string[];
    /**
     * 답변 커버리지 검사 여부. 일정 등 짧은 확인형 응답이 정상인 업무는 false —
     * footer 노이즈(false-positive) 방지. 블록 주입은 항상 수행.
     */
    coverageCheck: boolean;
    elements: RequirementElement[];
}

export interface CoverageResult {
    ran: boolean;
    taskId?: string;
    taskLabel?: string;
    covered: string[];   // element labels
    missing: string[];   // element labels
}

/**
 * 기본 업무 정의 4종. 배열 순서 = 감지 우선순위 (구체적 유형 먼저, 범용 '업무조사' 마지막 —
 * "조사" 류 키워드가 시장조사를 가로채지 않도록).
 */
export const DEFAULT_TASK_REQUIREMENTS: TaskRequirement[] = [
    {
        id: 'meeting-minutes',
        label: '회의록',
        detectKeywords: ['회의록', '회의 ?(내용|결과)? ?정리', '미팅 ?(노트|정리)', 'meeting (minutes|notes)'],
        coverageCheck: true,
        elements: [
            {
                id: 'attendees', label: '참석자',
                hint: '회의 참석 인원 전원. 불명확하면 "(확인 필요)".',
                detectPatterns: ['참석자', '참석 ?인원', 'attendees?'],
            },
            {
                id: 'decisions', label: '결정사항',
                hint: '회의에서 합의·확정된 사항. 논의만 되고 미결인 항목과 구분.',
                detectPatterns: ['결정 ?사항', '결정된', '합의', '확정', 'decisions?'],
            },
            {
                id: 'action-items', label: '액션 아이템',
                hint: '후속 실행 항목. 각 항목에 담당자·기한 연결.',
                detectPatterns: ['액션 ?아이템', 'action ?items?', '할 ?일', '후속 ?(조치|작업)', 'to-?do'],
            },
            {
                id: 'owners', label: '담당자',
                hint: '액션 아이템별 책임자. 미정이면 "(담당자 미정)" 명시.',
                detectPatterns: ['담당자?', '책임자', 'owner'],
            },
            {
                id: 'due-dates', label: '기한',
                hint: '액션 아이템별 마감일. 미정이면 "(기한 미정)" 명시.',
                detectPatterns: ['기한', '마감', '까지', 'due', '\\d{1,2}\\s*월\\s*\\d{1,2}\\s*일'],
            },
        ],
    },
    {
        id: 'market-research',
        label: '시장조사',
        detectKeywords: ['시장 ?조사', '시장 ?분석', '시장 ?(규모|동향|현황)', 'market (research|analysis)'],
        coverageCheck: true,
        elements: [
            {
                id: 'market-size', label: '시장 규모',
                hint: '금액/수량 기준 규모. 수치 출처 필수, 없으면 "(확인 필요)".',
                detectPatterns: ['시장 ?규모', 'market ?size', '\\d+\\s*(억|조|만\\s*달러|billion|million)'],
            },
            {
                id: 'growth', label: '성장률',
                hint: '연 성장률(CAGR 등) 또는 성장 추세.',
                detectPatterns: ['성장률', '성장세', 'CAGR', 'growth', '연평균'],
            },
            {
                id: 'competitors', label: '경쟁사',
                hint: '주요 플레이어와 각자의 포지션.',
                detectPatterns: ['경쟁사', '경쟁 ?업체', '주요 ?(업체|기업|플레이어)', 'competitors?'],
            },
            {
                id: 'pricing', label: '가격',
                hint: '가격대·요금 구조.',
                detectPatterns: ['가격', '요금', '단가', 'pricing', '원대', '달러'],
            },
            {
                id: 'customer-needs', label: '고객 니즈',
                hint: '고객 요구·페인 포인트.',
                detectPatterns: ['니즈', '고객 ?(요구|수요)', '페인 ?포인트', 'needs', 'pain ?points?'],
            },
            {
                id: 'trends', label: '트렌드',
                hint: '시장 동향·변화 방향.',
                detectPatterns: ['트렌드', '동향', '추세', 'trends?'],
            },
            {
                id: 'sources', label: '출처',
                hint: '핵심 수치·주장의 출처. 모델 일반 지식이면 그렇게 명시.',
                detectPatterns: ['출처', '근거', 'source', '자료:', '참고'],
            },
        ],
    },
    {
        id: 'schedule',
        label: '일정 관리',
        detectKeywords: ['일정 ?(등록|추가|확인|조회|정리|관리)', '스케줄', '캘린더', '미팅 ?잡', '약속 ?(등록|추가|잡)'],
        coverageCheck: false, // 짧은 확인형 응답이 정상 — footer 검사는 노이즈
        elements: [
            {
                id: 'datetime', label: '일시',
                hint: '날짜와 시간을 명시. 모호하면 되묻기.',
                detectPatterns: ['\\d{1,2}\\s*[:시]', '날짜', '일시'],
            },
            {
                id: 'title', label: '일정 제목',
                hint: '무엇을 위한 일정인지.',
                detectPatterns: ['제목', '일정명', '건명'],
            },
            {
                id: 'conflict-check', label: '충돌 확인',
                hint: '기존 일정과 겹침 여부 확인 결과 명시.',
                detectPatterns: ['충돌', '겹치', '겹침'],
            },
        ],
    },
    {
        id: 'work-research',
        label: '업무조사',
        detectKeywords: ['업무 ?조사', '조사해', '리서치', '알아봐\\s*줘?', '서치해', 'research'],
        coverageCheck: true,
        elements: [
            {
                id: 'purpose', label: '조사 목적',
                hint: '무엇을 알기 위한 조사인지 한 줄 명시.',
                detectPatterns: ['목적', '배경', '알아보기 위해'],
            },
            {
                id: 'summary', label: '핵심 요약',
                hint: '결론 먼저 — 3줄 이내 요약.',
                detectPatterns: ['요약', '핵심', '결론부터', 'TL;?DR', 'summary'],
            },
            {
                id: 'details', label: '세부 내용',
                hint: '요약을 뒷받침하는 상세 조사 내용.',
                detectPatterns: ['상세', '세부', '구체적', '자세히'],
            },
            {
                id: 'sources', label: '출처',
                hint: '핵심 주장의 출처. 모델 일반 지식이면 그렇게 명시.',
                detectPatterns: ['출처', '근거', 'source', '참고'],
            },
            {
                id: 'implications', label: '시사점·다음 단계',
                hint: '조사 결과가 의미하는 것과 권장 다음 행동.',
                detectPatterns: ['시사점', '다음 ?단계', '권장', '제안', '결론'],
            },
        ],
    },
];

function toRegex(sources: string[]): RegExp {
    return new RegExp(sources.join('|'), 'iu');
}

/**
 * 사용자 요청에서 업무 유형 감지. 배열 순서대로 첫 매치 반환, 없으면 null.
 * 짧은 인사·일반 잡담은 키워드 미매치로 자연스럽게 제외.
 */
export function detectTaskType(
    userPrompt: string,
    requirements: TaskRequirement[] = DEFAULT_TASK_REQUIREMENTS,
): TaskRequirement | null {
    if (!userPrompt || !userPrompt.trim()) return null;
    for (const req of requirements) {
        if (toRegex(req.detectKeywords).test(userPrompt)) return req;
    }
    return null;
}

/**
 * [TASK REQUIREMENTS] 시스템 프롬프트 블록 생성. 업무 유형 미감지 시 빈 문자열 —
 * memoryContext 의 dynamicBlocks join 에서 자동 제외.
 */
export function buildRequirementGraphBlock(
    userPrompt: string,
    requirements: TaskRequirement[] = DEFAULT_TASK_REQUIREMENTS,
    /** 과거 자주 누락된 요소 label — Reflection/Failure Pattern 이 공급 (T5: 같은 실수 반복 방지). */
    emphasizeLabels: string[] = [],
): string {
    const req = detectTaskType(userPrompt, requirements);
    if (!req) return '';

    const emphasize = new Set(emphasizeLabels);
    const lines: string[] = [];
    lines.push(`[TASK REQUIREMENTS — ${req.label}]`);
    lines.push(`이 요청은 '${req.label}' 업무로 감지됨. 아래 필수 요소를 *모두* 포함해 작성할 것.`);
    lines.push('정보가 없어 채울 수 없는 요소는 조용히 생략하지 말고 "(확인 필요)" 로 명시 후 사용자에게 질문.');
    lines.push('');
    for (const el of req.elements) {
        const mark = emphasize.has(el.label) ? ' ⚠️ *과거에 자주 누락된 요소 — 특히 주의*' : '';
        lines.push(`- [ ] **${el.label}** — ${el.hint}${mark}`);
    }
    lines.push('');
    lines.push('제출 전 위 체크리스트를 스스로 점검하고, 누락 요소가 있으면 보완 후 답변할 것.');
    lines.push('[/TASK REQUIREMENTS]');
    return lines.join('\n');
}

/**
 * 답변 커버리지 결정론적 검사 — 각 필수 요소의 detectPatterns 가 답변에 하나도 안 나타나면
 * missing. LLM 호출 없음 (정규식), 매 turn 안전.
 *
 * 한계(의도된 보수성): 패턴 매치 = "요소가 언급됨" 이지 "내용이 충실함" 이 아님.
 * 내용 충실도 평가는 Phase 3 Self Evaluation 담당.
 */
export function checkRequirementCoverage(
    userPrompt: string,
    assistantAnswer: string,
    requirements: TaskRequirement[] = DEFAULT_TASK_REQUIREMENTS,
): CoverageResult {
    const req = detectTaskType(userPrompt, requirements);
    if (!req || !req.coverageCheck || !assistantAnswer || !assistantAnswer.trim()) {
        return { ran: false, covered: [], missing: [] };
    }
    const covered: string[] = [];
    const missing: string[] = [];
    for (const el of req.elements) {
        if (toRegex(el.detectPatterns).test(assistantAnswer)) covered.push(el.label);
        else missing.push(el.label);
    }
    return { ran: true, taskId: req.id, taskLabel: req.label, covered, missing };
}

/**
 * 커버리지 footer — 누락 있을 때만 문자열 반환 (전부 충족 시 빈 문자열, 노이즈 방지).
 * termValidator footer 와 같은 위치(답변 아래 streamChunk)에 표시.
 */
export function formatRequirementCoverageFooter(result: CoverageResult): string {
    if (!result.ran || result.missing.length === 0) return '';
    const miss = result.missing.join(', ');
    return `\n\n> ⚠️ **Requirement Check (${result.taskLabel})** — 누락 가능 요소: ${miss}. 해당 내용이 없었다면 "(확인 필요)" 로 표시하거나 추가 정보를 요청하세요.`;
}
