"""
whisper-save-guidance.py

세션 종료 시 현재 상태를 스냅샷하여 다음 세션 가이던스를 생성하는 스크립트.

입력:
  - /home/jay/workspace/memory/events/bot-activity.json
  - /home/jay/workspace/memory/task-timers.json
  - /home/jay/workspace/memory/events/*.done

출력:
  - /home/jay/workspace/memory/whisper/session-guidance.json

사용법:
  python3 whisper-save-guidance.py
"""

import json
import os
import sys
from datetime import datetime, timedelta, timezone
from pathlib import Path
from typing import Any

# ---------------------------------------------------------------------------
# 경로 상수
# ---------------------------------------------------------------------------

_WORKSPACE_ROOT = os.environ.get("WORKSPACE_ROOT", str(Path(__file__).resolve().parent.parent))
_DEFAULT_BASE_DIR = Path(_WORKSPACE_ROOT) / "memory"

_BOT_ACTIVITY_REL = Path("events/bot-activity.json")
_TASK_TIMERS_REL = Path("task-timers.json")
_EVENTS_DIR_REL = Path("events")
_GUIDANCE_REL = Path("whisper/session-guidance.json")

# 유휴 팀 판정 기준 (시간) - config/constants.json 참조
_CONSTANTS_PATH = Path(_WORKSPACE_ROOT) / "config" / "constants.json"
try:
    with open(_CONSTANTS_PATH, encoding="utf-8") as _f:
        _CONSTANTS = json.load(_f)
except (FileNotFoundError, json.JSONDecodeError):
    _CONSTANTS = {}

_IDLE_THRESHOLD_HOURS = float(_CONSTANTS.get("thresholds", {}).get("idle_hours", 3))


# ---------------------------------------------------------------------------
# 데이터 로드 함수
# ---------------------------------------------------------------------------


def load_bot_activity(base_dir: Path = _DEFAULT_BASE_DIR) -> dict[str, Any]:
    """bot-activity.json을 읽어 bots dict 반환.

    파일이 없거나 손상된 경우 빈 dict 반환 (graceful fallback).
    """
    path = base_dir / _BOT_ACTIVITY_REL
    try:
        data = json.loads(path.read_text(encoding="utf-8"))
        bots = data.get("bots")
        if not isinstance(bots, dict):
            return {}
        return bots
    except (FileNotFoundError, json.JSONDecodeError, OSError):
        return {}


def load_task_timers(base_dir: Path = _DEFAULT_BASE_DIR) -> dict[str, Any]:
    """task-timers.json을 읽어 tasks dict 반환.

    파일이 없거나 손상된 경우 빈 dict 반환 (graceful fallback).
    """
    path = base_dir / _TASK_TIMERS_REL
    try:
        data = json.loads(path.read_text(encoding="utf-8"))
        tasks = data.get("tasks")
        if not isinstance(tasks, dict):
            return {}
        return tasks
    except (FileNotFoundError, json.JSONDecodeError, OSError):
        return {}


def scan_done_files(base_dir: Path = _DEFAULT_BASE_DIR) -> list[str]:
    """events/ 디렉토리에서 *.done 파일을 스캔하여 task_id 목록 반환.

    확장자가 정확히 .done 인 파일만 포함 (.done.clear 등은 제외).
    """
    events_dir = base_dir / _EVENTS_DIR_REL
    if not events_dir.is_dir():
        return []

    task_ids: list[str] = []
    for p in events_dir.iterdir():
        # 확장자가 정확히 .done 인 파일만
        if p.suffix == ".done":
            task_ids.append(p.stem)
    return task_ids


# ---------------------------------------------------------------------------
# guidance 생성 함수
# ---------------------------------------------------------------------------


def _parse_iso(ts: str) -> datetime | None:
    """ISO8601 문자열을 timezone-aware datetime으로 파싱."""
    try:
        dt = datetime.fromisoformat(ts)
        if dt.tzinfo is None:
            # naive → UTC 가정
            dt = dt.replace(tzinfo=timezone.utc)
        return dt
    except (ValueError, TypeError):
        return None


