/**
 * ============================================================
 * 텔레그램 메시지 — 단일 포맷 모듈 (v2.2.284)
 *
 * 배경: 기능마다 텔레그램 메시지 포맷이 제각각(주식 보고서·매수시그널·발굴 Top5·
 * 데일리 브리핑·이메일 알림)이라 모바일 시인성이 낮고 유지보수가 파편화됐다.
 * wikiFormat 이 위키 문서 포맷을 통일한 것처럼, **앞으로 텔레그램으로 나가는
 * 모든 정기/알림 메시지는 이 모듈의 renderTelegram() 으로 조립한다.**
 *
 * 모바일 규약:
 *   <이모지> *<제목>* (건수)          ← 헤더 한 줄
 *   _YYYY-MM-DD HH:MM KST_           ← 타임스탬프 (선택)
 *   *<섹션 제목>* (N)                 ← 섹션
 *   1. <본문 34자 컷>                 ← 번호 항목
 *       <메타 한 줄>                  ←   보조 정보 (들여쓰기)
 *   … 외 N건                         ← 잘림 표기 (묵살 금지)
 *   _<푸터 힌트>_                     ← 다음 행동 안내
 * 전체 3,800자 캡 (텔레그램 4,096 한도 여유분).
 * ============================================================
 */

export interface TgItem {
    /** 본문 한 줄 — 렌더러가 34자로 컷하고 번호를 붙인다. */
    main: string;
    /** 보조 메타 (발신자·대기시간 등) — 들여쓰기 줄. */
    sub?: string;
}

export interface TgSection {
    /** 섹션 제목 (없으면 항목만). */
    heading?: string;
    /** 섹션 건수 표기 — 항목이 잘려도 전체 규모를 알린다. */
    count?: number;
    /** 번호 매김 항목 (최대 maxItems, 기본 7). */
    items?: TgItem[];
    /** 자유 라인 (이미 포맷된 짧은 줄들 — 번호 없이). */
    lines?: string[];
    maxItems?: number;
}

export interface TgMessage {
    emoji: string;
    title: string;
    count?: number;
    /** true 면 헤더 아래 KST 타임스탬프. */
    timestamp?: boolean;
    sections: TgSection[];
    /** 다음 행동 힌트 — italic 푸터. */
    footer?: string;
}

const MAX_LEN = 3800;

export const tgCut = (s: string, n: number): string =>
    ((s || '').length > n ? (s || '').slice(0, n - 1) + '…' : (s || ''));

/** 발신자 표기 정리 — "김성환(칼리버스-칼리버스)" → "김성환", 10자 컷. */
export function tgWho(name: string, max = 10): string {
    return tgCut((name || '-').replace(/\(.*?\)/g, '').trim() || '-', max);
}

/** 제목 정리 — RE:/FW: 접두 제거 + 컷. */
export function tgSubject(subject: string, max = 34): string {
    let s = (subject || '').trim();
    const prefix = /^\s*(re|fw|fwd|회신|전달|답장)\s*[:：]\s*/i;
    while (prefix.test(s)) s = s.replace(prefix, '');
    return tgCut(s, max);
}

export function kstNowStamp(d: Date = new Date()): string {
    const fmt = new Intl.DateTimeFormat('ko-KR', {
        timeZone: 'Asia/Seoul', year: 'numeric', month: '2-digit', day: '2-digit',
        hour: '2-digit', minute: '2-digit', hour12: false,
    });
    const parts = fmt.formatToParts(d);
    const get = (t: string) => parts.find(p => p.type === t)?.value || '';
    return `${get('year')}-${get('month')}-${get('day')} ${get('hour')}:${get('minute')} KST`;
}

/** 단일 렌더러 — 모든 텔레그램 정기/알림 메시지의 조립 지점. */
export function renderTelegram(msg: TgMessage): string {
    const lines: string[] = [];
    lines.push(`${msg.emoji} *${msg.title}*${typeof msg.count === 'number' ? ` (${msg.count})` : ''}`);
    if (msg.timestamp) lines.push(`_${kstNowStamp()}_`);

    for (const sec of msg.sections) {
        const items = sec.items || [];
        const shown = items.slice(0, Math.max(1, sec.maxItems ?? 7));
        if (!sec.heading && shown.length === 0 && !(sec.lines || []).length) continue;
        lines.push('');
        if (sec.heading) lines.push(`*${sec.heading}*${typeof sec.count === 'number' ? ` (${sec.count})` : ''}`);
        for (const l of sec.lines || []) lines.push(l);
        shown.forEach((it, i) => {
            lines.push(`${i + 1}. ${tgCut(it.main, 40)}`);
            if (it.sub) lines.push(`    ${tgCut(it.sub, 44)}`);
        });
        const hidden = (typeof sec.count === 'number' ? sec.count : items.length) - shown.length;
        if (hidden > 0) lines.push(`… 외 ${hidden}건`);
    }

    if (msg.footer) lines.push('', `_${msg.footer}_`);
    const out = lines.join('\n');
    return out.length > MAX_LEN ? out.slice(0, MAX_LEN) + '\n…(잘림)' : out;
}

/** "09:00,15:00" 형식 스케줄 파서 — 메신저 설정 공용. 잘못된 토큰은 무시. */
export function parseTimesCsv(csv: string): { hour: number; minute: number }[] {
    return (csv || '')
        .split(',')
        .map(t => t.trim())
        .filter(Boolean)
        .map(t => {
            const m = t.match(/^(\d{1,2})\s*:\s*(\d{2})$/);
            if (!m) return null;
            const hour = parseInt(m[1], 10), minute = parseInt(m[2], 10);
            if (hour < 0 || hour > 23 || minute < 0 || minute > 59) return null;
            return { hour, minute };
        })
        .filter((x): x is { hour: number; minute: number } => x !== null)
        .sort((a, b) => a.hour * 60 + a.minute - (b.hour * 60 + b.minute));
}
