/**
 * 한·영 깨진 토큰 감지·수리 — 소형 로컬 모델의 토큰 붕괴 보정.
 *
 * 증상: 한국어 단어 중간에 영문 토큰이 섞임 — "덩어리"→"덩ey", "결과적으로"→"결ently".
 * 프롬프트 규칙([출력 위생])으로는 못 막는다 — 지시 불이행이 아니라 디코딩 사고라서.
 *
 * 보정: 결정론 감지(아래 패턴) + 발견 시 1회 LLM 수리 패스.
 *  - 감지 패턴: 한글 음절 바로 뒤 영문 소문자 2+ ("덩ey" ✓). 방향이 중요 —
 *    영문 단어 뒤 한글 조사("API를", "code의")는 정상 표기이므로 잡지 않는다.
 *  - 수리는 깨진 토큰 복원만 지시, 다른 내용 변경 금지. 수리 후 재검증
 *    (깨진 토큰이 줄고 길이 변화 ±35% 이내)을 통과해야 채택 — 아니면 원문 유지.
 */

const BROKEN_RE = /[가-힣][a-z]{2,}/g;
const MAX_REPAIR_CHARS = 14000;

/** 깨진 한·영 혼합 토큰 추출 (중복 제거, 주변 단어 포함). */
export function findBrokenHangulTokens(text: string): string[] {
    if (!text) return [];
    const out = new Set<string>();
    // 코드 블록·인라인 코드는 제외 — 변수명에 한글+영문이 정당하게 섞일 수 있음.
    const stripped = text.replace(/```[\s\S]*?```/g, '').replace(/`[^`\n]*`/g, '');
    for (const m of stripped.matchAll(BROKEN_RE)) {
        // 매치 주변의 전체 단어를 보고용으로 수집.
        const start = stripped.lastIndexOf(' ', m.index!) + 1;
        const end = stripped.indexOf(' ', m.index!);
        out.add(stripped.slice(start, end < 0 ? undefined : end).slice(0, 30));
        if (out.size >= 10) break;
    }
    return Array.from(out);
}

export type RepairLlmCall = (system: string, user: string, maxTokens: number) => Promise<string>;

/**
 * 깨진 토큰 수리 1회 — 성공 시 교정 전문, 실패/검증 미통과 시 null (원문 유지).
 */
export async function repairBrokenHangul(
    text: string,
    broken: string[],
    callLlm: RepairLlmCall,
): Promise<string | null> {
    if (!text.trim() || broken.length === 0 || text.length > MAX_REPAIR_CHARS) return null;
    const system = [
        '너는 한국어 표기 교정기다. 아래 텍스트에는 한국어 단어 중간에 영문 토큰이 깨져 들어간 오타가 있다 (예: "덩ey" → "덩어리", "결ently" → "결과적으로").',
        '깨진 토큰만 문맥에 맞는 자연스러운 한국어로 복원하라. 그 외의 모든 내용·문장·마크다운 형식·코드는 한 글자도 바꾸지 마라.',
        '교정된 전문만 출력하라 (해설·인사 금지).',
    ].join('\n');
    const user = `[깨진 토큰 예시] ${broken.join(', ')}\n\n[텍스트]\n${text}`;
    try {
        const repaired = (await callLlm(system, user, Math.min(4000, Math.ceil(text.length / 2) + 500))).trim();
        if (!repaired) return null;
        // 검증 — 수리가 더 망치면 원문 유지.
        const lenRatio = repaired.length / text.length;
        if (lenRatio < 0.65 || lenRatio > 1.35) return null;
        if (findBrokenHangulTokens(repaired).length >= broken.length) return null;
        return repaired;
    } catch {
        return null;
    }
}
