"""
test_task_timer_qc.py - task-timer qc_result 필드 + 히스토리 API 테스트

테스트 항목:
1. test_end_task_with_qc_result_pass: end_task에 qc_result="PASS" 전달 → task_data에 기록
2. test_end_task_without_qc_result: end_task에 qc_result 미전달 → task_data에 qc_result=None
3. test_end_task_with_qc_result_fail: end_task에 qc_result="FAIL" 전달 → task_data에 기록
4. test_end_task_with_qc_result_warn: end_task에 qc_result="WARN" 전달 → task_data에 기록
5. test_cli_end_with_qc_result: CLI end --qc-result PASS → 정상 동작
6. test_get_history_stats_completed_only: completed 작업만 집계
7. test_get_history_stats_team_classification: 팀별 분류 정확
8. test_get_history_stats_qc_pass_rate: QC 통과율 계산 정확
9. test_get_history_stats_empty: 데이터 없을 때 빈 dict 반환
10. test_get_history_stats_avg_duration: 평균 소요시간 계산 정확
"""

import importlib.util
import json
import os
import subprocess
import sys
import tempfile
from datetime import datetime
from pathlib import Path
from unittest.mock import MagicMock, patch

import pytest

# task-timer.py 경로
_WORKSPACE = Path(os.environ.get("WORKSPACE_ROOT", "/home/jay/workspace"))
_TIMER_PATH = _WORKSPACE / "memory/task-timer.py"

# utils.logger mock (환경에 따라 import 실패 방어)
if "utils.logger" not in sys.modules:
    _mock_logger = MagicMock()
    _mock_logger.get_logger.return_value = MagicMock()
    sys.modules["utils"] = MagicMock()
    sys.modules["utils.logger"] = _mock_logger

# task-timer 모듈 동적 로드
spec = importlib.util.spec_from_file_location("task_timer", str(_TIMER_PATH))
assert spec is not None and spec.loader is not None
task_timer_mod = importlib.util.module_from_spec(spec)
spec.loader.exec_module(task_timer_mod)  # type: ignore[union-attr]

TaskTimer = task_timer_mod.TaskTimer

# dashboard server.py 경로
_SERVER_PATH = _WORKSPACE / "dashboard/server.py"
spec2 = importlib.util.spec_from_file_location("dashboard_server", str(_SERVER_PATH))
assert spec2 is not None and spec2.loader is not None
dashboard_mod = importlib.util.module_from_spec(spec2)
spec2.loader.exec_module(dashboard_mod)  # type: ignore[union-attr]

DataLoader = dashboard_mod.DataLoader


# ---------------------------------------------------------------------------
# Fixtures
# ---------------------------------------------------------------------------


def make_timer(tmp_path: Path) -> TaskTimer:
    """임시 디렉토리 기반 TaskTimer 인스턴스 생성"""
    (tmp_path / "memory").mkdir(parents=True, exist_ok=True)
    (tmp_path / "memory" / "events").mkdir(parents=True, exist_ok=True)
    (tmp_path / "memory" / "daily").mkdir(parents=True, exist_ok=True)
    return TaskTimer(workspace_path=str(tmp_path))


def make_data_loader(tmp_path: Path) -> DataLoader:
    """임시 디렉토리 기반 DataLoader 인스턴스 생성"""
    (tmp_path / "memory").mkdir(parents=True, exist_ok=True)
    return DataLoader(tmp_path)


# ---------------------------------------------------------------------------
# TaskTimer.end_task qc_result 테스트
# ---------------------------------------------------------------------------


