/**
 * 환각 방지 3중 구조 유틸리티
 * Spec: docs/specs/260225-insuwiki-rag-spec-v2.md § 8
 *
 * 1. 유사도 임계값 게이트 (§ 8-1)
 * 2. Gemini 시스템 프롬프트 (§ 8-2) — 절대 변경 금지
 * 3. 답변 자동 검증 필터 (§ 8-3)
 */

// ── § 8-1. 유사도 임계값 ──────────────────────────────────────────────
export const SIMILARITY_THRESHOLDS = {
    TRUST:    0.85, // 이상 → 신뢰, 답변 허용
    AMBIGUOUS: 0.70, // ~0.85 → 불확실, Disambiguation 유도
    REJECT:    0.70, // 미만 → 매칭 없음, 답변 생성 금지
} as const;

export type SimilarityGateResult = 'TRUST' | 'DISAMBIGUATION' | 'REJECT';

export function checkSimilarityGate(score: number): SimilarityGateResult {
    if (score >= SIMILARITY_THRESHOLDS.TRUST)    return 'TRUST';
    if (score >= SIMILARITY_THRESHOLDS.AMBIGUOUS) return 'DISAMBIGUATION';
    return 'REJECT';
}

// ── § 8-2. Gemini 시스템 프롬프트 (절대 변경 금지) ────────────────────
export const GEMINI_SYSTEM_PROMPT = `당신은 보험 약관 분석 전문가입니다.
아래 규칙을 반드시 따르세요:

1. 제공된 약관 원문에 명시된 내용만 답변합니다.
2. 원문에 없는 내용은 절대 추정하거나 생성하지 않습니다.
3. 확인 불가 시 반드시 다음 형식으로 답변합니다:
   "제공된 약관에서 해당 내용을 확인할 수 없습니다.
    [어떤 정보가 부족한지 구체적으로 설명]"
4. 유사한 내용이 있어도 정확히 일치하지 않으면 언급하지 않습니다.
5. 답변 마지막에 반드시 출처를 명시합니다.
   형식: "※ 출처: {상품명} 약관 {페이지}p"
6. "아마도", "추정", "일반적으로", "보통은", "대개", "~인 것 같" 표현을 절대 사용하지 않습니다.`;

// ── § 9. 법적 면책 문구 템플릿 ──────────────────────────────────────
export type AnswerSourceType = 'policy' | 'newsletter' | 'youtube' | 'conflict';

export function getDisclaimerText(
    sourceType: AnswerSourceType,
    opts: { productName?: string; page?: number; companyName?: string; period?: string; channelName?: string; uploadDate?: string }
): string {
    switch (sourceType) {
        case 'policy':
            return `※ 출처: ${opts.productName ?? '해당 상품'} 약관 ${opts.page ?? ''}p\n※ 이 답변은 약관 원문 검색 결과이며, 실제 보험금 지급 여부는 보험사 심사 기준에 따릅니다. 청구 가능 여부는 반드시 보험사에 확인하세요.`;
        case 'newsletter':
            return `※ 출처: ${opts.companyName ?? ''} ${opts.period ?? ''} 소식지\n※ 주의: 소식지는 요약본입니다. 정확한 내용은 약관 원문을 확인하세요.`;
        case 'youtube':
            return `※ 참고: ${opts.channelName ?? ''} (${opts.uploadDate ?? ''}) - 참고 자료 수준\n※ 실제 약관 내용과 다를 수 있습니다. 약관 원문을 우선하세요.`;
        case 'conflict':
            return `⚠️ 주의: 유튜브 영상 내용과 약관 원문이 다릅니다. 약관 원문 기준이 정확한 내용입니다.`;
    }
}

// ── § 8-3. 답변 자동 검증 필터 ──────────────────────────────────────
export interface ValidationResult {
    valid: boolean;
    reason?: string;
}

const UNCERTAIN_PHRASES = ['아마도', '추정', '일반적으로', '보통은', '대개', '인 것 같'];

const CONCLUSION_ONLY_PHRASES = ['따라서', '그러므로', '결론적으로'];

export function validateAnswer(answer: string): ValidationResult {
    // 불확실 표현 감지
    const foundPhrase = UNCERTAIN_PHRASES.find(p => answer.includes(p));
    if (foundPhrase) {
        return { valid: false, reason: `불확실 표현 감지: "${foundPhrase}"` };
    }
    // 출처 누락 감지
    if (!answer.includes('※ 출처:') && !answer.includes('※ 참고:') && !answer.includes('확인할 수 없습니다')) {
        return { valid: false, reason: '출처 누락' };
    }
    // ── 작업 3 추가: 원문 출처 없이 결론만 있는 답변 차단 ──
    const hasSourceMarker = answer.includes('출처:') || answer.includes('※');
    const hasConclusion = CONCLUSION_ONLY_PHRASES.some(p => answer.includes(p));
    if (!hasSourceMarker && hasConclusion) {
        return { valid: false, reason: '원문 출처 없이 결론만 있는 답변' };
    }
    return { valid: true };
}