def generate_guidance(
    bots: dict[str, Any],
    tasks: dict[str, Any],
    done_task_ids: list[str],
) -> dict[str, Any]:
    """수집된 데이터로 session-guidance dict를 생성."""
    now = datetime.now(timezone.utc)

    # --- active 작업 추출 (status == "running") ---
    active_tasks: list[str] = [
        tid for tid, info in tasks.items() if isinstance(info, dict) and info.get("status") == "running"
    ]

    # --- idle 팀 추출 (status == "idle" AND idle 시간 >= 3h) ---
    idle_teams: list[str] = []
    for bot_id, info in bots.items():
        if not isinstance(info, dict):
            continue
        if info.get("status") != "idle":
            continue
        since_str = info.get("since", "")
        since_dt = _parse_iso(since_str)
        if since_dt is None:
            continue
        idle_hours = (now - since_dt).total_seconds() / 3600.0
        if idle_hours >= _IDLE_THRESHOLD_HOURS:
            idle_teams.append(f"{bot_id}-team")

    # --- pending dispatches (done 파일 → 미처리 완료 작업) ---
    pending_dispatches: list[str] = [f"{tid} 완료 확인 필요" for tid in done_task_ids]

    # --- guidance 텍스트 생성 ---
    parts: list[str] = []

    if active_tasks:
        task_list = ", ".join(active_tasks)
        # team_id 포함 표현: "task-565.1(1팀)" 스타일로 팀 약어 추가
        task_display_parts: list[str] = []
        for tid in active_tasks:
            info = tasks.get(tid, {})
            team_id: str = info.get("team_id", "") if isinstance(info, dict) else ""
            # dev1-team → 1팀, dev2-team → 2팀, dev3-team → 3팀 등
            team_label = _team_label(team_id)
            if team_label:
                task_display_parts.append(f"{tid}({team_label})")
            else:
                task_display_parts.append(tid)
        parts.append(f"활성 작업: {', '.join(task_display_parts)}")

    if done_task_ids:
        done_list = ", ".join(done_task_ids)
        parts.append(f"완료 미처리: {done_list}")

    if idle_teams:
        idle_list = ", ".join(idle_teams)
        parts.append(f"유휴 팀: {idle_list}")

    guidance_text = ". ".join(parts) + ("." if parts else "대기 중.")

    return {
        "last_session": now.strftime("%Y-%m-%dT%H:%M:%S"),
        "guidance": guidance_text,
        "pending_dispatches": pending_dispatches,
        "idle_teams": idle_teams,
        "active_tasks": active_tasks,
    }


def _team_label(team_id: str) -> str:
    """team_id를 사람이 읽기 쉬운 팀 레이블로 변환.

    예: "dev1-team" → "1팀", "dev2-team" → "2팀"
    """
    if not team_id:
        return ""
    # dev1-team, dev2-team, dev3-team 패턴
    for i in range(1, 10):
        if f"dev{i}" in team_id:
            return f"{i}팀"
    return ""


# ---------------------------------------------------------------------------
# 저장 함수
# ---------------------------------------------------------------------------


def save_guidance(
    data: dict[str, Any],
    base_dir: Path = _DEFAULT_BASE_DIR,
) -> None:
    """session-guidance.json으로 저장 (기존 파일 덮어쓰기)."""
    out_path = base_dir / _GUIDANCE_REL
    out_path.parent.mkdir(parents=True, exist_ok=True)
    out_path.write_text(
        json.dumps(data, ensure_ascii=False, indent=2),
        encoding="utf-8",
    )


# ---------------------------------------------------------------------------
# 메인 파이프라인
# ---------------------------------------------------------------------------


def run(base_dir: Path = _DEFAULT_BASE_DIR) -> None:
    """전체 파이프라인 실행."""
    bots = load_bot_activity(base_dir=base_dir)
    tasks = load_task_timers(base_dir=base_dir)
    done_task_ids = scan_done_files(base_dir=base_dir)

    guidance_data = generate_guidance(
        bots=bots,
        tasks=tasks,
        done_task_ids=done_task_ids,
    )

    save_guidance(guidance_data, base_dir=base_dir)


def main() -> None:
    """CLI 진입점. 인자 없음. exit code 항상 0."""
    run()


if __name__ == "__main__":
    main()
    sys.exit(0)
