"""Tests for launcher.context — check-context, register-plan, send-clear."""

import json
import time
from pathlib import Path
from unittest.mock import patch

import pytest

from launcher.context import check_context, register_plan, send_clear


class TestCheckContext:
    """Tests for the check-context command."""

    def test_returns_unknown_when_no_cache(self, tmp_path: Path, capsys: pytest.CaptureFixture[str]) -> None:
        with patch("launcher.context._session_dir", return_value=tmp_path):
            check_context(as_json=True)
        output = json.loads(capsys.readouterr().out)
        assert output["status"] == "UNKNOWN"
        assert output["percentage"] is None

    def test_returns_ok_when_low_context(self, tmp_path: Path, capsys: pytest.CaptureFixture[str]) -> None:
        cache = tmp_path / "context-pct.json"
        cache.write_text(json.dumps({"pct": 42.0, "ts": time.time(), "session_id": "abc"}))

        with patch("launcher.context._session_dir", return_value=tmp_path):
            check_context(as_json=True)
        output = json.loads(capsys.readouterr().out)
        assert output["status"] == "OK"
        assert output["percentage"] == 42.0

    def test_returns_warning_at_80_pct(self, tmp_path: Path, capsys: pytest.CaptureFixture[str]) -> None:
        cache = tmp_path / "context-pct.json"
        cache.write_text(json.dumps({"pct": 85.0, "ts": time.time(), "session_id": "abc"}))

        with patch("launcher.context._session_dir", return_value=tmp_path):
            check_context(as_json=True)
        output = json.loads(capsys.readouterr().out)
        assert output["status"] == "WARNING"

    def test_returns_clear_needed_at_90_pct(self, tmp_path: Path, capsys: pytest.CaptureFixture[str]) -> None:
        cache = tmp_path / "context-pct.json"
        cache.write_text(json.dumps({"pct": 92.0, "ts": time.time(), "session_id": "abc"}))

        with patch("launcher.context._session_dir", return_value=tmp_path):
            check_context(as_json=True)
        output = json.loads(capsys.readouterr().out)
        assert output["status"] == "CLEAR_NEEDED"

    def test_ignores_stale_cache(self, tmp_path: Path, capsys: pytest.CaptureFixture[str]) -> None:
        cache = tmp_path / "context-pct.json"
        cache.write_text(json.dumps({"pct": 95.0, "ts": time.time() - 200, "session_id": "abc"}))

        with patch("launcher.context._session_dir", return_value=tmp_path):
            check_context(as_json=True)
        output = json.loads(capsys.readouterr().out)
        assert output["status"] == "UNKNOWN"

    def test_human_output_format(self, tmp_path: Path, capsys: pytest.CaptureFixture[str]) -> None:
        cache = tmp_path / "context-pct.json"
        cache.write_text(json.dumps({"pct": 47.0, "ts": time.time(), "session_id": "abc"}))

        with patch("launcher.context._session_dir", return_value=tmp_path):
            check_context(as_json=False)
        output = capsys.readouterr().out
        assert "47%" in output
        assert "OK" in output


class TestRegisterPlan:
    """Tests for the register-plan command."""

    def test_writes_active_plan_json(self, tmp_path: Path) -> None:
        with patch("launcher.context._session_dir", return_value=tmp_path):
            register_plan("docs/plans/2026-02-15-fix.md", "PENDING")

        plan_file = tmp_path / "active_plan.json"
        assert plan_file.exists()
        data = json.loads(plan_file.read_text())
        assert data["plan_path"] == "docs/plans/2026-02-15-fix.md"
        assert data["status"] == "PENDING"

    def test_uppercases_status(self, tmp_path: Path) -> None:
        with patch("launcher.context._session_dir", return_value=tmp_path):
            register_plan("plan.md", "complete")

        data = json.loads((tmp_path / "active_plan.json").read_text())
        assert data["status"] == "COMPLETE"


