"""token_ledger.py — 일일 토큰 사용량 및 파이프라인 동시 실행 한도 관리.

작성자 : 토르 (dev2-team backend)
날짜   : 2026-03-24
"""

import datetime
import json
from pathlib import Path

__all__ = ["TokenLedger", "TOKENS_PER_MINUTE_OPUS", "TOKENS_PER_MINUTE_SONNET", "CONSERVATIVE_MULTIPLIER"]

TOKENS_PER_MINUTE_OPUS = 5000  # 팀장 설계 모드
TOKENS_PER_MINUTE_SONNET = 3000  # 팀원 코딩 모드
CONSERVATIVE_MULTIPLIER = 1.2  # 보수적 계수


class TokenLedger:
    DAILY_HARD_LIMIT = 1_000_000
    MAX_CONCURRENT_PIPELINES = 3
    MAX_RETRIES_PER_STEP = 2
    MAX_PIPELINE_STARTS_PER_DAY = 20

    def __init__(self, ledger_path: Path | str) -> None:
        self._path = Path(ledger_path)
        self._state: dict = self._load()

    # ------------------------------------------------------------------
    # Internal helpers
    # ------------------------------------------------------------------

    def _empty_state(self) -> dict:
        return {
            "date": datetime.date.today().isoformat(),
            "daily_total": 0,
            "pipelines": {},
        }

    def _load(self) -> dict:
        if not self._path.exists():
            return self._empty_state()
        try:
            raw = self._path.read_text(encoding="utf-8")
            data = json.loads(raw)
            if data.get("date") != datetime.date.today().isoformat():
                return self._empty_state()
            # 필수 키 보정
            data.setdefault("daily_total", 0)
            data.setdefault("pipelines", {})
            return data
        except (json.JSONDecodeError, OSError, KeyError):
            return self._empty_state()

    def _save(self) -> None:
        try:
            self._path.parent.mkdir(parents=True, exist_ok=True)
            self._path.write_text(json.dumps(self._state, ensure_ascii=False, indent=2), encoding="utf-8")
        except OSError:
            pass

    # ------------------------------------------------------------------
    # Public API
    # ------------------------------------------------------------------

    def record_usage(self, pipeline_id: str, tokens: int) -> None:
        """pipeline_id별 토큰 사용량을 누적하고 파일에 저장한다."""
        pipelines: dict = self._state["pipelines"]
        pipelines[pipeline_id] = pipelines.get(pipeline_id, 0) + tokens
        self._state["daily_total"] = self._state.get("daily_total", 0) + tokens
        self._save()

    def can_spend(self, pipeline_id: str, tokens: int) -> bool:
        """지정한 토큰을 소비할 수 있는지 여부를 반환한다."""
        daily_total: int = self._state.get("daily_total", 0)
        pipelines: dict = self._state.get("pipelines", {})
        is_new = pipeline_id not in pipelines

        # 1. 일일 한도 초과 여부
        if daily_total + tokens > self.DAILY_HARD_LIMIT:
            return False

        # 2. 신규 파이프라인인데 동시 실행 한도 초과
        if is_new and len(pipelines) >= self.MAX_CONCURRENT_PIPELINES:
            return False

        # 3. 신규 파이프라인인데 하루 시작 횟수 초과
        if is_new and len(pipelines) >= self.MAX_PIPELINE_STARTS_PER_DAY:
            return False

        return True

    def get_daily_usage(self) -> int:
        """현재 날짜의 총 토큰 사용량을 반환한다."""
        return int(self._state.get("daily_total", 0))

    def estimate_session_tokens(self, team_id: str, duration_seconds: float) -> int:
        """task-timers.json 세션 시간 기반 토큰 추정.

        Args:
            team_id: 팀 식별자 (예: "dev1-team")
            duration_seconds: 세션 지속 시간(초)

        Returns:
            추정 토큰 수 (정수)

        로직:
        - duration_seconds <= 0이면 0 반환
        - 기본 rate: TOKENS_PER_MINUTE_SONNET (3000 tokens/min)
        - 보수적 계수: CONSERVATIVE_MULTIPLIER (1.2)
        - 계산: int(duration_minutes * rate * CONSERVATIVE_MULTIPLIER)

        Note: 현재는 모든 세션을 Sonnet rate로 추정 (Opus 세션 구분이 불확실하므로 보수적).
              향후 team_id에서 팀장/팀원 구분 가능 시 rate 분기.
        """
        if duration_seconds <= 0:
            return 0
        duration_minutes = duration_seconds / 60.0
        # team_id에 "팀장"이 포함되면 Opus rate, 그 외 Sonnet rate
        if "팀장" in team_id:
            rate = TOKENS_PER_MINUTE_OPUS
        else:
            rate = TOKENS_PER_MINUTE_SONNET
        return int(duration_minutes * rate * CONSERVATIVE_MULTIPLIER)

    def get_daily_usage_summary(self) -> dict:
        """당일 토큰 사용량 + 잔여 예산 반환.

        Returns:
            {
                "today": int,           # 오늘 사용량
                "limit": int,           # DAILY_HARD_LIMIT
                "remaining": int,       # limit - today
                "percentage": float,    # (today / limit) * 100, 소수점 1자리
            }
        """
        today = self.get_daily_usage()
        limit = self.DAILY_HARD_LIMIT
        remaining = limit - today
        percentage = round((today / limit) * 100, 1)
        return {
            "today": today,
            "limit": limit,
            "remaining": remaining,
            "percentage": percentage,
        }

    def check_warning_threshold(self, threshold: float = 0.8) -> bool:
        """사용량이 DAILY_HARD_LIMIT의 threshold 비율 이상이면 True.

        Args:
            threshold: 0.0 ~ 1.0 사이 비율 (기본 0.8 = 80%)

        Returns:
            daily_total >= threshold * DAILY_HARD_LIMIT이면 True
        """
        daily_total = self.get_daily_usage()
        return daily_total >= threshold * self.DAILY_HARD_LIMIT
