#!/usr/bin/env python3
"""
日程变化监控器。

执行时机：每小时整点（北京时间 8:00–20:00），由 OpenClaw Cron 触发。

流程：
  1. 加载上次快照（data/last_events.json）
  2. 拉取 Google Calendar 今天+明天的事件
  3. 对比变化：新增、修改、取消
  4. 保存新快照
  5. 有变化时打印通知（OpenClaw 捕获 stdout 并投递）
     无变化时只打印日志，不输出通知

核心规则：
  - 无变化 → 不通知
  - 已结束事件消失 → 不通知
  - 被取消事件消失 → 通知

用法：
  python3 apps/monitor_calendar_changes.py
  python3 apps/monitor_calendar_changes.py --dry-run   # 不写快照，只打印结果
"""

from __future__ import annotations

import argparse
import json
import logging
import sys
from datetime import datetime, timezone
from pathlib import Path

# ── sys.path ─────────────────────────────────────────────────────
sys.path.insert(0, str(Path(__file__).parent.parent))

from config.settings import (
    GCAL_TOKEN_PATH, PROXIES, GCAL_TIMEOUT, GCAL_MAX_RETRIES,
    GCAL_CALENDAR_ID, GCAL_SSL_VERIFY, TIMEZONE, DATA_DIR, LAST_EVENTS_FILE,
)
from gcal.client import CalendarClient
from gcal.models import CalendarEvent
from services.calendar_backend import active_provider
from services.time_window import get_today_and_tomorrow_window
from services.event_diff import diff_events

logging.basicConfig(level=logging.INFO, format="%(levelname)s %(message)s")
logger = logging.getLogger(__name__)


# ─────────────────────────── 快照读写 ────────────────────────────

def load_snapshot() -> list[CalendarEvent]:
    if not LAST_EVENTS_FILE.exists():
        logger.info("📝 无历史快照，首次运行")
        return []
    try:
        with open(LAST_EVENTS_FILE, encoding="utf-8") as f:
            data = json.load(f)
        events = [CalendarEvent.from_dict(e) for e in data.get("events", [])]
        logger.info(f"加载上次快照：{len(events)} 个事件，时间 {data.get('last_updated', '未知')}")
        return events
    except Exception as e:
        logger.error(f"读取快照失败: {e}")
        return []


def save_snapshot(events: list[CalendarEvent]) -> None:
    DATA_DIR.mkdir(parents=True, exist_ok=True)
    now_utc = datetime.now(timezone.utc).isoformat()
    # 只保存未来的事件（已结束的不再追踪）
    future = [e for e in events if not e.is_past()]
    data = {
        "events":       [e.to_dict() for e in future],
        "last_updated": now_utc,
        "total":        len(future),
    }
    with open(LAST_EVENTS_FILE, "w", encoding="utf-8") as f:
        json.dump(data, f, indent=2, ensure_ascii=False)
    logger.info(f"✅ 快照已更新：{len(future)} 个未来事件")


# ─────────────────────────── main ────────────────────────────────

def main():
    parser = argparse.ArgumentParser(description="日程变化监控")
    parser.add_argument("--dry-run", action="store_true",
                        help="不写快照，仅打印变化结果")
    args = parser.parse_args()

    logger.info(f"=== 日程变化监控 {datetime.now().strftime('%Y-%m-%d %H:%M:%S')} ===")

    if active_provider() != "google":
        logger.info("当前为本地模式，跳过 Google 日程变化轮询")
        sys.exit(0)

    # ── 1. 拉取当前日程 ───────────────────────────────────────────
    client = CalendarClient(
        GCAL_TOKEN_PATH, PROXIES,
        calendar_id=GCAL_CALENDAR_ID,
        timeout=GCAL_TIMEOUT,
        max_retries=GCAL_MAX_RETRIES,
        verify=GCAL_SSL_VERIFY,
    )
    t_min, t_max = get_today_and_tomorrow_window(TIMEZONE)

    try:
        current_events = client.list_events(t_min, t_max)
        logger.info(f"当前事件数：{len(current_events)}")
    except Exception as e:
        logger.error(f"❌ 拉取日程失败: {e}")
        sys.exit(1)

    # ── 2. 加载上次快照 ──────────────────────────────────────────
    last_events = load_snapshot()

    # ── 3. diff ──────────────────────────────────────────────────
    result = diff_events(
        current=current_events,
        last=last_events,
        get_remote_status=client.get_event_status,
    )

    # ── 4. 保存快照 ──────────────────────────────────────────────
    if not args.dry_run:
        save_snapshot(current_events)

    # ── 5. 输出结果 ──────────────────────────────────────────────
    if not result.has_changes:
        logger.info("✅ 无变化，不发送通知")
        sys.exit(0)

    logger.info(f"检测到变化：{result.summary_text}")
    # OpenClaw cron 会捕获 stdout 并投递给 用户
    # 监控任务配置为 delivery:none，由此脚本自行控制是否通知
    print(result.format_notification())


if __name__ == "__main__":
    main()
