"""
Module: test_status
Description: Tests for the huitzo status command

Implements:
    - docs/cli/reference.md#huitzo-status
"""

import json
from pathlib import Path
from unittest.mock import MagicMock, patch

import httpx
import pytest
from typer.testing import CliRunner

from huitzo_cli.auth import TokenStore
from huitzo_cli.main import app


@pytest.fixture
def runner() -> CliRunner:
    return CliRunner()


@pytest.fixture
def no_token(temp_dir: Path):
    """Patch token store to return no token."""
    token_file = temp_dir / "token"
    with patch.object(TokenStore, "_get_token_path", return_value=token_file):
        yield


@pytest.fixture
def with_token(temp_dir: Path):
    """Patch token store to return a valid token."""
    token_file = temp_dir / "token"
    token_file.parent.mkdir(parents=True, exist_ok=True)
    token_file.write_text("test-token-123")
    with patch.object(TokenStore, "_get_token_path", return_value=token_file):
        yield


def _mock_user_response() -> httpx.Response:
    response = MagicMock(spec=httpx.Response)
    response.status_code = 200
    response.json.return_value = {
        "data": {
            "email": "dev@acme.com",
            "role": "developer",
            "subscriptionTier": "developer_preview",
            "tenantSlug": "acme",
        }
    }
    return response


def _mock_health_response() -> httpx.Response:
    response = MagicMock(spec=httpx.Response)
    response.status_code = 200
    response.json.return_value = {"status": "healthy", "version": "0.3.0"}
    return response


def _mock_sessions_response(sessions: list | None = None) -> httpx.Response:
    response = MagicMock(spec=httpx.Response)
    response.status_code = 200
    response.json.return_value = {"data": sessions or []}
    return response


def _authenticated_side_effect(sessions: list | None = None):
    """Side effect for authenticated requests with health + auth/me + dev-sessions."""

    def side_effect(url, **kwargs):
        if "/auth/me" in url:
            return _mock_user_response()
        if "/health" in url:
            return _mock_health_response()
        if "/dev-sessions" in url:
            return _mock_sessions_response(sessions)
        raise httpx.HTTPError("unexpected")

    return side_effect


class TestStatusUnauthenticated:
    def test_shows_not_authenticated(self, runner: CliRunner, no_token: None) -> None:
        with patch("huitzo_cli.commands.status.httpx.get") as mock_get:
            mock_get.return_value = _mock_health_response()
            result = runner.invoke(app, ["status"])
        assert result.exit_code == 0
        assert "Not authenticated" in result.output

    def test_suggests_login(self, runner: CliRunner, no_token: None) -> None:
        with patch("huitzo_cli.commands.status.httpx.get") as mock_get:
            mock_get.return_value = _mock_health_response()
            result = runner.invoke(app, ["status"])
        assert "huitzo login" in result.output

    def test_no_dev_sessions_section_when_unauthenticated(
        self, runner: CliRunner, no_token: None
    ) -> None:
        with patch("huitzo_cli.commands.status.httpx.get") as mock_get:
            mock_get.return_value = _mock_health_response()
            result = runner.invoke(app, ["status"])
        assert "Dev Sessions" not in result.output


class TestStatusAuthenticated:
    def test_shows_user_info(self, runner: CliRunner, with_token: None) -> None:
        with patch("huitzo_cli.commands.status.httpx.get") as mock_get:
            mock_get.side_effect = _authenticated_side_effect()
            result = runner.invoke(app, ["status"])
        assert result.exit_code == 0
        assert "dev@acme.com" in result.output
        assert "developer_preview" in result.output
        assert "acme" in result.output

    def test_shows_server_info(self, runner: CliRunner, with_token: None) -> None:
        with patch("huitzo_cli.commands.status.httpx.get") as mock_get:
            mock_get.side_effect = _authenticated_side_effect()
            result = runner.invoke(app, ["status"])
        assert "healthy" in result.output
        assert "0.3.0" in result.output

    def test_shows_active_dev_sessions(self, runner: CliRunner, with_token: None) -> None:
        sessions = [
            {
                "id": "abcdef12-3456-7890-abcd-ef1234567890",
                "pack_namespace": "my-pack",
                "sandbox_type": "local",
                "local_port": 8080,
            }
        ]
        with patch("huitzo_cli.commands.status.httpx.get") as mock_get:
            mock_get.side_effect = _authenticated_side_effect(sessions)
            result = runner.invoke(app, ["status"])
        assert "Dev Sessions" in result.output
        assert "abcdef12" in result.output
        assert "my-pack" in result.output
        assert "8080" in result.output

    def test_shows_no_active_sessions(self, runner: CliRunner, with_token: None) -> None:
        with patch("huitzo_cli.commands.status.httpx.get") as mock_get:
            mock_get.side_effect = _authenticated_side_effect(sessions=[])
            result = runner.invoke(app, ["status"])
        assert "No active dev sessions" in result.output


