/**
 * seedInsuranceTerms.ts 핵심 로직 단위 테스트
 *
 * 테스트 대상:
 *  - isDescriptionNotAlias: ICD 코드, 범위 설명, 영문 약어 판별
 *  - parseTermLine: 용어명과 alias 파싱
 *  - termToDocId: Firestore 문서 ID 변환
 *
 * Firebase 의존성 없이 순수 함수만 복사하여 테스트합니다.
 */

import { describe, it, expect } from 'vitest';

// ============================================================
// 순수 함수 복사 (seedInsuranceTerms.ts에서)
// ============================================================

/**
 * 괄호 안 내용이 ICD 코드나 범위 설명인지 판단
 * 예: "가장 좁은 범위, I60-I62", "I60-I62", "GA, General Average"
 * 이런 경우 alias가 아닌 설명으로 간주하여 제외
 */
function isDescriptionNotAlias(content: string): boolean {
    // ICD 코드 패턴 포함 (예: I60-I62, I21-I22)
    if (/[A-Z]\d{2}-[A-Z]\d{2}/.test(content)) return true;
    // "가장 좁은 범위", "중간 범위", "가장 넓은 범위" 등 범위 설명
    if (/(가장\s*(좁은|넓은)|중간)\s*범위/.test(content)) return true;
    // 단독 영문 약어 2글자 이상 + 영문만으로 구성된 경우 (단, 한글 섞인 alias는 허용)
    // 예: "TLO", "GA, General Average", "W.A., With Average" — 단, "VUL", "CI" 같은 것은 alias로 허용
    // 쉼표 포함 + 영문만인 경우 제외
    if (/^[A-Za-z\s,./]+$/.test(content) && content.includes(',')) return true;
    return false;
}

/**
 * 용어 라인을 파싱하여 term과 commonAliases 추출
 * 형식: "용어명" 또는 "용어명 (alias1, alias2)"
 */
function parseTermLine(line: string): { term: string; commonAliases: string[] } | null {
    const trimmed = line.trim();
    if (!trimmed) return null;

    // 괄호가 있는 경우: "용어명 (alias1, alias2, ...)"
    const parenMatch = trimmed.match(/^(.+?)\s*\((.+)\)\s*$/);
    if (parenMatch) {
        const term = parenMatch[1].trim();
        const parenContent = parenMatch[2].trim();

        // 괄호 안이 설명(ICD 코드, 범위 설명 등)인 경우 alias 없이 term만 반환
        if (isDescriptionNotAlias(parenContent)) {
            return { term, commonAliases: [] };
        }

        // 쉼표로 구분된 alias 목록 파싱
        const aliases = parenContent
            .split(',')
            .map(a => a.trim())
            .filter(a => a.length > 0);

        return { term, commonAliases: aliases };
    }

    // 괄호 없는 경우: 용어명만
    return { term: trimmed, commonAliases: [] };
}

/**
 * term을 안전한 Firestore 문서 ID로 변환
 * Firestore는 유니코드(한글) 허용, 단 '/', '.', '__'는 피함
 */
