/**
 * ============================================================
 * /email 브리핑 — 받은편지함을 '주제(스레드)' 단위로 정리 (v2.2.270)
 *
 * 원시 메일 나열 대신 사람이 상황을 파악할 수 있는 형태로:
 *   ① RE:/FW: 를 벗겨 같은 주제 메일을 하나의 스레드로 묶고
 *   ② 보낸편지함과 대조해 "마지막 발화가 누구인가"로 답변 여부 판정
 *      (마지막이 상대방 → 🔴 회신 대기 / 마지막이 나 → ✅ 공 넘김)
 *   ③ 뉴스레터·자동발신은 📢 로 분리 (회신 대상 아님)
 *
 * 이 파일은 순수 로직만 — COM/네트워크 없음 (테스트 가능).
 * ============================================================
 */

export interface MailLite {
    /** 참조 라벨 (예: 'O3', 'G1') — 브리핑에서 read/wikify 로 이어지는 연결고리. */
    ref?: string;
    entryId?: string;
    subject: string;
    from: string;
    to?: string;
    /** 'YYYY-MM-DD HH:mm' — 문자열 비교로 정렬 가능한 형식. */
    received: string;
    unread?: boolean;
    snippet?: string;
    /** true = 내가 보낸 메일 (Sent Items / Gmail SENT 라벨). */
    outgoing?: boolean;
    /** 내가 To 가 아니라 CC 로만 수신 (회신 대상 아님). */
    ccOnly?: boolean;
}

/** 스레드 내 메시지 흐름 한 칸 — 브리핑의 '경과(히스토리)' 재료. */
export interface TimelineEntry {
    date: string;
    from: string;
    outgoing: boolean;
    snippet?: string;
}

export interface ThreadGroup {
    /** 정규화된 주제 (RE:/FW: 제거 후). */
    topic: string;
    /** 원 제목 (가장 최근 메일 기준). */
    subject: string;
    /** 상대방 참여자 (내 발신 제외, 중복 제거, 최대 4명). */
    participants: string[];
    inCount: number;
    outCount: number;
    /** 스레드에서 가장 최근 메시지의 방향. */
    lastDirection: 'in' | 'out';
    lastDate: string;
    /** 가장 최근 수신 메일의 스니펫. */
    snippet: string;
    /** 읽지 않은 수신 메일 존재 여부. */
    hasUnread: boolean;
    /** 뉴스레터·자동발신 (회신 대상 아님). */
    automated: boolean;
    /** 수신 메일들의 참조 라벨 (최신순, 예: ['O1','O2']). */
    refs: string[];
    /** 가장 최근 수신 메일 entryId (본문 심화 조회용). */
    latestEntryId?: string;
    /** 메시지 흐름 (시간순, 최근 6개) — 브리핑의 '경과' 서술 재료. */
    timeline: TimelineEntry[];
    /** 수신 메일 전부가 CC 수신 — 회신 불요, 확인만 분류 (v2.2.290). */
    ccOnly: boolean;
}

/** RE:/FW:/회신:/전달: 접두를 반복 제거하고 소문자·공백 정규화 → 스레드 키. */
export function normalizeSubject(subject: string): string {
    let s = (subject || '').trim();
    // 여러 겹 (예: "RE: FW: RE: 제목") 모두 벗긴다.
    const prefix = /^\s*(re|fw|fwd|회신|전달|답장|답변)\s*[:：]\s*/i;
    while (prefix.test(s)) s = s.replace(prefix, '');
    return s.replace(/\s+/g, ' ').trim().toLowerCase() || '(제목 없음)';
}

/** 뉴스레터·시스템 자동발신 판정 — 회신 대상이 아닌 노이즈 분리. */
export function isAutomated(from: string, subject: string): boolean {
    const f = (from || '').toLowerCase().trim();
    const s = (subject || '').toLowerCase();
    if (/no-?reply|donotreply|noreply|notification|알림|newsletter|뉴스레터|marketing|digest|다이제스트/i.test(f)) return true;
    // 서비스 발신자 (v2.2.283 확장: confluence·AWS·plain Apple 등 — 텔레그램 미회신 노이즈의 주범)
    if (/app store connect|google payments|google cloud|aws marketplace|amazon web services|apple developer|atlassian|confluence|jira|github|slack|figma|notion|linkedin|dropbox|플래티어/i.test(f)) return true;
    if (f === 'apple' || f === 'aws' || f === 'google') return true;
    // 제목 신호 (광고 표기·시스템 태그·다이제스트류)
    if (/뉴스레터|newsletter|digest|다이제스트|weekly update|product update|receipt|영수증|결제 완료|invoice|\(광고\)|\[notification\]|놓치지 마세요/i.test(s)) return true;
    return false;
}

