/**
 * 한·영 깨진 토큰 감지·수리 — 순수 로직 테스트.
 */
import { findBrokenHangulTokens, repairBrokenHangul } from '../src/agent/hangulHygiene';

describe('findBrokenHangulTokens', () => {
    test('깨진 토큰 감지: 한글+영문소문자 연속', () => {
        const t = '문서를 단순히 텍스트 덩ey로 두지 말고, 결ently 헤더를 강제해야 합니다.';
        const broken = findBrokenHangulTokens(t);
        expect(broken.some(b => b.includes('덩ey'))).toBe(true);
        expect(broken.some(b => b.includes('결ently'))).toBe(true);
    });
    test.each([
        'API를 호출하고 Code의 구조를 본다',          // 영문 단어 + 한글 조사 = 정상
        'VS Code랑 LM Studio에서 모델을 로드한다',
        '플랜B로 진행하고 옵션A를 검토한다',           // 한글+대문자 1글자 = 정상
        'RAG 파이프라인과 recall@1 지표',
    ])('정상 표기는 미감지: %s', (t) => {
        expect(findBrokenHangulTokens(t)).toHaveLength(0);
    });
    test('코드 블록 안은 제외', () => {
        const t = '설명\n```js\nconst 덩ey = 1;\n```\n그리고 `값ab` 도 변수다';
        expect(findBrokenHangulTokens(t)).toHaveLength(0);
    });
});

describe('repairBrokenHangul — 검증 게이트', () => {
    const broken = ['덩ey로'];
    const text = '텍스트 덩ey로 두지 말 것. '.repeat(3);

    test('수리 성공 (깨진 토큰 감소 + 길이 유지) → 채택', async () => {
        const fixed = text.replace(/덩ey로/g, '덩어리로');
        const r = await repairBrokenHangul(text, broken, async () => fixed);
        expect(r).toBe(fixed.trim());
    });
    test('수리 결과가 너무 짧으면 기각 (내용 유실 방지)', async () => {
        const r = await repairBrokenHangul(text, broken, async () => '덩어리.');
        expect(r).toBeNull();
    });
    test('깨진 토큰이 줄지 않으면 기각', async () => {
        const r = await repairBrokenHangul(text, broken, async () => text);
        expect(r).toBeNull();
    });
    test('LLM 실패 시 null (원문 유지)', async () => {
        const r = await repairBrokenHangul(text, broken, async () => { throw new Error('down'); });
        expect(r).toBeNull();
    });
    test('깨진 토큰 없으면 호출 자체를 안 함', async () => {
        let called = false;
        const r = await repairBrokenHangul(text, [], async () => { called = true; return text; });
        expect(r).toBeNull();
        expect(called).toBe(false);
    });
});
