/**
 * ============================================================
 * Gmail API v1 — 읽기 전용(read-only) 메시지 수집 (Project Astra, Phase 1)
 *
 * Calendar/Tasks/Sheets 와 *같은 Google OAuth 토큰*을 공유한다
 * (`getFreshAccessToken`). scope 에 `gmail.readonly` 가 포함돼야 함(oauth.ts).
 * 삭제/답장/전달 등 쓰기 기능은 일절 없다(읽기 전용 — 데이터 무결성·보안).
 *
 * 외부 라이브러리 없음 — REST + native fetch. tasksApi.ts 와 동일한 셰이프:
 *   (context, ...) -> getFreshAccessToken -> fetch -> { ok, data } | { ok:false, error }
 * ============================================================
 */

import * as vscode from 'vscode';
import { getFreshAccessToken } from '../calendar/calendarApi';

const API_BASE = 'https://gmail.googleapis.com/gmail/v1/users/me';

export interface ParsedMessage {
    messageId: string;
    threadId: string;
    from: string;
    to: string;
    subject: string;
    /** epoch ms */
    date: number;
    snippet: string;
    bodyText: string;
    permalink: string;
    labels: string[];
}

type ApiResult<T> = { ok: true; data: T } | { ok: false; error: string };

function authError(status: number, msg: string): boolean {
    return status === 401 || status === 403 || /insufficient|scope|disabled|enable/i.test(msg);
}

const REAUTH_HINT =
    'Gmail API 권한 부족 — "Astra: Google Calendar OAuth 연결" 명령을 다시 실행해 gmail.readonly 스코프 동의가 필요합니다. (Google Cloud Console 에서 Gmail API 활성화도 확인)';

/**
 * 최근 메시지 id 목록을 조회. q 는 Gmail 검색 문법(예: `newer_than:7d`).
 * maxResults 까지 pageToken 으로 페이지네이션한다.
 */
export async function listMessageIds(
    context: vscode.ExtensionContext,
    opts: { query?: string; maxResults?: number } = {},
): Promise<ApiResult<Array<{ id: string; threadId: string }>>> {
    const tok = await getFreshAccessToken(context);
    if (!tok.ok) return { ok: false, error: tok.error };

    const target = Math.max(1, Math.min(2000, opts.maxResults ?? 200));
    const out: Array<{ id: string; threadId: string }> = [];
    let pageToken: string | undefined;

    try {
        while (out.length < target) {
            const params = new URLSearchParams({ maxResults: String(Math.min(100, target - out.length)) });
            if (opts.query) params.set('q', opts.query);
            if (pageToken) params.set('pageToken', pageToken);
            const res = await fetch(`${API_BASE}/messages?${params.toString()}`, {
                headers: { Authorization: `Bearer ${tok.accessToken}` },
                signal: AbortSignal.timeout(20000),
            });
            const json: any = await res.json().catch(() => ({}));
            if (!res.ok) {
                const msg: string = json?.error?.message || `HTTP ${res.status}`;
                return { ok: false, error: authError(res.status, msg) ? REAUTH_HINT : msg };
            }
            const items: any[] = Array.isArray(json.messages) ? json.messages : [];
            for (const m of items) {
                if (m?.id) out.push({ id: String(m.id), threadId: String(m.threadId || '') });
            }
            pageToken = json.nextPageToken;
            if (!pageToken || items.length === 0) break;
        }
        return { ok: true, data: out.slice(0, target) };
    } catch (e: any) {
        return { ok: false, error: e?.message || String(e) };
    }
}

