"""test_kickoff.py - kickoff.py CLI 테스트"""

import json
import subprocess
import sys
from pathlib import Path

import pytest

KICKOFF_PY = "/home/jay/workspace/kickoff.py"


def run_kickoff(args: list[str], base_dir: Path) -> subprocess.CompletedProcess:
    """kickoff.py를 subprocess로 실행하고 결과를 반환한다."""
    env = {"KICKOFF_BASE_DIR": str(base_dir), "PATH": "/usr/bin:/bin:/usr/local/bin"}
    return subprocess.run(
        [sys.executable, KICKOFF_PY] + args,
        capture_output=True,
        text=True,
        env=env,
    )


def state_path(base_dir: Path, project: str) -> Path:
    """kickoff-state.json 경로를 반환한다."""
    return base_dir / "memory" / "kickoff" / project / "kickoff-state.json"


# ---------------------------------------------------------------------------
# init 명령 테스트
# ---------------------------------------------------------------------------


class TestInit:
    def test_init_creates_state_file(self, tmp_path):
        """정상 초기화 시 kickoff-state.json이 생성된다."""
        result = run_kickoff(["init", "--project", "myproj", "--task", "T-001"], tmp_path)

        assert result.returncode == 0, f"stderr: {result.stderr}"
        assert state_path(tmp_path, "myproj").exists()

    def test_init_json_schema(self, tmp_path):
        """생성된 JSON에 필수 키(project, task_id, current_phase, phases, approval_points)가 존재한다."""
        run_kickoff(["init", "--project", "myproj", "--task", "T-001"], tmp_path)

        with state_path(tmp_path, "myproj").open("r", encoding="utf-8") as f:
            state = json.load(f)

        assert "project" in state
        assert "task_id" in state
        assert "current_phase" in state
        assert "phases" in state
        assert "approval_points" in state

    def test_init_project_and_task_id_values(self, tmp_path):
        """project와 task_id 값이 인수로 전달한 값과 일치한다."""
        run_kickoff(["init", "--project", "alpha", "--task", "ROOT-42"], tmp_path)

        with state_path(tmp_path, "alpha").open("r", encoding="utf-8") as f:
            state = json.load(f)

        assert state["project"] == "alpha"
        assert state["task_id"] == "ROOT-42"

    def test_init_all_phases_pending(self, tmp_path):
        """초기화 직후 모든 Phase의 status가 "pending"이다."""
        run_kickoff(["init", "--project", "myproj", "--task", "T-001"], tmp_path)

        with state_path(tmp_path, "myproj").open("r", encoding="utf-8") as f:
            state = json.load(f)

        phases = state["phases"]
        assert set(phases.keys()) == {"0", "1", "2", "3"}
        for key, phase in phases.items():
            assert phase["status"] == "pending", f"Phase {key} status is not pending"

    def test_init_current_phase_is_zero(self, tmp_path):
        """초기화 직후 current_phase가 0이다."""
        run_kickoff(["init", "--project", "myproj", "--task", "T-001"], tmp_path)

        with state_path(tmp_path, "myproj").open("r", encoding="utf-8") as f:
            state = json.load(f)

        assert state["current_phase"] == 0

    def test_init_approval_points_schema(self, tmp_path):
        """approval_points에 phase0_review, phase2_review, phase3_approval 키가 존재한다."""
        run_kickoff(["init", "--project", "myproj", "--task", "T-001"], tmp_path)

        with state_path(tmp_path, "myproj").open("r", encoding="utf-8") as f:
            state = json.load(f)

        ap = state["approval_points"]
        assert "phase0_review" in ap
        assert "phase2_review" in ap
        assert "phase3_approval" in ap

    def test_init_duplicate_raises_error(self, tmp_path):
        """이미 kickoff-state.json이 존재할 때 두 번 init 하면 에러가 발생한다."""
        run_kickoff(["init", "--project", "myproj", "--task", "T-001"], tmp_path)
        result = run_kickoff(["init", "--project", "myproj", "--task", "T-002"], tmp_path)

        assert result.returncode != 0
        assert "already exists" in result.stderr.lower() or "error" in result.stderr.lower()


