"""Tests for InitWizard."""

from __future__ import annotations

from unittest.mock import MagicMock, patch

import pytest

from ilum.wizard.flow import InitWizard


@pytest.fixture()
def wizard() -> InitWizard:
    from ilum.cli.output import IlumConsole
    from ilum.config.manager import ConfigManager
    from ilum.core.modules import ModuleResolver

    console = MagicMock(spec=IlumConsole)
    config_mgr = MagicMock(spec=ConfigManager)
    resolver = ModuleResolver()
    return InitWizard(console=console, config_mgr=config_mgr, resolver=resolver)


class TestWizardPresetStep:
    def test_step_preset_returns_none_in_non_interactive(self, wizard: InitWizard) -> None:
        result = wizard._step_preset(non_interactive=True)
        assert result is None

    def test_step_preset_custom_returns_none(self, wizard: InitWizard) -> None:
        with patch("ilum.wizard.flow.questionary") as mock_q:
            mock_q.select.return_value.ask.return_value = "Custom"
            result = wizard._step_preset(non_interactive=False)
        assert result is None

    def test_step_preset_selects_development(self, wizard: InitWizard) -> None:
        with patch("ilum.wizard.flow.questionary") as mock_q:
            mock_q.select.return_value.ask.return_value = "development"
            result = wizard._step_preset(non_interactive=False)
        assert result is not None
        assert result.name == "development"

    def test_step_preset_selects_production(self, wizard: InitWizard) -> None:
        with patch("ilum.wizard.flow.questionary") as mock_q:
            mock_q.select.return_value.ask.return_value = "production"
            result = wizard._step_preset(non_interactive=False)
        assert result is not None
        assert result.name == "production"

    def test_wizard_run_with_preset_skips_module_selection(self, wizard: InitWizard) -> None:
        """When a preset is selected, module step should be skipped."""
        from ilum.config.models import ClusterConfig
        from ilum.core.presets import PRESETS

        with (
            patch.object(wizard, "_step_preflight"),
            patch.object(wizard, "_step_cluster", return_value=ClusterConfig()),
            patch.object(wizard, "_step_profile", return_value=("default", "ilum", "default")),
            patch.object(wizard, "_step_preset") as mock_preset,
            patch.object(wizard, "_step_modules") as mock_modules,
            patch.object(wizard, "_step_confirm", return_value=True),
            patch.object(wizard, "_step_save"),
        ):
            mock_preset.return_value = PRESETS["development"]
            wizard.run(non_interactive=False)
            mock_modules.assert_not_called()

    def test_wizard_run_custom_preset_proceeds_to_modules(self, wizard: InitWizard) -> None:
        """When 'Custom' is selected, module step runs."""
        from ilum.config.models import ClusterConfig

        with (
            patch.object(wizard, "_step_preflight"),
            patch.object(wizard, "_step_cluster", return_value=ClusterConfig()),
            patch.object(wizard, "_step_profile", return_value=("default", "ilum", "default")),
            patch.object(wizard, "_step_preset", return_value=None),
            patch.object(wizard, "_step_modules", return_value=["core", "ui"]) as mock_modules,
            patch.object(wizard, "_step_confirm", return_value=True),
            patch.object(wizard, "_step_save"),
        ):
            wizard.run(non_interactive=False)
            mock_modules.assert_called_once()


class TestAskHelper:
    """Ctrl+C handling: _ask raises KeyboardInterrupt when questionary returns None."""

    def test_ask_returns_value_when_not_none(self) -> None:
        question = MagicMock()
        question.ask.return_value = "hello"
        assert InitWizard._ask(question) == "hello"

    def test_ask_raises_keyboard_interrupt_on_none(self) -> None:
        question = MagicMock()
        question.ask.return_value = None
        with pytest.raises(KeyboardInterrupt):
            InitWizard._ask(question)

    def test_ask_passes_through_falsy_non_none(self) -> None:
        """Empty string / False should pass through, not raise."""
        question = MagicMock()
        question.ask.return_value = ""
        assert InitWizard._ask(question) == ""

        question.ask.return_value = False
        assert InitWizard._ask(question) is False

    def test_step_cluster_raises_on_ctrl_c(self, wizard: InitWizard) -> None:
        """Ctrl+C during cluster selection should propagate."""
        with (
            patch.object(wizard, "_list_kubecontexts", return_value=["ctx1"]),
            patch("ilum.wizard.flow.questionary") as mock_q,
        ):
            mock_q.select.return_value.ask.return_value = None
            with pytest.raises(KeyboardInterrupt):
                wizard._step_cluster(non_interactive=False)

    def test_step_preset_raises_on_ctrl_c(self, wizard: InitWizard) -> None:
        """Ctrl+C during preset selection should propagate."""
        with patch("ilum.wizard.flow.questionary") as mock_q:
            mock_q.select.return_value.ask.return_value = None
            mock_q.Choice = MagicMock()
            with pytest.raises(KeyboardInterrupt):
                wizard._step_preset(non_interactive=False)

    def test_step_confirm_raises_on_ctrl_c(self, wizard: InitWizard) -> None:
        """Ctrl+C during confirm should propagate."""
        from ilum.config.models import ClusterConfig, ProfileConfig

        profile = ProfileConfig(
            name="test",
            release_name="ilum",
            cluster=ClusterConfig(),
            enabled_modules=["core", "ui"],
        )
        with patch("ilum.wizard.flow.questionary") as mock_q:
            mock_q.confirm.return_value.ask.return_value = None
            with pytest.raises(KeyboardInterrupt):
                wizard._step_confirm(profile)