function termToDocId(term: string): string {
    return term
        .replace(/\//g, '_')      // 슬래시 제거
        .replace(/\./g, '_')      // 점 제거
        .replace(/\s+/g, '_')     // 공백 → 언더스코어
        .replace(/__+/g, '_')     // 연속 언더스코어 정리
        .replace(/^_|_$/g, '');   // 앞뒤 언더스코어 제거
}

// ============================================================
// 테스트: isDescriptionNotAlias
// ============================================================

describe('seedInsuranceTerms: isDescriptionNotAlias', () => {

    // ----------------------------------------------------------
    // true 케이스 (설명으로 간주 → alias 제외)
    // ----------------------------------------------------------
    describe('true 반환 케이스 (설명으로 간주)', () => {

        it('ICD 코드 + 범위 설명이 함께 있으면 true', () => {
            expect(isDescriptionNotAlias('가장 좁은 범위, I60-I62')).toBe(true);
        });

        it('ICD 코드만 있어도 true', () => {
            expect(isDescriptionNotAlias('I21-I22')).toBe(true);
        });

        it('가장 넓은 범위 + ICD 코드 조합도 true', () => {
            expect(isDescriptionNotAlias('가장 넓은 범위, I60-I69')).toBe(true);
        });

        it('영문만 + 쉼표 포함인 경우 true (GA, General Average)', () => {
            expect(isDescriptionNotAlias('GA, General Average')).toBe(true);
        });

        it('영문만 + 쉼표 + 마침표 포함인 경우 true (W.A., With Average)', () => {
            expect(isDescriptionNotAlias('W.A., With Average')).toBe(true);
        });
    });

    // ----------------------------------------------------------
    // false 케이스 (alias로 허용)
    // ----------------------------------------------------------
    describe('false 반환 케이스 (alias로 허용)', () => {

        it('한글 포함 alias 목록은 false (암진단금, 암진)', () => {
            expect(isDescriptionNotAlias('암진단금, 암진')).toBe(false);
        });

        it('한글만 포함된 alias 목록은 false (씨아이보험, 치명적질환보험)', () => {
            expect(isDescriptionNotAlias('씨아이보험, 치명적질환보험')).toBe(false);
        });

        it('쉼표 없는 영문 약어 단독은 false (TLO)', () => {
            expect(isDescriptionNotAlias('TLO')).toBe(false);
        });
    });
});

// ============================================================
// 테스트: parseTermLine
// ============================================================

describe('seedInsuranceTerms: parseTermLine', () => {

    // ----------------------------------------------------------
    // alias가 있는 경우
    // ----------------------------------------------------------
    describe('괄호 안에 alias가 있는 경우', () => {

        it('한글 alias 목록을 올바르게 파싱한다', () => {
            const result = parseTermLine('암진단비 (암진단금, 암진)');
            expect(result).toEqual({ term: '암진단비', commonAliases: ['암진단금', '암진'] });
        });

        it('영문 단일 alias도 파싱한다 (TLO)', () => {
            const result = parseTermLine('전손담보 (TLO)');
            expect(result).toEqual({ term: '전손담보', commonAliases: ['TLO'] });
        });

        it('한글 + 영문 혼합 alias를 파싱한다 (CI보험)', () => {
            const result = parseTermLine('CI보험 (씨아이보험, 치명적질환보험)');
            expect(result).toEqual({ term: 'CI보험', commonAliases: ['씨아이보험', '치명적질환보험'] });
        });
    });

    // ----------------------------------------------------------
    // 괄호 안이 설명인 경우 (alias 제외)
    // ----------------------------------------------------------
    describe('괄호 안이 설명(ICD 코드, 범위)인 경우', () => {

        it('ICD 코드 + 범위 설명이면 commonAliases가 빈 배열', () => {
            const result = parseTermLine('뇌출혈 (가장 좁은 범위, I60-I62)');
            expect(result).toEqual({ term: '뇌출혈', commonAliases: [] });
        });
    });

    // ----------------------------------------------------------
    // 괄호 없는 경우
    // ----------------------------------------------------------
    describe('괄호 없는 단순 용어명', () => {

        it('용어명만 있으면 commonAliases는 빈 배열', () => {
            const result = parseTermLine('피보험자');
            expect(result).toEqual({ term: '피보험자', commonAliases: [] });
        });
    });

    // ----------------------------------------------------------
    // null 반환 케이스
    // ----------------------------------------------------------
    describe('null 반환 케이스', () => {

        it('빈 문자열이면 null 반환', () => {
            expect(parseTermLine('')).toBeNull();
        });

        it('공백만 있는 문자열이면 null 반환', () => {
            expect(parseTermLine('  ')).toBeNull();
        });
    });
});

// ============================================================
// 테스트: termToDocId
// ============================================================

describe('seedInsuranceTerms: termToDocId', () => {

    it('특수문자 없는 한글 용어는 그대로 반환', () => {
        expect(termToDocId('암진단비')).toBe('암진단비');
    });

    it('슬래시(/)를 언더스코어로 변환한다', () => {
        expect(termToDocId('InsuWiki/Test')).toBe('InsuWiki_Test');
    });

    it('공백을 언더스코어로 변환한다', () => {
        expect(termToDocId('용어 이름')).toBe('용어_이름');
    });

    it('마침표(.)를 언더스코어로 변환하고 끝의 언더스코어는 제거한다', () => {
        // "W.A." → "W_A_" → 앞뒤 언더스코어 제거 → "W_A"
        expect(termToDocId('W.A.')).toBe('W_A');
    });

    it('슬래시와 공백이 연속되어도 연속 언더스코어를 정리한다', () => {
        expect(termToDocId('용어/ 이름')).toBe('용어_이름');
    });

    it('앞뒤 언더스코어를 제거한다', () => {
        expect(termToDocId('/앞슬래시')).toBe('앞슬래시');
    });
});