# ---------------------------------------------------------------------------
# status 명령 테스트
# ---------------------------------------------------------------------------


class TestStatus:
    def test_status_output_contains_project_name(self, tmp_path):
        """status 출력에 프로젝트명이 포함된다."""
        run_kickoff(["init", "--project", "betaproj", "--task", "T-010"], tmp_path)
        result = run_kickoff(["status", "--project", "betaproj"], tmp_path)

        assert result.returncode == 0, f"stderr: {result.stderr}"
        assert "betaproj" in result.stdout

    def test_status_output_contains_phase_info(self, tmp_path):
        """status 출력에 Phase 정보가 포함된다."""
        run_kickoff(["init", "--project", "betaproj", "--task", "T-010"], tmp_path)
        result = run_kickoff(["status", "--project", "betaproj"], tmp_path)

        assert result.returncode == 0
        # Phase 섹션 또는 개별 Phase 레이블이 출력에 포함되어야 함
        assert "Phase" in result.stdout or "phase" in result.stdout.lower()

    def test_status_missing_project_returns_error(self, tmp_path):
        """존재하지 않는 프로젝트를 status로 조회하면 에러가 발생한다."""
        result = run_kickoff(["status", "--project", "nonexistent"], tmp_path)

        assert result.returncode != 0
        assert result.stderr.strip() != ""


# ---------------------------------------------------------------------------
# phase-done 명령 테스트
# ---------------------------------------------------------------------------


