"""세션 인사이트 엔진.

task-timers.json 기반으로 작업 통계와 비용을 추정한다.
ASCII 가로 막대 차트, 기간별 필터, 팀/상태별 집계를 지원한다.

데이터 형식 (task-timers.json):
    {
      "tasks": {
        "task-1.0": {
          "task_id": "task-1.0",
          "team_id": "dev1-team",
          "description": "설명",
          "start_time": "2026-03-01T10:00:00",
          "end_time": "2026-03-01T10:30:00",
          "duration_seconds": 1800.0,
          "status": "completed",
          "duration_human": "30분"
        }
      }
    }

Usage:
    from utils.insights_engine import InsightsEngine
    engine = InsightsEngine("/home/jay/workspace/memory/task-timers.json")
    summary = engine.get_summary(days=30)
    chart = engine.render_ascii_chart(summary.tasks_by_team, title="팀별 태스크")
"""

from __future__ import annotations

import json
from dataclasses import dataclass, field
from datetime import datetime, timedelta
from pathlib import Path
from typing import Any

# 비용 추정 상수 (usage_pricing.py import 없이 단순 추정)
# 태스크당 평균 토큰: 50,000 (입력 40,000 + 출력 10,000)
# claude-sonnet-4-6 기준: $3.00/1M input, $15.00/1M output
_AVG_INPUT_TOKENS_PER_TASK = 40_000
_AVG_OUTPUT_TOKENS_PER_TASK = 10_000
_INPUT_PRICE_PER_1M = 3.00  # USD
_OUTPUT_PRICE_PER_1M = 15.00  # USD
_COST_PER_TASK = (
    _AVG_INPUT_TOKENS_PER_TASK / 1_000_000 * _INPUT_PRICE_PER_1M
    + _AVG_OUTPUT_TOKENS_PER_TASK / 1_000_000 * _OUTPUT_PRICE_PER_1M
)  # ≈ $0.27 per task

_BAR_CHAR = "█"
_BAR_MAX_WIDTH = 30


@dataclass
class InsightsSummary:
    """작업 인사이트 요약."""

    total_tasks: int
    completed_tasks: int
    avg_duration_minutes: float
    total_estimated_cost: float
    tasks_by_team: dict[str, int] = field(default_factory=dict)
    tasks_by_status: dict[str, int] = field(default_factory=dict)


def _parse_datetime(dt_str: str | None) -> datetime | None:
    """ISO 형식 datetime 문자열을 파싱한다."""
    if not dt_str:
        return None
    try:
        # Python 3.7+: fromisoformat은 'T' 구분자 지원
        return datetime.fromisoformat(dt_str)
    except (ValueError, TypeError):
        return None


class InsightsEngine:
    """task-timers.json 기반 작업 인사이트 엔진.

    Args:
        data_path: task-timers.json 파일 경로 (str 또는 Path).
    """

    def __init__(self, data_path: str | Path) -> None:
        self._path = Path(data_path)

    def _load_tasks(self) -> list[dict[str, Any]]:
        """JSON에서 태스크 목록을 로드한다. 실패 시 빈 리스트."""
        if not self._path.exists():
            return []
        try:
            with open(self._path, encoding="utf-8") as f:
                data = json.load(f)
            tasks_dict = data.get("tasks", {})
            if isinstance(tasks_dict, dict):
                return list(tasks_dict.values())
            return []
        except (OSError, json.JSONDecodeError, AttributeError):
            return []

    def _filter_by_days(self, tasks: list[dict[str, Any]], days: int) -> list[dict[str, Any]]:
        """기간 내 태스크만 필터링한다."""
        cutoff = datetime.now() - timedelta(days=days)
        result: list[dict[str, Any]] = []
        for task in tasks:
            start = _parse_datetime(task.get("start_time"))
            if start is None:
                # start_time 없는 태스크는 포함 (데이터 누락 허용)
                result.append(task)
                continue
            if start >= cutoff:
                result.append(task)
        return result

    def get_summary(self, days: int = 30) -> InsightsSummary:
        """기간 내 작업 통계 요약을 반환한다.

        Args:
            days: 조회 기간 (일). 기본 30일.

        Returns:
            InsightsSummary 인스턴스.
        """
        all_tasks = self._load_tasks()
        tasks = self._filter_by_days(all_tasks, days)

        if not tasks:
            return InsightsSummary(
                total_tasks=0,
                completed_tasks=0,
                avg_duration_minutes=0.0,
                total_estimated_cost=0.0,
                tasks_by_team={},
                tasks_by_status={},
            )

        total_tasks = len(tasks)
        completed_tasks = sum(1 for t in tasks if t.get("status") == "completed")

        # 평균 소요 시간 (분)
        durations = [t["duration_seconds"] / 60.0 for t in tasks if isinstance(t.get("duration_seconds"), (int, float))]
        avg_duration = sum(durations) / len(durations) if durations else 0.0

        # 비용 추정: completed 태스크 기준
        total_estimated_cost = completed_tasks * _COST_PER_TASK

        # 팀별 집계
        tasks_by_team: dict[str, int] = {}
        for t in tasks:
            team = t.get("team_id") or "unknown"
            tasks_by_team[team] = tasks_by_team.get(team, 0) + 1

        # 상태별 집계
        tasks_by_status: dict[str, int] = {}
        for t in tasks:
            status = t.get("status") or "unknown"
            tasks_by_status[status] = tasks_by_status.get(status, 0) + 1

        return InsightsSummary(
            total_tasks=total_tasks,
            completed_tasks=completed_tasks,
            avg_duration_minutes=round(avg_duration, 2),
            total_estimated_cost=round(total_estimated_cost, 6),
            tasks_by_team=tasks_by_team,
            tasks_by_status=tasks_by_status,
        )

    def render_ascii_chart(self, data: dict[str, int], title: str = "") -> str:
        """가로 막대 ASCII 차트를 반환한다.

        Args:
            data: {레이블: 값} 딕셔너리.
            title: 차트 제목 (선택).

        Returns:
            ASCII 차트 문자열.
        """
        if not data:
            return ""

        peak = max(data.values()) if data else 1
        if peak <= 0:
            peak = 1

        lines: list[str] = []

        if title:
            lines.append(f"  {title}")
            lines.append("  " + "-" * (len(title) + 2))

        # 레이블 최대 길이 계산 (정렬용)
        max_label = max(len(k) for k in data) if data else 10

        for label, value in data.items():
            bar_width = max(1, round(value / peak * _BAR_MAX_WIDTH)) if value > 0 else 0
            bar = _BAR_CHAR * bar_width
            lines.append(f"  {label:<{max_label}}  {bar:<{_BAR_MAX_WIDTH}}  {value}")

        return "\n".join(lines)
