from __future__ import annotations

"""
task-timers.json reconcile from memory/events/*.done — idempotent.

Source of truth (우선순위):
1. completed_at
2. end_time
3. merged_at

helpers.py:454 mtime fallback은 절대 사용 X (5/9 14:32 일괄 갱신 사고 재발 방지).

5/8, 5/9 entries reconcile:
- done event 시각 기반으로 task-timers.json end_time backfill
- 기존 entry는 보존 (덮어쓰기 X), 누락된 entry만 추가
- chat_id != 6937032012 record는 silently skip
"""

import argparse
import json
import os
import tempfile
from pathlib import Path


def reconcile_from_done_events(
    timers_path: Path = Path("memory/task-timers.json"),
    events_dir: Path = Path("memory/events"),
    chat_id_filter: int = 6937032012,
    target_date_range: tuple[str, str] = ("2026-05-08", "2026-05-09"),
    dry_run: bool = False,
) -> dict:
    """
    결과 dict: {
        "backfilled": int,
        "skipped_existing": int,
        "skipped_other_chat": int,
        "skipped_no_timestamp": int,
        "tasks_added": list[str],
    }

    동작:
      1. events_dir (루트 + archive/ 모두)의 done event 파일을 스캔
         지원 변종: *.done, *.merge-done, *.done.acked (helpers _resolve_end_time_priority 와 동일)
      2. 각 .done JSON 로드 후 시각 우선순위: completed_at -> end_time -> merged_at
      3. 시각 date(첫 10자) 가 target_date_range 양쪽 경계 포함이면 후보
      4. chat_id 필드가 존재하고 chat_id_filter 와 다르면 silently skip
      5. task-timers.json tasks[task_id] 가 이미 존재하면 silently skip (idempotent)
      6. 누락 entry 추가
      7. dry_run=False 이면 원자적 쓰기(임시파일 → rename)
    """
    timers_path = Path(timers_path)
    events_dir = Path(events_dir)
    date_lo, date_hi = target_date_range
    chat_id_filter_str = str(chat_id_filter)

    # --- load task-timers.json ---
    if timers_path.exists():
        with open(timers_path, encoding="utf-8") as f:
            timers_data = json.load(f)
    else:
        timers_data = {"tasks": {}}
    tasks: dict = timers_data.setdefault("tasks", {})

    # --- scan .done files ---
    scan_dirs = [events_dir]
    archive_dir = events_dir / "archive"
    if archive_dir.exists():
        scan_dirs.append(archive_dir)

    backfilled = 0
    skipped_existing = 0
    skipped_other_chat = 0
    skipped_no_timestamp = 0
    tasks_added: list[str] = []

    for scan_base in scan_dirs:
        if not scan_base.exists():
            continue
        for p in sorted(scan_base.iterdir()):
            # helpers._resolve_end_time_priority 와 동일 변종 지원: .done / .merge-done / .done.acked
            if not p.is_file():
                continue
            if not (
                p.name.endswith(".done")
                or p.name.endswith(".merge-done")
                or p.name.endswith(".done.acked")
            ):
                continue

            # --- JSON 로드 ---
            try:
                with open(p, encoding="utf-8") as f:
                    data = json.load(f)
            except (json.JSONDecodeError, OSError):
                continue
            if not isinstance(data, dict):
                continue

            # --- 시각 우선순위 ---
            ts = data.get("completed_at") or data.get("end_time") or data.get("merged_at")
            if not ts:
                skipped_no_timestamp += 1
                continue

            # --- date 필터 ---
            date_str = str(ts)[:10]
            if not (date_lo <= date_str <= date_hi):
                continue

            # --- chat_id 필터 ---
            raw_chat_id = data.get("chat_id")
            if raw_chat_id is not None:
                if str(raw_chat_id) != chat_id_filter_str:
                    skipped_other_chat += 1
                    continue
            # chat_id 미명시 → 우리 chat 기본값으로 간주 (skip 아님)

            # --- task_id 결정 ---
            tid = data.get("task_id")
            if not tid:
                # 파일명에서 추론 (지원 변종 모두 strip)
                name = p.name
                for suf in (".done.acked", ".merge-done", ".done"):
                    if name.endswith(suf):
                        tid = name[: -len(suf)]
                        break
                if not tid:
                    tid = p.stem

            # --- idempotent: 이미 존재하면 skip ---
            if tid in tasks:
                skipped_existing += 1
                continue

            # --- team_id 결정 ---
            team_or_id = data.get("team_id") or data.get("team") or ""

            # --- 시각 정규화 (string 그대로) ---
            ts_str = str(ts)

            # --- entry 구성 ---
            entry = {
                "task_id": tid,
                "team_id": team_or_id,
                "description": "(reconcile from done event)",
                "start_time": ts_str,
                "end_time": ts_str,
                "status": "completed",
                "duration_seconds": 0,
                "duration_human": "0초",
                "reconciled_from_done_event_2543": True,
            }

            tasks[tid] = entry
            tasks_added.append(tid)
            backfilled += 1

    result = {
        "backfilled": backfilled,
        "skipped_existing": skipped_existing,
        "skipped_other_chat": skipped_other_chat,
        "skipped_no_timestamp": skipped_no_timestamp,
        "tasks_added": tasks_added,
    }

    # --- 원자적 쓰기 ---
    if not dry_run and backfilled > 0:
        timers_dir = timers_path.parent
        timers_dir.mkdir(parents=True, exist_ok=True)
        fd, tmp_path = tempfile.mkstemp(dir=timers_dir, suffix=".tmp")
        try:
            with os.fdopen(fd, "w", encoding="utf-8") as tmp_f:
                json.dump(timers_data, tmp_f, ensure_ascii=False, indent=2)
            os.replace(tmp_path, timers_path)
        except Exception:
            try:
                os.unlink(tmp_path)
            except Exception:
                pass
            raise

    return result


if __name__ == "__main__":
    parser = argparse.ArgumentParser(
        description="task-timers.json reconcile from done events (idempotent)"
    )
    parser.add_argument(
        "--dry-run",
        action="store_true",
        default=False,
        help="변경 없이 결과만 출력",
    )
    parser.add_argument(
        "--timers-path",
        default="memory/task-timers.json",
        help="task-timers.json 경로 (기본: memory/task-timers.json)",
    )
    parser.add_argument(
        "--events-dir",
        default="memory/events",
        help="done events 디렉토리 (기본: memory/events)",
    )
    args = parser.parse_args()

    result = reconcile_from_done_events(
        timers_path=Path(args.timers_path),
        events_dir=Path(args.events_dir),
        dry_run=args.dry_run,
    )
    print(json.dumps(result, indent=2, ensure_ascii=False))
