"""Tests for Phase 2 doctor enhancements."""

from __future__ import annotations

from unittest.mock import MagicMock

import pytest

from ilum.cli.output import IlumConsole
from ilum.core.helm import HelmClient
from ilum.core.kubernetes import KubeClient
from ilum.doctor.checks import CheckResult, CheckStatus, check_storage_class
from ilum.doctor.runner import DoctorRunner


@pytest.fixture()
def mock_runner() -> DoctorRunner:
    helm = MagicMock(spec=HelmClient)
    k8s = MagicMock(spec=KubeClient)
    console = IlumConsole()
    return DoctorRunner(helm=helm, k8s=k8s, console=console, namespace="default", release="ilum")


class TestCheckResultFixable:
    def test_fixable_default_false(self) -> None:
        r = CheckResult(name="test", status=CheckStatus.OK, message="ok")
        assert r.fixable is False

    def test_fixable_set_true(self) -> None:
        r = CheckResult(name="test", status=CheckStatus.FAIL, message="fail", fixable=True)
        assert r.fixable is True


class TestToDict:
    def test_serializes_results(self, mock_runner: DoctorRunner) -> None:
        results = [
            CheckResult(name="helm", status=CheckStatus.OK, message="ok"),
            CheckResult(
                name="cluster",
                status=CheckStatus.FAIL,
                message="down",
                suggestion="fix it",
                fixable=True,
            ),
        ]
        data = mock_runner.to_dict(results)
        assert len(data) == 2
        assert data[0]["name"] == "helm"
        assert data[0]["status"] == "ok"
        assert data[0]["fixable"] is False
        assert data[1]["status"] == "fail"
        assert data[1]["fixable"] is True
        assert data[1]["suggestion"] == "fix it"


class TestFixSimpleIssues:
    def test_fix_creates_namespace(self, mock_runner: DoctorRunner) -> None:
        results = [
            CheckResult(
                name="namespace",
                status=CheckStatus.FAIL,
                message="not found",
                fixable=True,
            ),
        ]
        fixed = mock_runner.fix_simple_issues(results)
        assert len(fixed) == 1
        assert "namespace" in fixed[0].lower()
        mock_runner._k8s.create_namespace.assert_called_once()

    def test_fix_skips_non_fixable(self, mock_runner: DoctorRunner) -> None:
        results = [
            CheckResult(
                name="pods",
                status=CheckStatus.FAIL,
                message="crashloop",
                fixable=False,
            ),
        ]
        fixed = mock_runner.fix_simple_issues(results)
        assert len(fixed) == 0

    def test_fix_skips_ok_results(self, mock_runner: DoctorRunner) -> None:
        results = [
            CheckResult(
                name="namespace",
                status=CheckStatus.OK,
                message="exists",
                fixable=True,
            ),
        ]
        fixed = mock_runner.fix_simple_issues(results)
        assert len(fixed) == 0


class TestCheckStorageClass:
    def test_ok_with_default(self) -> None:
        k8s = MagicMock(spec=KubeClient)
        k8s.list_storage_classes.return_value = [
            {"name": "standard", "provisioner": "k8s.io/local", "is_default": True}
        ]
        result = check_storage_class(k8s)
        assert result.status == CheckStatus.OK
        assert "standard" in result.message

    def test_warn_no_default(self) -> None:
        k8s = MagicMock(spec=KubeClient)
        k8s.list_storage_classes.return_value = [
            {"name": "manual", "provisioner": "k8s.io/local", "is_default": False}
        ]
        result = check_storage_class(k8s)
        assert result.status == CheckStatus.WARN

    def test_warn_no_classes(self) -> None:
        k8s = MagicMock(spec=KubeClient)
        k8s.list_storage_classes.return_value = []
        result = check_storage_class(k8s)
        assert result.status == CheckStatus.WARN

    def test_skip_on_error(self) -> None:
        k8s = MagicMock(spec=KubeClient)
        k8s.list_storage_classes.side_effect = Exception("fail")
        result = check_storage_class(k8s)
        assert result.status == CheckStatus.SKIP