class TestPhaseDone:
    def test_phase0_done_sets_completed(self, tmp_path):
        """Phase 0 완료 후 phases["0"]["status"]가 "completed"이다."""
        run_kickoff(["init", "--project", "proj", "--task", "T-100"], tmp_path)
        result = run_kickoff(
            ["phase-done", "--project", "proj", "--phase", "0", "--output", "/tmp/out0.md"],
            tmp_path,
        )

        assert result.returncode == 0, f"stderr: {result.stderr}"

        with state_path(tmp_path, "proj").open("r", encoding="utf-8") as f:
            state = json.load(f)

        assert state["phases"]["0"]["status"] == "completed"

    def test_phase0_done_sets_phase1_in_progress(self, tmp_path):
        """Phase 0 완료 후 phases["1"]["status"]가 "in_progress"이다."""
        run_kickoff(["init", "--project", "proj", "--task", "T-100"], tmp_path)
        run_kickoff(
            ["phase-done", "--project", "proj", "--phase", "0", "--output", "/tmp/out0.md"],
            tmp_path,
        )

        with state_path(tmp_path, "proj").open("r", encoding="utf-8") as f:
            state = json.load(f)

        assert state["phases"]["1"]["status"] == "in_progress"

    def test_phase0_done_updates_current_phase(self, tmp_path):
        """Phase 0 완료 후 current_phase가 1로 업데이트된다."""
        run_kickoff(["init", "--project", "proj", "--task", "T-100"], tmp_path)
        run_kickoff(
            ["phase-done", "--project", "proj", "--phase", "0", "--output", "/tmp/out0.md"],
            tmp_path,
        )

        with state_path(tmp_path, "proj").open("r", encoding="utf-8") as f:
            state = json.load(f)

        assert state["current_phase"] == 1

    def test_phase0_done_records_output_path(self, tmp_path):
        """Phase 0 완료 후 output 경로가 JSON에 기록된다."""
        run_kickoff(["init", "--project", "proj", "--task", "T-100"], tmp_path)
        run_kickoff(
            ["phase-done", "--project", "proj", "--phase", "0", "--output", "/tmp/out0.md"],
            tmp_path,
        )

        with state_path(tmp_path, "proj").open("r", encoding="utf-8") as f:
            state = json.load(f)

        assert state["phases"]["0"]["output"] == "/tmp/out0.md"

    def test_phase0_done_records_completed_at(self, tmp_path):
        """Phase 0 완료 후 completed_at 타임스탬프가 기록된다."""
        run_kickoff(["init", "--project", "proj", "--task", "T-100"], tmp_path)
        run_kickoff(
            ["phase-done", "--project", "proj", "--phase", "0", "--output", "/tmp/out0.md"],
            tmp_path,
        )

        with state_path(tmp_path, "proj").open("r", encoding="utf-8") as f:
            state = json.load(f)

        assert "completed_at" in state["phases"]["0"]
        assert state["phases"]["0"]["completed_at"] != ""

    def test_phase1_before_phase0_raises_error(self, tmp_path):
        """Phase 0 완료 전에 Phase 1 phase-done을 실행하면 에러가 발생한다."""
        run_kickoff(["init", "--project", "proj", "--task", "T-100"], tmp_path)
        result = run_kickoff(
            ["phase-done", "--project", "proj", "--phase", "1", "--output", "/tmp/out1.md"],
            tmp_path,
        )

        assert result.returncode != 0
        assert result.stderr.strip() != ""

    def test_invalid_phase_number_raises_error(self, tmp_path):
        """유효하지 않은 phase 번호(5)를 전달하면 에러가 발생한다."""
        run_kickoff(["init", "--project", "proj", "--task", "T-100"], tmp_path)
        result = run_kickoff(
            ["phase-done", "--project", "proj", "--phase", "5", "--output", "/tmp/out5.md"],
            tmp_path,
        )

        assert result.returncode != 0
        assert result.stderr.strip() != ""

    def test_full_flow_all_phases_completed(self, tmp_path):
        """Phase 0 -> 1 -> 2 -> 3 순차 완료 후 모든 Phase가 completed 상태이다."""
        run_kickoff(["init", "--project", "fullflow", "--task", "T-999"], tmp_path)

        for phase in range(4):
            result = run_kickoff(
                [
                    "phase-done",
                    "--project",
                    "fullflow",
                    "--phase",
                    str(phase),
                    "--output",
                    f"/tmp/out{phase}.md",
                ],
                tmp_path,
            )
            assert result.returncode == 0, (
                f"Phase {phase} failed - stdout: {result.stdout} stderr: {result.stderr}"
            )

        with state_path(tmp_path, "fullflow").open("r", encoding="utf-8") as f:
            state = json.load(f)

        for phase_key in ["0", "1", "2", "3"]:
            assert state["phases"][phase_key]["status"] == "completed", (
                f"Phase {phase_key} is not completed"
            )

    def test_full_flow_current_phase_after_last(self, tmp_path):
        """모든 Phase 완료 후 current_phase가 마지막 Phase 번호(3)이다."""
        run_kickoff(["init", "--project", "fullflow2", "--task", "T-888"], tmp_path)

        for phase in range(4):
            run_kickoff(
                [
                    "phase-done",
                    "--project",
                    "fullflow2",
                    "--phase",
                    str(phase),
                    "--output",
                    f"/tmp/out{phase}.md",
                ],
                tmp_path,
            )

        with state_path(tmp_path, "fullflow2").open("r", encoding="utf-8") as f:
            state = json.load(f)

        assert state["current_phase"] == 3

    def test_approval_point_updated_after_phase0(self, tmp_path):
        """Phase 0 완료 후 phase0_review approval point가 pending_review 상태이다."""
        run_kickoff(["init", "--project", "proj", "--task", "T-100"], tmp_path)
        run_kickoff(
            ["phase-done", "--project", "proj", "--phase", "0", "--output", "/tmp/out0.md"],
            tmp_path,
        )

        with state_path(tmp_path, "proj").open("r", encoding="utf-8") as f:
            state = json.load(f)

        assert state["approval_points"]["phase0_review"]["status"] == "pending_review"

    def test_phase_done_missing_project_raises_error(self, tmp_path):
        """존재하지 않는 프로젝트에 phase-done을 실행하면 에러가 발생한다."""
        result = run_kickoff(
            ["phase-done", "--project", "ghost", "--phase", "0", "--output", "/tmp/out.md"],
            tmp_path,
        )

        assert result.returncode != 0
        assert result.stderr.strip() != ""