/** 단일 메시지 전체(format=full)를 조회해 파싱. */
export async function getMessage(
    context: vscode.ExtensionContext,
    id: string,
): Promise<ApiResult<ParsedMessage>> {
    const tok = await getFreshAccessToken(context);
    if (!tok.ok) return { ok: false, error: tok.error };
    try {
        const res = await fetch(`${API_BASE}/messages/${encodeURIComponent(id)}?format=full`, {
            headers: { Authorization: `Bearer ${tok.accessToken}` },
            signal: AbortSignal.timeout(20000),
        });
        const json: any = await res.json().catch(() => ({}));
        if (!res.ok) {
            const msg: string = json?.error?.message || `HTTP ${res.status}`;
            return { ok: false, error: authError(res.status, msg) ? REAUTH_HINT : msg };
        }
        return { ok: true, data: parseMessage(json) };
    } catch (e: any) {
        return { ok: false, error: e?.message || String(e) };
    }
}

/** 스레드 전체 메시지 조회 + 파싱 (v2.2.269 — /email read/wikify 용). 시간순 정렬. */
export async function getThreadMessages(
    context: vscode.ExtensionContext,
    threadId: string,
): Promise<ApiResult<ParsedMessage[]>> {
    const tok = await getFreshAccessToken(context);
    if (!tok.ok) return { ok: false, error: tok.error };
    try {
        const res = await fetch(`${API_BASE}/threads/${encodeURIComponent(threadId)}?format=full`, {
            headers: { Authorization: `Bearer ${tok.accessToken}` },
            signal: AbortSignal.timeout(25000),
        });
        const json: any = await res.json().catch(() => ({}));
        if (!res.ok) {
            const msg: string = json?.error?.message || `HTTP ${res.status}`;
            return { ok: false, error: authError(res.status, msg) ? REAUTH_HINT : msg };
        }
        const msgs: any[] = Array.isArray(json?.messages) ? json.messages : [];
        const parsed = msgs.map(parseMessage).sort((a, b) => a.date - b.date);
        return { ok: true, data: parsed };
    } catch (e: any) {
        return { ok: false, error: e?.message || String(e) };
    }
}

// ─── 파싱 헬퍼 ───────────────────────────────────────────────────────────────

function header(headers: any[], name: string): string {
    const h = (headers || []).find((x) => String(x?.name || '').toLowerCase() === name.toLowerCase());
    return h ? String(h.value || '') : '';
}

function decodeBase64Url(data: string): string {
    try {
        return Buffer.from(String(data).replace(/-/g, '+').replace(/_/g, '/'), 'base64').toString('utf-8');
    } catch {
        return '';
    }
}

/** payload 트리를 순회하며 text/plain 본문을 추출. 없으면 text/html 을 태그 제거해 사용. */
function extractBody(payload: any): string {
    if (!payload) return '';
    const plain = findPart(payload, 'text/plain');
    if (plain) return plain;
    const html = findPart(payload, 'text/html');
    if (html) return html.replace(/<style[\s\S]*?<\/style>/gi, ' ').replace(/<[^>]+>/g, ' ').replace(/&nbsp;/g, ' ').replace(/\s+\n/g, '\n');
    return '';
}

function findPart(node: any, mime: string): string {
    if (!node) return '';
    if (node.mimeType === mime && node.body?.data) return decodeBase64Url(node.body.data);
    const parts: any[] = Array.isArray(node.parts) ? node.parts : [];
    for (const p of parts) {
        const found = findPart(p, mime);
        if (found) return found;
    }
    return '';
}

function parseMessage(msg: any): ParsedMessage {
    const headers: any[] = msg?.payload?.headers || [];
    const internal = Number(msg?.internalDate);
    const dateHeader = Date.parse(header(headers, 'Date'));
    const date = Number.isFinite(internal) && internal > 0
        ? internal
        : (Number.isFinite(dateHeader) ? dateHeader : Date.now());
    return {
        messageId: String(msg?.id || ''),
        threadId: String(msg?.threadId || ''),
        from: header(headers, 'From'),
        to: header(headers, 'To'),
        subject: header(headers, 'Subject'),
        date,
        snippet: String(msg?.snippet || ''),
        bodyText: extractBody(msg?.payload).trim(),
        permalink: `https://mail.google.com/mail/u/0/#all/${String(msg?.id || '')}`,
        labels: Array.isArray(msg?.labelIds) ? msg.labelIds.map((x: any) => String(x)) : [],
    };
}
