#!/usr/bin/env python3
"""
将 ROC 事件按年份批量同步到 Google Calendar。

设计原则：
  - 每个年份独立管理，同一年只同步一次（除非 --force）。
  - 同步记录保存在 data/roc_gcal_sync.json：
      { "2026": {"roc-001": "gcal_event_id_xxx", ...}, "2027": {...} }
  - 事件以"全天事件"写入 Google Calendar，标题带 📅 前缀，备注含提醒日期。
  - 跨年自动处理：每年 1 月 1 日触发当年同步；check_roc.py 首次运行也会触发。

用法：
  python3 apps/sync_roc_to_gcal.py             # 同步当年
  python3 apps/sync_roc_to_gcal.py --year 2027 # 同步指定年份
  python3 apps/sync_roc_to_gcal.py --dry-run   # 只打印，不写入 GCal
  python3 apps/sync_roc_to_gcal.py --force     # 强制重新同步（已有记录也重建）
"""

from __future__ import annotations

import argparse
import json
import sys
from datetime import datetime
from pathlib import Path

import yaml

_SKILL_BASE = Path(__file__).resolve().parent.parent
sys.path.insert(0, str(_SKILL_BASE))

from config.settings import (
    GCAL_TOKEN_PATH, PROXIES, GCAL_TIMEOUT, GCAL_MAX_RETRIES, GCAL_CALENDAR_ID,
    GCAL_SSL_VERIFY, TIMEZONE,
)
from gcal.client import CalendarClient, CalendarAuthError, CalendarAPIError
from services.datetime_utils import current_year

_SYNC_STATE_FILE = _SKILL_BASE / "data" / "roc_gcal_sync.json"
_CONFIG_FILE     = _SKILL_BASE / "config" / "roc_events.yaml"


# ── 状态文件 ──────────────────────────────────────────────────────────

def _load_sync_state() -> dict:
    try:
        return json.loads(_SYNC_STATE_FILE.read_text(encoding="utf-8"))
    except Exception:
        return {}


def _save_sync_state(state: dict) -> None:
    _SYNC_STATE_FILE.parent.mkdir(parents=True, exist_ok=True)
    _SYNC_STATE_FILE.write_text(
        json.dumps(state, ensure_ascii=False, indent=2), encoding="utf-8"
    )


# ── 核心同步逻辑 ─────────────────────────────────────────────────────

def sync_year(
    year: int,
    dry_run: bool = False,
    force: bool = False,
    verbose: bool = True,
) -> dict:
    """
    同步指定年份的全部 ROC 事件到 Google Calendar。

    Returns:
        {"added": [...], "skipped": [...], "errors": [...]}
    """
    # 复用 check_roc 的日期解析逻辑，避免重复代码
    from apps.check_roc import build_year_events

    with open(_CONFIG_FILE, encoding="utf-8") as f:
        cfg = yaml.safe_load(f)

    year_events = build_year_events(year, cfg)
    sync_state  = _load_sync_state()
    year_key    = str(year)
    year_state  = dict(sync_state.get(year_key, {}))

    client = None
    if not dry_run:
        client = CalendarClient(
            GCAL_TOKEN_PATH, PROXIES, GCAL_CALENDAR_ID, GCAL_TIMEOUT, GCAL_MAX_RETRIES,
            verify=GCAL_SSL_VERIFY,
        )

    added, skipped, errors = [], [], []

    for ev in year_events:
        ev_id = ev["id"]

        # 已同步且不强制重建 → 跳过
        if ev_id in year_state and not force:
            skipped.append(ev["name"])
            if verbose:
                print(f"  ⏭  跳过（已同步）: {ev['name']}  {ev['event_date']}")
            continue

        summary     = f"📅 {ev['name']}"
        date_str    = ev["event_date"]
        desc_lines  = []
        if ev.get("description"):
            desc_lines.append(ev["description"])
        desc_lines.append(f"ROC 周期事件 | 提前提醒日期: {ev['reminder_date']}")
        description = "\n".join(desc_lines)

        if dry_run:
            print(f"  [dry-run] 将创建: {summary}  {date_str}")
            added.append(ev["name"])
            continue

        try:
            assert client is not None
            gcal_id = client.create_allday_event(
                summary, date_str, description=description
            )
            year_state[ev_id] = gcal_id
            added.append(ev["name"])
            if verbose:
                print(f"  ✅ 已创建: {summary}  {date_str}  (gcal_id={gcal_id})")
        except (CalendarAuthError, CalendarAPIError, Exception) as e:
            errors.append(f"{ev['name']}: {e}")
            if verbose:
                print(f"  ❌ 失败: {ev['name']}: {e}")

    # 写回状态（干跑时不写）
    if not dry_run:
        sync_state[year_key] = year_state
        _save_sync_state(sync_state)

    return {"added": added, "skipped": skipped, "errors": errors}


def is_year_synced(year: int) -> bool:
    """检查指定年份的 ROC 事件是否已同步（有任意记录即视为已同步）。"""
    state = _load_sync_state()
    return bool(state.get(str(year)))


# ── CLI ──────────────────────────────────────────────────────────────

def main() -> None:
    parser = argparse.ArgumentParser(description="ROC 事件 → Google Calendar 按年同步")
    parser.add_argument("--year", type=int, default=current_year(TIMEZONE),
                        help="目标年份（默认当年）")
    parser.add_argument("--dry-run", action="store_true",
                        help="只打印计划，不写入 GCal")
    parser.add_argument("--force", action="store_true",
                        help="强制重新同步（已有记录也重建）")
    args = parser.parse_args()

    label = f"{args.year} 年 ROC 事件"
    suffix = "（dry-run，不写入）" if args.dry_run else ""
    print(f"📅 同步 {label} 到 Google Calendar{suffix} …")

    result = sync_year(args.year, dry_run=args.dry_run, force=args.force)

    print(
        f"\n完成：新增 {len(result['added'])} 个，"
        f"跳过 {len(result['skipped'])} 个，"
        f"失败 {len(result['errors'])} 个"
    )
    if result["errors"]:
        for err in result["errors"]:
            print(f"  ✗ {err}")
        sys.exit(1)


if __name__ == "__main__":
    main()