class TestEndTaskQcResult:
    def test_end_task_with_qc_result_pass(self, tmp_path):
        """end_task에 qc_result='PASS' 전달 → task_data['qc_result'] == 'PASS'"""
        timer = make_timer(tmp_path)
        timer.start_task("task-792", "dev1-team", "QC 테스트")
        result = timer.end_task("task-792", qc_result="PASS")

        assert result["status"] == "completed"
        task_data = timer.timers["tasks"]["task-792"]
        assert task_data["qc_result"] == "PASS"

    def test_end_task_without_qc_result(self, tmp_path):
        """end_task에 qc_result 미전달 → task_data['qc_result'] == None"""
        timer = make_timer(tmp_path)
        timer.start_task("task-793", "dev1-team", "QC 없는 테스트")
        timer.end_task("task-793")

        task_data = timer.timers["tasks"]["task-793"]
        assert task_data["qc_result"] is None

    def test_end_task_with_qc_result_fail(self, tmp_path):
        """end_task에 qc_result='FAIL' 전달 → task_data['qc_result'] == 'FAIL'"""
        timer = make_timer(tmp_path)
        timer.start_task("task-794", "dev2-team", "FAIL 테스트")
        timer.end_task("task-794", qc_result="FAIL")

        task_data = timer.timers["tasks"]["task-794"]
        assert task_data["qc_result"] == "FAIL"

    def test_end_task_with_qc_result_warn(self, tmp_path):
        """end_task에 qc_result='WARN' 전달 → task_data['qc_result'] == 'WARN'"""
        timer = make_timer(tmp_path)
        timer.start_task("task-795", "dev3-team", "WARN 테스트")
        timer.end_task("task-795", qc_result="WARN")

        task_data = timer.timers["tasks"]["task-795"]
        assert task_data["qc_result"] == "WARN"

    def test_end_task_empty_string_qc_result(self, tmp_path):
        """end_task에 qc_result='' (빈 문자열) 전달 → task_data['qc_result'] == None"""
        timer = make_timer(tmp_path)
        timer.start_task("task-796", "dev1-team", "빈 문자열 테스트")
        timer.end_task("task-796", qc_result="")

        task_data = timer.timers["tasks"]["task-796"]
        assert task_data["qc_result"] is None

    def test_end_task_qc_result_persisted_in_json(self, tmp_path):
        """end_task 후 task-timers.json에 qc_result 저장 여부 확인"""
        timer = make_timer(tmp_path)
        timer.start_task("task-797", "dev1-team", "JSON 저장 테스트")
        timer.end_task("task-797", qc_result="PASS")

        # JSON 파일에서 직접 읽어서 확인
        timer_file = tmp_path / "memory" / "task-timers.json"
        assert timer_file.exists()
        with open(timer_file, encoding="utf-8") as f:
            data = json.load(f)
        assert data["tasks"]["task-797"]["qc_result"] == "PASS"

    def test_end_task_idempotent_already_completed(self, tmp_path):
        """이미 completed 태스크 재호출 → already_completed 반환, qc_result 덮어쓰기 없음"""
        timer = make_timer(tmp_path)
        timer.start_task("task-798", "dev1-team", "멱등성 테스트")
        timer.end_task("task-798", qc_result="PASS")

        # 두 번째 호출
        result = timer.end_task("task-798", qc_result="FAIL")
        assert result.get("already_completed") is True
        # 기존 qc_result(PASS)가 유지되어야 함
        assert timer.timers["tasks"]["task-798"]["qc_result"] == "PASS"


# ---------------------------------------------------------------------------
# CLI --qc-result 옵션 테스트
# ---------------------------------------------------------------------------


class TestCliQcResult:
    def test_cli_end_with_qc_result_pass(self, tmp_path):
        """CLI: python3 task-timer.py end task-792.1 --qc-result PASS → 정상 실행"""
        # 먼저 task를 start
        result_start = subprocess.run(
            [
                sys.executable,
                str(_TIMER_PATH),
                "start",
                "task-792.1",
                "--team",
                "dev1-team",
            ],
            capture_output=True,
            text=True,
            env={**__import__("os").environ, "WORKSPACE_ROOT": str(tmp_path)},
        )
        assert result_start.returncode == 0, f"start 실패: {result_start.stderr}"

        # end --qc-result PASS
        result_end = subprocess.run(
            [
                sys.executable,
                str(_TIMER_PATH),
                "end",
                "task-792.1",
                "--qc-result",
                "PASS",
            ],
            capture_output=True,
            text=True,
            env={**__import__("os").environ, "WORKSPACE_ROOT": str(tmp_path)},
        )
        assert result_end.returncode == 0, f"end 실패: {result_end.stderr}"
        out = json.loads(result_end.stdout)
        assert out["status"] == "completed"

        # JSON 파일에서 qc_result 확인
        timer_file = tmp_path / "memory" / "task-timers.json"
        with open(timer_file, encoding="utf-8") as f:
            data = json.load(f)
        assert data["tasks"]["task-792.1"]["qc_result"] == "PASS"

    def test_cli_end_without_qc_result(self, tmp_path):
        """CLI: python3 task-timer.py end task-792.2 (--qc-result 없이) → qc_result=None"""
        # start
        subprocess.run(
            [sys.executable, str(_TIMER_PATH), "start", "task-792.2", "--team", "dev1-team"],
            capture_output=True,
            text=True,
            env={**__import__("os").environ, "WORKSPACE_ROOT": str(tmp_path)},
        )

        # end (옵션 없이)
        result_end = subprocess.run(
            [sys.executable, str(_TIMER_PATH), "end", "task-792.2"],
            capture_output=True,
            text=True,
            env={**__import__("os").environ, "WORKSPACE_ROOT": str(tmp_path)},
        )
        assert result_end.returncode == 0

        timer_file = tmp_path / "memory" / "task-timers.json"
        with open(timer_file, encoding="utf-8") as f:
            data = json.load(f)
        assert data["tasks"]["task-792.2"]["qc_result"] is None