/**
 * 수신 + 발신 메일을 주제별 스레드로 묶는다. 반환 정렬:
 * 회신 대기(사람) → 진행 중 → 자동발신, 각 그룹 내 최신순.
 */
export function groupThreads(inbox: MailLite[], sent: MailLite[]): ThreadGroup[] {
    const map = new Map<string, { in: MailLite[]; out: MailLite[] }>();
    const put = (m: MailLite, dir: 'in' | 'out') => {
        const key = normalizeSubject(m.subject);
        let g = map.get(key);
        if (!g) { g = { in: [], out: [] }; map.set(key, g); }
        g[dir].push(m);
    };
    for (const m of inbox) put(m, 'in');
    for (const m of sent) put(m, 'out');

    const threads: ThreadGroup[] = [];
    for (const [topic, g] of map) {
        if (g.in.length === 0) continue; // 발신만 있는 주제는 브리핑 대상 아님 (받은편지함 정리가 목적)
        const byDateDesc = (a: MailLite, b: MailLite) => b.received.localeCompare(a.received);
        g.in.sort(byDateDesc);
        g.out.sort(byDateDesc);
        const latestIn = g.in[0];
        const latestOut = g.out[0];
        const lastDirection: 'in' | 'out' =
            latestOut && latestOut.received.localeCompare(latestIn.received) > 0 ? 'out' : 'in';
        const participants = [...new Set(g.in.map(m => (m.from || '').trim()).filter(Boolean))].slice(0, 4);
        // 시간순 타임라인 (수신+발신 합쳐 최근 6개) — "누가 언제 무슨 말을 했나" 경과 재료.
        const timeline: TimelineEntry[] = [...g.in, ...g.out]
            .sort((a, b) => a.received.localeCompare(b.received))
            .slice(-6)
            .map(m => ({
                date: m.received,
                from: m.outgoing ? '나' : (m.from || '-'),
                outgoing: !!m.outgoing,
                snippet: (m.snippet || '').slice(0, 100) || undefined,
            }));
        threads.push({
            topic,
            subject: latestIn.subject || '(제목 없음)',
            participants,
            inCount: g.in.length,
            outCount: g.out.length,
            lastDirection,
            lastDate: lastDirection === 'out' ? latestOut.received : latestIn.received,
            snippet: (latestIn.snippet || '').trim(),
            hasUnread: g.in.some(m => !!m.unread),
            automated: g.in.every(m => isAutomated(m.from, m.subject)),
            refs: g.in.map(m => m.ref || '').filter(Boolean),
            latestEntryId: latestIn.entryId,
            timeline,
            ccOnly: g.in.length > 0 && g.in.every(m => m.ccOnly === true),
        });
    }

    const rank = (t: ThreadGroup) => (t.automated ? 2 : t.lastDirection === 'in' ? 0 : 1);
    threads.sort((a, b) => rank(a) - rank(b) || b.lastDate.localeCompare(a.lastDate));
    return threads;
}

/** LLM 실패 시에도 쓸 수 있는 결정론 브리핑 렌더 (마크다운 리스트). */
export function renderBriefFallback(threads: ThreadGroup[]): string {
    const lines: string[] = [];
    const section = (title: string, items: ThreadGroup[], fmt: (t: ThreadGroup) => string) => {
        if (items.length === 0) return;
        lines.push(`\n**${title}** (${items.length})\n`);
        for (const t of items) lines.push(fmt(t));
    };
    const label = (t: ThreadGroup) =>
        `- ${t.hasUnread ? '🔵 ' : ''}**${t.subject}** — ${t.participants.join(', ') || '-'} · 메시지 ${t.inCount + t.outCount}건 · ${t.lastDate}${t.refs.length ? ` · [${t.refs.slice(0, 3).join(' ')}]` : ''}`;

    const humans = threads.filter(t => !t.automated);
    section('🔴 회신 대기 — 상대방이 마지막으로 보냄', humans.filter(t => t.lastDirection === 'in'), label);
    section('✅ 공 넘김 — 내가 마지막으로 답함', humans.filter(t => t.lastDirection === 'out'), label);
    section('📢 자동발신 · 공지 (회신 불필요)', threads.filter(t => t.automated),
        t => `- ${t.subject} — ${t.participants[0] || '-'} · ${t.lastDate}`);
    return lines.join('\n');
}
