"""Tests for agnes diagnose command."""

import json
import pytest
from unittest.mock import patch, MagicMock

from typer.testing import CliRunner
from cli.main import app

runner = CliRunner()


@pytest.fixture(autouse=True)
def tmp_config(tmp_path, monkeypatch):
    monkeypatch.setenv("AGNES_CONFIG_DIR", str(tmp_path / "config"))
    (tmp_path / "config").mkdir()
    yield tmp_path


def _resp(status_code=200, json_data=None):
    r = MagicMock()
    r.status_code = status_code
    r.json.return_value = json_data if json_data is not None else {}
    r.elapsed = MagicMock()
    r.elapsed.total_seconds.return_value = 0.042
    return r


HEALTHY_HEALTH = {
    "status": "ok",
    "instance_name": "Test Instance",
    "services": {
        "duckdb": {"status": "ok", "tables": 5},
        "scheduler": {"status": "ok"},
    },
}


class TestDiagnoseText:
    def test_diagnose_healthy(self):
        """Diagnose healthy system shows 'healthy' overall."""
        with patch("cli.commands.diagnose.api_get", return_value=_resp(200, HEALTHY_HEALTH)):
            result = runner.invoke(app, ["diagnose"])
        assert result.exit_code == 0
        assert "healthy" in result.output.lower()
        assert "api" in result.output
        assert "duckdb" in result.output

    def test_diagnose_api_unreachable(self):
        """Diagnose marks overall as unhealthy when API is down."""
        with patch("cli.commands.diagnose.api_get", side_effect=Exception("Connection refused")):
            result = runner.invoke(app, ["diagnose"])
        assert result.exit_code == 0
        assert "unhealthy" in result.output.lower()
        assert "api" in result.output
        assert "Server unreachable" in result.output or "Suggested actions" in result.output

    def test_diagnose_warning_service(self):
        """Diagnose shows 'degraded' when a service reports warning."""
        health = {
            "services": {
                "duckdb": {"status": "warning", "stale_tables": ["orders"]},
            }
        }
        with patch("cli.commands.diagnose.api_get", return_value=_resp(200, health)):
            result = runner.invoke(app, ["diagnose"])
        assert result.exit_code == 0
        assert "degraded" in result.output.lower()


class TestDiagnoseJson:
    def test_diagnose_json_output(self):
        """--json flag produces parseable JSON with expected structure."""
        with patch("cli.commands.diagnose.api_get", return_value=_resp(200, HEALTHY_HEALTH)):
            result = runner.invoke(app, ["diagnose", "--json"])
        assert result.exit_code == 0
        data = json.loads(result.output)
        assert "overall" in data
        assert "checks" in data
        assert "suggested_actions" in data

    def test_diagnose_json_api_down(self):
        """--json flag still emits valid JSON when API is unreachable."""
        with patch("cli.commands.diagnose.api_get", side_effect=Exception("timeout")):
            result = runner.invoke(app, ["diagnose", "--json"])
        assert result.exit_code == 0
        data = json.loads(result.output)
        assert data["overall"] == "unhealthy"
        assert any(c["name"] == "api" and c["status"] == "error" for c in data["checks"])

    def test_diagnose_json_has_latency(self):
        """Healthy API check includes latency_ms in JSON output."""
        with patch("cli.commands.diagnose.api_get", return_value=_resp(200, HEALTHY_HEALTH)):
            result = runner.invoke(app, ["diagnose", "--json"])
        assert result.exit_code == 0
        data = json.loads(result.output)
        api_check = next(c for c in data["checks"] if c["name"] == "api")
        assert "latency_ms" in api_check
