"""Tests for error codes registry and error handling."""

from __future__ import annotations

from ilum.error_codes import ERROR_REGISTRY
from ilum.errors import ConfigError, HelmError, IlumError, ModuleError


class TestErrorCodeRegistry:
    def test_all_codes_have_valid_format(self) -> None:
        for code, entry in ERROR_REGISTRY.items():
            assert code.startswith("ILUM-"), f"Code {code} does not start with ILUM-"
            assert code == entry.code
            assert len(entry.category) > 0
            assert len(entry.title) > 0

    def test_registry_lookup(self) -> None:
        entry = ERROR_REGISTRY["ILUM-020"]
        assert entry.code == "ILUM-020"
        assert entry.category == "helm"
        assert entry.title == "Helm command failed"

    def test_error_code_frozen(self) -> None:
        entry = ERROR_REGISTRY["ILUM-001"]
        import pytest

        with pytest.raises(AttributeError):
            entry.code = "changed"  # type: ignore[misc]

    def test_all_categories_valid(self) -> None:
        valid = {
            "prerequisite",
            "cluster",
            "helm",
            "config",
            "module",
            "values",
            "auth",
            "exec",
            "events",
            "metrics",
        }
        for entry in ERROR_REGISTRY.values():
            assert entry.category in valid, f"Invalid category: {entry.category}"


class TestIlumErrorWithCode:
    def test_backward_compat_no_code(self) -> None:
        err = IlumError("something failed")
        assert str(err) == "something failed"
        assert err.error_code == ""
        assert err.recovery_steps == []
        assert err.suggestion == ""

    def test_backward_compat_with_suggestion(self) -> None:
        err = IlumError("failed", "try again")
        assert err.suggestion == "try again"
        assert err.error_code == ""

    def test_with_error_code(self) -> None:
        err = IlumError("Helm failed", error_code="ILUM-020")
        assert err.error_code == "ILUM-020"
        assert str(err) == "Helm failed"

    def test_with_recovery_steps(self) -> None:
        err = IlumError(
            "failed",
            error_code="ILUM-020",
            recovery_steps=["Check connectivity", "Retry"],
        )
        assert len(err.recovery_steps) == 2
        assert err.recovery_steps[0] == "Check connectivity"

    def test_recovery_steps_from_tuple(self) -> None:
        err = IlumError(
            "failed",
            recovery_steps=("Step 1", "Step 2"),
        )
        assert isinstance(err.recovery_steps, list)
        assert len(err.recovery_steps) == 2

    def test_subclass_inherits_error_code(self) -> None:
        err = HelmError("helm broke", error_code="ILUM-020")
        assert err.error_code == "ILUM-020"
        assert isinstance(err, IlumError)

    def test_module_error_with_code(self) -> None:
        err = ModuleError("unknown module", error_code="ILUM-040")
        assert err.error_code == "ILUM-040"

    def test_config_error_with_code(self) -> None:
        err = ConfigError("bad config", error_code="ILUM-030")
        assert err.error_code == "ILUM-030"


class TestHandleErrorWithCode:
    def test_handle_error_shows_code_prefix(self, capsys) -> None:
        from ilum.cli.output import IlumConsole

        console = IlumConsole()
        err = IlumError("Something failed", error_code="ILUM-020")
        console.handle_error(err)

        captured = capsys.readouterr()
        assert "ILUM-020" in captured.err
        assert "Something failed" in captured.err

    def test_handle_error_without_code(self, capsys) -> None:
        from ilum.cli.output import IlumConsole

        console = IlumConsole()
        err = IlumError("Something failed")
        console.handle_error(err)

        captured = capsys.readouterr()
        assert "ILUM-" not in captured.err
        assert "Something failed" in captured.err

    def test_handle_error_with_recovery_steps(self, capsys) -> None:
        from ilum.cli.output import IlumConsole

        console = IlumConsole()
        err = IlumError(
            "Something failed",
            error_code="ILUM-020",
            recovery_steps=["Check connectivity", "Retry the operation"],
        )
        console.handle_error(err)

        captured = capsys.readouterr()
        assert "Recovery steps" in captured.out
        assert "Check connectivity" in captured.out
        assert "Retry the operation" in captured.out