class TestStatusServerUnreachable:
    def test_shows_unreachable(self, runner: CliRunner, no_token: None) -> None:
        with patch(
            "huitzo_cli.commands.status.httpx.get",
            side_effect=httpx.ConnectError("refused"),
        ):
            result = runner.invoke(app, ["status"])
        assert result.exit_code == 0
        assert "unreachable" in result.output

    def test_dev_sessions_fetch_failure(self, runner: CliRunner, with_token: None) -> None:
        """Dev sessions network error shows warning, doesn't crash."""

        def side_effect(url, **kwargs):
            if "/auth/me" in url:
                return _mock_user_response()
            if "/health" in url:
                return _mock_health_response()
            if "/dev-sessions" in url:
                raise httpx.ConnectError("refused")
            raise httpx.HTTPError("unexpected")

        with patch("huitzo_cli.commands.status.httpx.get") as mock_get:
            mock_get.side_effect = side_effect
            result = runner.invoke(app, ["status"])
        assert result.exit_code == 0
        assert "Could not fetch dev sessions" in result.output


class TestStatusJsonOutput:
    def test_valid_json_authenticated(self, runner: CliRunner, with_token: None) -> None:
        with patch("huitzo_cli.commands.status.httpx.get") as mock_get:
            mock_get.side_effect = _authenticated_side_effect()
            result = runner.invoke(app, ["status", "--json"])
        assert result.exit_code == 0
        data = json.loads(result.output)
        assert data["identity"]["authenticated"] is True
        assert data["identity"]["email"] == "dev@acme.com"
        assert data["server"]["reachable"] is True
        assert data["server"]["version"] == "0.3.0"

    def test_json_unauthenticated(self, runner: CliRunner, no_token: None) -> None:
        with patch("huitzo_cli.commands.status.httpx.get") as mock_get:
            mock_get.return_value = _mock_health_response()
            result = runner.invoke(app, ["status", "--json"])
        assert result.exit_code == 0
        data = json.loads(result.output)
        assert data["identity"]["authenticated"] is False

    def test_json_server_unreachable(self, runner: CliRunner, no_token: None) -> None:
        with patch(
            "huitzo_cli.commands.status.httpx.get",
            side_effect=httpx.ConnectError("refused"),
        ):
            result = runner.invoke(app, ["status", "--json"])
        assert result.exit_code == 0
        data = json.loads(result.output)
        assert data["server"]["reachable"] is False


class TestStatusCodebase:
    def test_not_in_pack_dir(self, runner: CliRunner, no_token: None) -> None:
        with (
            patch(
                "huitzo_cli.commands.status.httpx.get",
                side_effect=httpx.ConnectError("refused"),
            ),
            patch("huitzo_cli.commands.status.PackValidator") as mock_validator,
        ):
            from huitzo_cli.validator import ValidationResult

            mock_instance = MagicMock()
            mock_instance.validate.return_value = ValidationResult(
                valid=False,
                errors=["pyproject.toml not found", "huitzo.yaml not found"],
                warnings=["src/ directory not found", "tests/ directory not found"],
            )
            mock_validator.return_value = mock_instance
            result = runner.invoke(app, ["status"])
        assert result.exit_code == 0
        assert "Not in a pack directory" in result.output

    def test_valid_pack(self, runner: CliRunner, no_token: None) -> None:
        with (
            patch(
                "huitzo_cli.commands.status.httpx.get",
                side_effect=httpx.ConnectError("refused"),
            ),
            patch("huitzo_cli.commands.status.PackValidator") as mock_validator,
        ):
            from huitzo_cli.validator import ValidationResult

            mock_instance = MagicMock()
            mock_instance.validate.return_value = ValidationResult(
                valid=True, errors=[], warnings=[]
            )
            mock_validator.return_value = mock_instance
            result = runner.invoke(app, ["status"])
        assert result.exit_code == 0
        assert "Valid Intelligence Pack" in result.output
