#!/usr/bin/env python3
"""
扫描已过截止时间但未完成的待办，输出逾期清单

用法:
    python todo_overdue_check.py
    python todo_overdue_check.py --dry-run
"""

import sys
import json
import subprocess
from datetime import datetime
from typing import List, Dict, Any, Optional

PAGE_SIZE = 50
MAX_PAGES = 10
PRIORITY_MAP = {10: '低', 20: '普通', 30: '较高', 40: '紧急'}


def run_dws(
    args: List[str], dry_run: bool = False,
) -> Optional[Any]:
    cmd = ['dws'] + args
    if dry_run:
        print(f"[dry-run] {' '.join(cmd)}")
        return None
    try:
        result = subprocess.run(
            cmd, capture_output=True, text=True, timeout=60
        )
        if result.returncode != 0:
            print(f"错误：{result.stderr.strip()}", file=sys.stderr)
            return None
        return json.loads(result.stdout)
    except (subprocess.TimeoutExpired, json.JSONDecodeError,
            FileNotFoundError) as e:
        print(f"错误：{e}", file=sys.stderr)
        return None


def fetch_all_undone(dry_run: bool = False) -> List[Dict[str, Any]]:
    all_todos: List[Dict[str, Any]] = []
    for page in range(1, MAX_PAGES + 1):
        data = run_dws([
            'todo', 'task', 'list',
            '--page', str(page), '--size', str(PAGE_SIZE),
            '--status', 'false', '--format', 'json',
        ], dry_run=dry_run)
        if dry_run or not data:
            break
        if isinstance(data, list):
            items = data
        elif isinstance(data, dict):
            inner = data.get('result', data)
            if isinstance(inner, dict):
                items = inner.get('todoCards', [])
            elif isinstance(inner, list):
                items = inner
            else:
                items = []
        else:
            items = []
        if not items or not isinstance(items, list):
            break
        all_todos.extend(items)
        if len(items) < PAGE_SIZE:
            break
    return all_todos


def find_overdue(todos: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
    now_ms = int(datetime.now().timestamp() * 1000)
    overdue = []
    for t in todos:
        due = t.get('dueTime') or t.get('due')
        if not due:
            continue
        try:
            if int(due) < now_ms:
                overdue.append(t)
        except (ValueError, TypeError):
            continue
    return overdue


def days_overdue(due_ms) -> int:
    now = datetime.now()
    try:
        due_dt = datetime.fromtimestamp(int(due_ms) / 1000)
        return max(0, (now - due_dt).days)
    except (ValueError, TypeError, OSError):
        return 0


def main():
    dry_run = '--dry-run' in sys.argv
    todos = fetch_all_undone(dry_run=dry_run)
    if dry_run:
        return

    overdue = find_overdue(todos)
    overdue.sort(
        key=lambda t: int(t.get('dueTime') or t.get('due', 0))
    )

    print(f"\n⏰ 逾期待办检查 ({datetime.now().strftime('%Y-%m-%d %H:%M')})")
    print('=' * 50)

    if not overdue:
        print('  ✅ 没有逾期待办，继续保持！')
        return

    for t in overdue:
        title = t.get('subject') or t.get('title', '无标题')
        due = t.get('dueTime') or t.get('due')
        days = days_overdue(due)
        pri = PRIORITY_MAP.get(
            int(t.get('priority', 20)), '普通'
        )
        due_str = datetime.fromtimestamp(
            int(due) / 1000
        ).strftime('%Y-%m-%d')
        print(f"  🔴 [{pri}] {title}")
        print(f"     截止: {due_str}  逾期: {days} 天")

    print(f"\n合计: {len(overdue)} 条逾期待办")
    sys.exit(1 if overdue else 0)


if __name__ == '__main__':
    main()
