/**
 * 레슨 네트워크(A-MEM 이식) + 통합 초안 형식 — 순수 로직 테스트.
 */
import * as fs from 'fs';
import * as os from 'os';
import * as path from 'path';
import { lessonSimilarity, addRelatedLink, linkRelatedLessons } from '../src/intelligence/lessonNetwork';
import { reconcileDraftMarkdown, type ConflictFinding } from '../src/features/growth/conflictScan';
import { tokenize } from '../src/retrieval/scoring';

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

function mkLesson(brain: string, name: string, body: string): string {
    const dir = path.join(brain, 'lessons');
    fs.mkdirSync(dir, { recursive: true });
    const fp = path.join(dir, `${name}.md`);
    fs.writeFileSync(fp, body, 'utf8');
    return fp;
}

describe('lessonSimilarity', () => {
    test('겹치는 토큰 비율 — 동일 주제 > 무관 주제', () => {
        const a = tokenize('회의 날짜를 잘못 기억해 캘린더 등록 오류 발생');
        const b = tokenize('회의 일정 등록 시 날짜 확인 누락으로 오류');
        const c = tokenize('파이썬 가상환경 의존성 충돌 해결 방법');
        expect(lessonSimilarity(a, b)).toBeGreaterThan(lessonSimilarity(a, c));
        expect(lessonSimilarity(a, a)).toBe(1);
        expect(lessonSimilarity([], a)).toBe(0);
    });
});

describe('addRelatedLink', () => {
    test('섹션 없으면 생성, 있으면 append, 중복은 멱등', () => {
        let c = '# Lesson: X\n\n## Fix\n내용\n';
        c = addRelatedLink(c, '레슨A');
        expect(c).toContain('## 관련 레슨\n- [[레슨A]]');
        c = addRelatedLink(c, '레슨B');
        expect(c).toContain('- [[레슨A]]\n- [[레슨B]]');
        const again = addRelatedLink(c, '레슨A');
        expect(again).toBe(c); // 멱등
    });
    test('관련 레슨 섹션 뒤에 다른 헤딩이 있어도 섹션 안에 삽입', () => {
        const c = '# L\n\n## 관련 레슨\n- [[기존]]\n\n## Applies To\n- 태그\n';
        const out = addRelatedLink(c, '신규');
        expect(out.indexOf('- [[신규]]')).toBeLessThan(out.indexOf('## Applies To'));
    });
});

describe('linkRelatedLessons — 상호 링크 + 역방향 갱신', () => {
    test('유사 레슨과 양방향 링크 생성', () => {
        const brain = tmpBrain();
        const oldFp = mkLesson(brain, 'old-meeting-date', '# Lesson: 회의 날짜 오류\n\n## Mistake / Risk\n회의 날짜를 잘못 기억해 캘린더 등록 오류 발생\n');
        mkLesson(brain, 'unrelated-python', '# Lesson: 파이썬 환경\n\n## Mistake / Risk\n파이썬 가상환경 의존성 충돌 npm 빌드 도구 체인 별개 주제\n');
        const newFp = mkLesson(brain, 'new-meeting-date', '# Lesson: 회의 일정 재발\n\n## Mistake / Risk\n회의 일정 등록 시 날짜 확인 누락 캘린더 오류\n');

        const linked = linkRelatedLessons(brain, newFp);
        expect(linked).toBeGreaterThanOrEqual(1);
        expect(fs.readFileSync(newFp, 'utf8')).toContain('[[old-meeting-date]]');
        expect(fs.readFileSync(oldFp, 'utf8')).toContain('[[new-meeting-date]]'); // 역방향
    });
    test('유사 레슨 없으면 0 (파일 미변경)', () => {
        const brain = tmpBrain();
        mkLesson(brain, 'a', '# Lesson: 완전히 다른 알파 베타 감마 주제\n');
        const newFp = mkLesson(brain, 'b', '# Lesson: 전혀 무관한 델타 입실론 제타\n');
        const before = fs.readFileSync(newFp, 'utf8');
        expect(linkRelatedLessons(brain, newFp)).toBe(0);
        expect(fs.readFileSync(newFp, 'utf8')).toBe(before);
    });
});

describe('reconcileDraftMarkdown', () => {
    test('frontmatter + 비자동반영 고지 + 본문', () => {
        const f: ConflictFinding = {
            newDoc: 'AI_and_ML/신규.md', existingDoc: 'AI_and_ML/기존.md',
            summary: '버전 수치 모순', recommend: '권고: **신규 우선** (S·1.0 vs A·0.8)',
        };
        const md = reconcileDraftMarkdown(f, '## 통합 내용\n…', '2026-06-12T00:00:00Z');
        expect(md).toMatch(/^---\ntype: reconcile-draft/);
        expect(md).toContain('status: pending-review');
        expect(md).toContain('자동 반영되지 않습니다');
        expect(md).toContain('버전 수치 모순');
        expect(md).toContain('신규 우선');
    });
});
