import * as vscode from 'vscode';
import { logError, logInfo } from '../../utils';
import { readStocksStore, writeStocksStore } from './stocksStore';
import { fetchAllPrices } from './yahooClient';
import { sendStocksReport } from './telegramReport';
import { syncToSheets } from './sheetsSync';

/**
 * VS Code 시작 시 자동 활성화 — KST 09:00 / 15:00 에:
 *   1. Yahoo 로 현재가 일괄 갱신 → stocks.json 업데이트
 *   2. (선택) Google Sheets 동기화 — g1nation.stocks.spreadsheetId 설정 시
 *   3. 텔레그램 보고서 발송
 *
 * 구현 노트:
 *  - setTimeout 단일 chain — 매 firing 후 다음 알람까지 재계산해서 새 setTimeout.
 *  - VS Code 종료 시 disposable 로 clear.
 *  - 시간대는 Asia/Seoul 강제 — 사용자 macOS timezone 과 무관하게 같은 시각에 동작.
 *  - run_kodari_sync.command 의 sleep-loop 구조를 단일 setTimeout 으로 대체.
 *
 * 트리거 시각 변경 시 SCHEDULE 만 수정 — 분 단위.
 */

const SCHEDULE_HOURS_KST = [9, 15]; // 09:00, 15:00 KST

let _timer: NodeJS.Timeout | undefined;
let _disposed = false;

/** Asia/Seoul 기준 *지금* 의 hour/minute. */
function nowInKst(): { date: Date; hour: number; minute: number; ymd: string } {
    const now = new Date();
    const parts = new Intl.DateTimeFormat('en-US', {
        timeZone: 'Asia/Seoul',
        year: 'numeric', month: '2-digit', day: '2-digit',
        hour: '2-digit', minute: '2-digit', hour12: false,
    }).formatToParts(now);
    const get = (t: string) => Number(parts.find(p => p.type === t)?.value || '0');
    return {
        date: now,
        hour: get('hour'),
        minute: get('minute'),
        ymd: `${get('year')}-${parts.find(p => p.type === 'month')?.value}-${parts.find(p => p.type === 'day')?.value}`,
    };
}

/**
 * 지금부터 다음 firing 까지 milliseconds 계산.
 * SCHEDULE_HOURS_KST 중 *오늘 남은 시각* 우선, 다 지났으면 내일 첫 시각.
 *
 * 시간대 변환: 사용자 OS 가 KST 가 아닐 수 있으므로 KST 기준 hour/minute 으로 비교 후
 * 그 차이를 ms 로 변환 (변환은 단순 산수 — 분 차이 × 60000).
 */
function msUntilNextRun(): number {
    const kst = nowInKst();
    const todayMinutes = kst.hour * 60 + kst.minute;

    let bestTodayMinutes: number | null = null;
    for (const h of SCHEDULE_HOURS_KST) {
        const targetMinutes = h * 60;
        if (targetMinutes > todayMinutes) {
            bestTodayMinutes = targetMinutes;
            break;
        }
    }

    if (bestTodayMinutes !== null) {
        return (bestTodayMinutes - todayMinutes) * 60_000;
    }
    // 오늘 더 없음 → 내일 첫 시각.
    const tomorrowFirstMinutes = SCHEDULE_HOURS_KST[0] * 60;
    const remainingTodayMinutes = 24 * 60 - todayMinutes;
    return (remainingTodayMinutes + tomorrowFirstMinutes) * 60_000;
}

/**
 * 한 번 fire — 가격 갱신 + (선택) Sheets sync + 텔레그램 보고서.
 * 각 단계는 독립적으로 try/catch — 한 단계 실패해도 다른 단계는 계속.
 */
async function fireOnce(context: vscode.ExtensionContext): Promise<void> {
    const kst = nowInKst();
    logInfo('Stocks watcher fire 시작.', { kst: `${kst.hour}:${kst.minute}` });

    // (1) Yahoo 가격 갱신
    try {
        const store = readStocksStore();
        const symbols = store.map(s => s.심볼).filter(Boolean);
        if (symbols.length === 0) {
            logInfo('Stocks watcher: 종목 없음 — skip.');
        } else {
            const prices = await fetchAllPrices(symbols);
            for (const s of store) {
                const p = prices.get(s.심볼);
                if (typeof p === 'number') s.현재가 = p;
            }
            writeStocksStore(store);
        }
    } catch (e: any) {
        logError('Stocks watcher: 가격 갱신 실패.', { error: e?.message ?? String(e) });
    }

    // (2) Sheets sync — 선택 (spreadsheetId 설정 시에만)
    try {
        const cfg = vscode.workspace.getConfiguration('g1nation');
        if ((cfg.get<string>('stocks.spreadsheetId') || '').trim()) {
            const r = await syncToSheets(context);
            if (!r.ok) logError('Stocks watcher: Sheets 동기화 실패.', { errors: r.errors });
        }
    } catch (e: any) {
        logError('Stocks watcher: Sheets 호출 실패.', { error: e?.message ?? String(e) });
    }

    // (3) Telegram 보고서
    try {
        const r = await sendStocksReport(context);
        if (!r.ok) logInfo(`Stocks watcher: 보고서 skip — ${r.reason}`);
    } catch (e: any) {
        logError('Stocks watcher: 보고서 호출 실패.', { error: e?.message ?? String(e) });
    }
}

function scheduleNext(context: vscode.ExtensionContext): void {
    if (_disposed) return;
    const ms = msUntilNextRun();
    const hours = Math.floor(ms / 3600_000);
    const minutes = Math.floor((ms % 3600_000) / 60_000);
    logInfo(`Stocks watcher: 다음 firing 까지 ${hours}h ${minutes}m.`);

    _timer = setTimeout(async () => {
        try {
            await fireOnce(context);
        } catch (e: any) {
            logError('Stocks watcher: fireOnce 예외.', { error: e?.message ?? String(e) });
        }
        scheduleNext(context);
    }, ms);
}

/**
 * VS Code 시작 시 호출 (extension.ts activate 의 마지막 단계).
 * 설정 `g1nation.stocks.watcherEnabled` 가 false 이면 활성화 skip.
 */
export function startStocksWatcher(context: vscode.ExtensionContext): vscode.Disposable {
    const cfg = vscode.workspace.getConfiguration('g1nation');
    const enabled = cfg.get<boolean>('stocks.watcherEnabled', true);
    if (!enabled) {
        logInfo('Stocks watcher: 비활성 (g1nation.stocks.watcherEnabled=false).');
        return { dispose: () => {} };
    }
    _disposed = false;
    scheduleNext(context);
    logInfo('Stocks watcher: 시작됨.', { schedule: SCHEDULE_HOURS_KST });
    return {
        dispose: () => {
            _disposed = true;
            if (_timer) { clearTimeout(_timer); _timer = undefined; }
            logInfo('Stocks watcher: dispose.');
        },
    };
}

/** 명령으로 즉시 한 번 트리거 (`/stocks watch run` 같은 미래 명령 또는 디버깅). */
export async function runOnceNow(context: vscode.ExtensionContext): Promise<void> {
    await fireOnce(context);
}
