/**
 * Sleep-time 사전 소화 — 순수 로직 테스트 (대상 선정·노후화 판정·노트 형식).
 * LLM 호출(runSleepDigestOnce)은 제외 — 통합 검증은 수동 명령으로.
 */
import * as fs from 'fs';
import * as os from 'os';
import * as path from 'path';
import {
    selectDigestTargets, folderSlug, isDigestFresh, digestMarkdown, DIGEST_DIR,
    type DigestTarget,
} from '../src/features/growth/sleepDigest';

const tmpBrain = () => fs.mkdtempSync(path.join(os.tmpdir(), 'astra-digest-'));

function mkFile(brain: string, rel: string, ageDays: number): string {
    const abs = path.join(brain, rel);
    fs.mkdirSync(path.dirname(abs), { recursive: true });
    fs.writeFileSync(abs, `# ${path.basename(rel)}\n내용`, 'utf8');
    const t = new Date(Date.now() - ageDays * 86_400_000);
    fs.utimesSync(abs, t, t);
    return abs;
}

describe('selectDigestTargets', () => {
    test('최근 변경 파일이 많은 폴더 우선, 오래된 파일 제외', () => {
        const brain = tmpBrain();
        const files = [
            mkFile(brain, 'Topics_Rag/a.md', 1),
            mkFile(brain, 'Topics_Rag/b.md', 2),
            mkFile(brain, 'Topics_Rag/c.md', 3),
            mkFile(brain, 'Coding/Python/x.md', 1),
            mkFile(brain, 'Coding/Python/y.md', 2),
            mkFile(brain, 'Old_Folder/z.md', 30), // 윈도우 밖
        ];
        const targets = selectDigestTargets(brain, files, Date.now(), 7);
        expect(targets[0].folder).toBe('Topics_Rag');
        expect(targets[0].files).toHaveLength(3);
        expect(targets[1].folder).toBe('Coding/Python');
        expect(targets.find(t => t.folder === 'Old_Folder')).toBeUndefined();
    });
    test('Digests 폴더 자신은 재소화하지 않음 + 루트 직속은 빈 키', () => {
        const brain = tmpBrain();
        const files = [
            mkFile(brain, `${DIGEST_DIR}/old-digest.md`, 1),
            mkFile(brain, 'root-note.md', 1),
        ];
        const targets = selectDigestTargets(brain, files, Date.now(), 7);
        expect(targets.find(t => t.folder.includes(DIGEST_DIR))).toBeUndefined();
        expect(targets.find(t => t.folder === '')).toBeDefined();
    });
    test('파일 상한 8개', () => {
        const brain = tmpBrain();
        const files = Array.from({ length: 12 }, (_, i) => mkFile(brain, `Big/f${i}.md`, 1));
        const targets = selectDigestTargets(brain, files, Date.now(), 7);
        expect(targets[0].files.length).toBeLessThanOrEqual(8);
    });
});

describe('folderSlug', () => {
    test('경로 구분자·특수문자 정리', () => {
        expect(folderSlug('Coding/Python')).toBe('Coding--Python');
        expect(folderSlug('')).toBe('root');
        expect(folderSlug('AI & ML!')).toBe('AI-ML-');
    });
});

describe('isDigestFresh — 노후화 판정', () => {
    const target = (over: Partial<DigestTarget> = {}): DigestTarget => ({
        folder: 'X', slug: 'X', files: [], newestMtimeMs: Date.now(), ...over,
    });
    test('노트 없음 → 재생성 필요', () => {
        expect(isDigestFresh(path.join(tmpBrain(), 'no.md'), Date.now())).toBe(false);
    });
    test('generated_at ≥ 소스 mtime → fresh', () => {
        const brain = tmpBrain();
        const f = path.join(brain, 'd.md');
        const t = target();
        fs.writeFileSync(f, digestMarkdown(t, '본문', ['s1'], new Date(t.newestMtimeMs + 1000).toISOString()), 'utf8');
        expect(isDigestFresh(f, t.newestMtimeMs)).toBe(true);
    });
    test('소스가 노트보다 최신 → 재생성 필요', () => {
        const brain = tmpBrain();
        const f = path.join(brain, 'd.md');
        fs.writeFileSync(f, digestMarkdown(target(), '본문', ['s1'], new Date(Date.now() - 86_400_000).toISOString()), 'utf8');
        expect(isDigestFresh(f, Date.now())).toBe(false);
    });
});

describe('digestMarkdown', () => {
    test('frontmatter(type: digest, sources) + 원문 우선 고지', () => {
        const md = digestMarkdown(
            { folder: 'Topics_Rag', slug: 'Topics_Rag', files: [], newestMtimeMs: 0 },
            '## 예상 질문과 답\n- Q…', ['문서 "A"', 'B'], '2026-06-12T03:00:00Z',
        );
        expect(md).toMatch(/^---\ntype: digest/);
        expect(md).toContain('generated_at: 2026-06-12T03:00:00Z');
        expect(md).toContain("문서 'A'"); // 따옴표 이스케이프
        expect(md).toContain('원문이 항상 우선');
        expect(md).toContain('# 소화 노트: Topics_Rag');
    });
});