class TestSendClear:
    """Tests for the send-clear command."""

    def test_writes_trigger_file(self, tmp_path: Path) -> None:
        with patch("launcher.context._session_dir", return_value=tmp_path):
            send_clear(plan_path="docs/plans/test.md")

        trigger = tmp_path / "continuation-trigger.json"
        assert trigger.exists()
        data = json.loads(trigger.read_text())
        assert data["action"] == "send-clear"
        assert data["plan_path"] == "docs/plans/test.md"

    def test_writes_continuation_prompt_with_plan(self, tmp_path: Path) -> None:
        with patch("launcher.context._session_dir", return_value=tmp_path):
            send_clear(plan_path="docs/plans/test.md")

        prompt = tmp_path / "continuation-prompt.txt"
        assert prompt.exists()
        content = prompt.read_text()
        assert "/spec --continue docs/plans/test.md" in content

    def test_writes_continuation_prompt_general(self, tmp_path: Path) -> None:
        with patch("launcher.context._session_dir", return_value=tmp_path):
            send_clear(general=True)

        prompt = tmp_path / "continuation-prompt.txt"
        content = prompt.read_text()
        assert "Continue from previous session" in content

    def test_writes_general_flag_in_trigger(self, tmp_path: Path) -> None:
        with patch("launcher.context._session_dir", return_value=tmp_path):
            send_clear(general=True)

        data = json.loads((tmp_path / "continuation-trigger.json").read_text())
        assert data["general"] is True

    def test_prints_clear_to_stdout(self, tmp_path: Path, capsys: pytest.CaptureFixture[str]) -> None:
        with patch("launcher.context._session_dir", return_value=tmp_path):
            send_clear(general=True)

        captured = capsys.readouterr()
        assert "/clear" in captured.out
        assert "continuation prepared" in captured.err

    def test_plan_path_wins_over_general_flag(self, tmp_path: Path) -> None:
        """When both plan_path and general=True are given, plan_path takes precedence."""
        with patch("launcher.context._session_dir", return_value=tmp_path):
            send_clear(plan_path="docs/plans/test.md", general=True)

        prompt = (tmp_path / "continuation-prompt.txt").read_text()
        assert "/spec --continue docs/plans/test.md" in prompt

        trigger = json.loads((tmp_path / "continuation-trigger.json").read_text())
        assert trigger["plan_path"] == "docs/plans/test.md"
        # general flag must NOT appear in trigger when plan_path is set
        assert "general" not in trigger

    def test_neither_plan_nor_general_uses_generic_prompt(self, tmp_path: Path) -> None:
        """With no plan_path and general=False, falls back to generic continuation prompt."""
        with patch("launcher.context._session_dir", return_value=tmp_path):
            send_clear()

        prompt = (tmp_path / "continuation-prompt.txt").read_text()
        assert "Continue from previous session" in prompt

        trigger = json.loads((tmp_path / "continuation-trigger.json").read_text())
        assert "plan_path" not in trigger
        assert "general" not in trigger

    def test_check_context_handles_corrupt_cache(self, tmp_path: Path, capsys: pytest.CaptureFixture[str]) -> None:
        """Corrupt cache JSON should fall back to UNKNOWN status."""
        cache = tmp_path / "context-pct.json"
        cache.write_text("{not valid json!!")

        with patch("launcher.context._session_dir", return_value=tmp_path):
            check_context(as_json=True)

        output = json.loads(capsys.readouterr().out)
        assert output["status"] == "UNKNOWN"

    def test_check_context_handles_missing_pct_key(self, tmp_path: Path, capsys: pytest.CaptureFixture[str]) -> None:
        """Cache file missing 'pct' key should return UNKNOWN."""
        import time

        cache = tmp_path / "context-pct.json"
        cache.write_text(json.dumps({"ts": time.time()}))

        with patch("launcher.context._session_dir", return_value=tmp_path):
            check_context(as_json=True)

        output = json.loads(capsys.readouterr().out)
        assert output["status"] == "UNKNOWN"