// ── 작업 3: 단정 표현 자동 치환 ──────────────────────────────────────
// 부정형을 먼저 배치하여 "보장되지 않습니다"가 "보장됩니다" 패턴에 먼저 걸리지 않도록 순서 보장
const ASSERTION_REPLACEMENTS: Array<{ pattern: RegExp; replacement: string }> = [
    {
        pattern: /보장되지 않습니다/g,
        replacement: '해당 조항에 따르면 보장되지 않는 것으로 보입니다. 정확한 보장 여부는 보험사에 확인하세요',
    },
    {
        pattern: /지급되지 않습니다/g,
        replacement: '해당 조항에 따르면 지급되지 않는 것으로 보입니다. 정확한 지급 여부는 보험사에 확인하세요',
    },
    {
        pattern: /보장됩니다/g,
        replacement: '해당 조항에 따르면 보장되는 것으로 보입니다. 정확한 보장 여부는 보험사에 확인하세요',
    },
    {
        pattern: /지급됩니다/g,
        replacement: '해당 조항에 따르면 지급되는 것으로 보입니다. 정확한 지급 여부는 보험사에 확인하세요',
    },
    {
        pattern: /보상됩니다/g,
        replacement: '해당 조항에 따르면 보상되는 것으로 보입니다. 정확한 보상 여부는 보험사에 확인하세요',
    },
    {
        pattern: /해당됩니다/g,
        replacement: '해당 조항에 따르면 해당되는 것으로 보입니다. 정확한 해당 여부는 보험사에 확인하세요',
    },
    {
        pattern: /적용됩니다/g,
        replacement: '해당 조항에 따르면 적용되는 것으로 보입니다. 정확한 적용 여부는 보험사에 확인하세요',
    },
];

export function sanitizeAssertions(answer: string): string {
    return ASSERTION_REPLACEMENTS.reduce(
        (text, { pattern, replacement }) => text.replace(pattern, replacement),
        answer,
    );
}

// ── 작업 3: 개인정보 마스킹 ──────────────────────────────────────────
// 호칭(님/씨) 앞에 붙은 한글 2~4자 이름만 마스킹
// "고객"은 보험 약관에서 일반 용어("당사 고객", "계약자 고객" 등)로 빈번하므로 제외
// 보험 약관 일반 용어 오마스킹 방지를 위한 제외 목록
const PII_NAME_EXCLUDES = [
    '계약자', '피보험자', '보험수익자', '보험계약자',
    '납입자', '피해자', '당사자', '대리인',
    '수익자', '청약자', '귀하', '당사',
];

const PII_PATTERNS: Array<{ pattern: RegExp; replacement: string }> = [
    // 주민등록번호: 6자리-7자리
    {
        pattern: /\d{6}-\d{7}/g,
        replacement: '[MASKED_RRN]',
    },
    // 전화번호: 02-XXX(X)-XXXX / 0XX-XXX(X)-XXXX / 010-XXXX-XXXX
    {
        pattern: /0\d{1,2}-\d{3,4}-\d{4}/g,
        replacement: '[MASKED_PHONE]',
    },
    // 이름 + 호칭 패턴: 한글 2~4자 뒤에 님/씨가 오는 경우 (보험 용어 제외)
    {
        pattern: /([가-힣]{2,4})(님|씨)/g,
        replacement: '[MASKED_NAME]$2',
    },
];

export function maskPII(text: string): string {
    let result = text;

    // 주민등록번호, 전화번호 마스킹 (단순 패턴)
    for (const { pattern, replacement } of PII_PATTERNS.slice(0, 2)) {
        result = result.replace(pattern, replacement);
    }

    // 이름+호칭 마스킹 (보험 약관 용어 제외)
    const namePattern = PII_PATTERNS[2];
    result = result.replace(namePattern.pattern, (match, name, suffix) => {
        if (PII_NAME_EXCLUDES.includes(name)) return match;
        return `[MASKED_NAME]${suffix}`;
    });

    return result;
}

// ── § 8-4. 답변 불가 표준 메시지 ─────────────────────────────────────
export const UNABLE_TO_ANSWER_MESSAGE =
    '제공된 약관에서 해당 내용을 확인할 수 없습니다. 관련 약관이 DB에 등록되어 있는지 확인해 주세요.';

export const DB_NOT_REGISTERED_MESSAGE =
    '해당 상품의 약관이 DB에 등록되어 있지 않습니다. 관리자에게 약관 등록을 요청해 주세요.';

// ── CL-10: 특약 경고 자동 삽입 ──────────────────────────────────────
const RIDER_KEYWORDS = ['선택특약', '추가특약', '특별약관', '선택담보'];
const RIDER_WARNING = '\n\n⚠️ **선택특약은 가입 여부에 따라 보장이 달라집니다. 보험증권을 확인하세요.**';

export function appendRiderWarning(answer: string): string {
    const hasRiderKeyword = RIDER_KEYWORDS.some(k => answer.includes(k));
    if (hasRiderKeyword && !answer.includes('보험증권을 확인하세요')) {
        return answer + RIDER_WARNING;
    }
    return answer;
}