# ---------------------------------------------------------------------------
# DataLoader.get_history_stats 테스트
# ---------------------------------------------------------------------------


def _build_task_timers(tasks: dict) -> dict:
    """task-timers.json 구조 생성 헬퍼"""
    return {"tasks": tasks}


def _write_task_timers(path: Path, tasks: dict) -> None:
    """task-timers.json 파일 쓰기"""
    path.mkdir(parents=True, exist_ok=True)
    with open(path / "task-timers.json", "w", encoding="utf-8") as f:
        json.dump(_build_task_timers(tasks), f, ensure_ascii=False)


class TestGetHistoryStats:
    def test_completed_only(self, tmp_path):
        """get_history_stats: completed 작업만 집계, running/stale 제외"""
        tasks = {
            "task-1": {
                "team_id": "dev1-team",
                "status": "completed",
                "qc_result": "PASS",
                "duration_seconds": 120.0,
            },
            "task-2": {
                "team_id": "dev1-team",
                "status": "running",
                "qc_result": None,
                "duration_seconds": None,
            },
            "task-3": {
                "team_id": "dev1-team",
                "status": "stale",
                "qc_result": None,
                "duration_seconds": None,
            },
        }
        _write_task_timers(tmp_path / "memory", tasks)

        loader = make_data_loader(tmp_path)
        loader.load_tasks()
        stats = loader.get_history_stats()

        # dev1-team에 completed 1개만 집계
        assert "dev1-team" in stats
        assert stats["dev1-team"]["total_tasks"] == 1
        assert stats["dev1-team"]["qc_pass"] == 1

    def test_team_classification(self, tmp_path):
        """get_history_stats: 팀별 분류 정확"""
        tasks = {
            "task-10": {
                "team_id": "dev1-team",
                "status": "completed",
                "qc_result": "PASS",
                "duration_seconds": 60.0,
            },
            "task-11": {
                "team_id": "dev2-team",
                "status": "completed",
                "qc_result": "FAIL",
                "duration_seconds": 90.0,
            },
            "task-12": {
                "team_id": "dev2-team",
                "status": "completed",
                "qc_result": "WARN",
                "duration_seconds": 30.0,
            },
        }
        _write_task_timers(tmp_path / "memory", tasks)

        loader = make_data_loader(tmp_path)
        loader.load_tasks()
        stats = loader.get_history_stats()

        assert "dev1-team" in stats
        assert "dev2-team" in stats
        assert stats["dev1-team"]["total_tasks"] == 1
        assert stats["dev2-team"]["total_tasks"] == 2
        assert stats["dev2-team"]["qc_fail"] == 1
        assert stats["dev2-team"]["qc_warn"] == 1

    def test_qc_pass_rate(self, tmp_path):
        """get_history_stats: QC 통과율 계산 정확"""
        tasks = {
            "task-20": {
                "team_id": "dev1-team",
                "status": "completed",
                "qc_result": "PASS",
                "duration_seconds": 100.0,
            },
            "task-21": {
                "team_id": "dev1-team",
                "status": "completed",
                "qc_result": "PASS",
                "duration_seconds": 200.0,
            },
            "task-22": {
                "team_id": "dev1-team",
                "status": "completed",
                "qc_result": "FAIL",
                "duration_seconds": 150.0,
            },
            "task-23": {
                "team_id": "dev1-team",
                "status": "completed",
                "qc_result": None,
                "duration_seconds": 50.0,
            },
        }
        _write_task_timers(tmp_path / "memory", tasks)

        loader = make_data_loader(tmp_path)
        loader.load_tasks()
        stats = loader.get_history_stats()

        s = stats["dev1-team"]
        assert s["total_tasks"] == 4
        assert s["qc_pass"] == 2
        assert s["qc_fail"] == 1
        assert s["qc_none"] == 1
        # 통과율: 2/4 * 100 = 50.0
        assert s["qc_pass_rate"] == 50.0

    def test_empty_data(self, tmp_path):
        """get_history_stats: 데이터 없을 때 빈 dict 반환"""
        _write_task_timers(tmp_path / "memory", {})

        loader = make_data_loader(tmp_path)
        loader.load_tasks()
        stats = loader.get_history_stats()

        assert stats == {}

    def test_avg_duration(self, tmp_path):
        """get_history_stats: 평균 소요시간 계산 정확"""
        tasks = {
            "task-30": {
                "team_id": "dev3-team",
                "status": "completed",
                "qc_result": "PASS",
                "duration_seconds": 100.0,
            },
            "task-31": {
                "team_id": "dev3-team",
                "status": "completed",
                "qc_result": "PASS",
                "duration_seconds": 300.0,
            },
        }
        _write_task_timers(tmp_path / "memory", tasks)

        loader = make_data_loader(tmp_path)
        loader.load_tasks()
        stats = loader.get_history_stats()

        s = stats["dev3-team"]
        # 평균: (100 + 300) / 2 = 200.0
        assert s["avg_duration_seconds"] == 200.0

    def test_avg_duration_human_format(self, tmp_path):
        """get_history_stats: avg_duration_human 포맷 확인"""
        tasks = {
            "task-40": {
                "team_id": "dev1-team",
                "status": "completed",
                "qc_result": "PASS",
                "duration_seconds": 90.0,  # 1분 30초
            },
        }
        _write_task_timers(tmp_path / "memory", tasks)

        loader = make_data_loader(tmp_path)
        loader.load_tasks()
        stats = loader.get_history_stats()

        s = stats["dev1-team"]
        assert s["avg_duration_human"] == "1분 30초"

    def test_no_duration_tasks(self, tmp_path):
        """get_history_stats: duration_seconds=None 태스크는 평균 계산에서 제외"""
        tasks = {
            "task-50": {
                "team_id": "dev1-team",
                "status": "completed",
                "qc_result": "PASS",
                "duration_seconds": None,
            },
            "task-51": {
                "team_id": "dev1-team",
                "status": "completed",
                "qc_result": "PASS",
                "duration_seconds": 200.0,
            },
        }
        _write_task_timers(tmp_path / "memory", tasks)

        loader = make_data_loader(tmp_path)
        loader.load_tasks()
        stats = loader.get_history_stats()

        s = stats["dev1-team"]
        # total_duration = 200, 평균은 total/total_tasks = 200/2 = 100
        assert s["total_tasks"] == 2
        assert s["avg_duration_seconds"] == 100.0

    def test_qc_none_count(self, tmp_path):
        """get_history_stats: qc_result=None 태스크는 qc_none으로 집계"""
        tasks = {
            "task-60": {
                "team_id": "dev1-team",
                "status": "completed",
                "qc_result": None,
                "duration_seconds": 60.0,
            },
        }
        _write_task_timers(tmp_path / "memory", tasks)

        loader = make_data_loader(tmp_path)
        loader.load_tasks()
        stats = loader.get_history_stats()

        s = stats["dev1-team"]
        assert s["qc_none"] == 1
        assert s["qc_pass"] == 0
        assert s["qc_fail"] == 0
        assert s["qc_warn"] == 0

    def test_unknown_team_id(self, tmp_path):
        """get_history_stats: team_id 없는 태스크는 'unknown' 팀으로 집계"""
        tasks = {
            "task-70": {
                "status": "completed",
                "qc_result": "PASS",
                "duration_seconds": 60.0,
                # team_id 없음
            },
        }
        _write_task_timers(tmp_path / "memory", tasks)

        loader = make_data_loader(tmp_path)
        loader.load_tasks()
        stats = loader.get_history_stats()

        assert "unknown" in stats
        assert stats["unknown"]["total_tasks"] == 1
