"""
Tests for UIPanel.
"""

from engine.pipeline.ui import StageControl, UIConfig, UIPanel


class MockStage:
    """Mock stage for testing."""

    def __init__(self, name, category="effect"):
        self.name = name
        self.category = category
        self._enabled = True

    def is_enabled(self):
        return self._enabled


class TestUIPanel:
    """Tests for UIPanel."""

    def test_init(self):
        """UIPanel initializes with default config."""
        panel = UIPanel()
        assert panel.config.panel_width == 24
        assert panel.config.stage_list_height == 12
        assert panel.scroll_offset == 0
        assert panel.selected_stage is None

    def test_register_stage(self):
        """register_stage adds a stage control."""
        panel = UIPanel()
        stage = MockStage("noise")
        panel.register_stage(stage, enabled=True)
        assert "noise" in panel.stages
        ctrl = panel.stages["noise"]
        assert ctrl.name == "noise"
        assert ctrl.enabled is True
        assert ctrl.selected is False

    def test_select_stage(self):
        """select_stage sets selection."""
        panel = UIPanel()
        stage1 = MockStage("noise")
        stage2 = MockStage("fade")
        panel.register_stage(stage1)
        panel.register_stage(stage2)
        panel.select_stage("fade")
        assert panel.selected_stage == "fade"
        assert panel.stages["fade"].selected is True
        assert panel.stages["noise"].selected is False

    def test_toggle_stage(self):
        """toggle_stage flips enabled state."""
        panel = UIPanel()
        stage = MockStage("glitch")
        panel.register_stage(stage, enabled=True)
        result = panel.toggle_stage("glitch")
        assert result is False
        assert panel.stages["glitch"].enabled is False
        result = panel.toggle_stage("glitch")
        assert result is True

    def test_get_enabled_stages(self):
        """get_enabled_stages returns only enabled stage names."""
        panel = UIPanel()
        panel.register_stage(MockStage("noise"), enabled=True)
        panel.register_stage(MockStage("fade"), enabled=False)
        panel.register_stage(MockStage("glitch"), enabled=True)
        enabled = panel.get_enabled_stages()
        assert set(enabled) == {"noise", "glitch"}

    def test_scroll_stages(self):
        """scroll_stages moves the view."""
        panel = UIPanel(UIConfig(stage_list_height=3))
        for i in range(10):
            panel.register_stage(MockStage(f"stage{i}"))
        assert panel.scroll_offset == 0
        panel.scroll_stages(1)
        assert panel.scroll_offset == 1
        panel.scroll_stages(-1)
        assert panel.scroll_offset == 0
        # Clamp at max
        panel.scroll_stages(100)
        assert panel.scroll_offset == 7  # 10 - 3 = 7

    def test_render_produces_lines(self):
        """render produces list of strings of correct width."""
        panel = UIPanel(UIConfig(panel_width=20))
        panel.register_stage(MockStage("noise"), enabled=True)
        panel.register_stage(MockStage("fade"), enabled=False)
        panel.select_stage("noise")
        lines = panel.render(80, 24)
        # All lines should be exactly panel_width chars (20)
        for line in lines:
            assert len(line) == 20
        # Should have header, stage rows, separator, params area, footer
        assert len(lines) >= 5

    def test_process_key_event_space_toggles_stage(self):
        """process_key_event with space toggles UI panel visibility."""
        panel = UIPanel()
        stage = MockStage("glitch")
        panel.register_stage(stage, enabled=True)
        panel.select_stage("glitch")
        # Space should now toggle UI panel visibility, not stage
        assert panel._show_panel is True
        handled = panel.process_key_event(" ")
        assert handled is True
        assert panel._show_panel is False
        # Pressing space again should show panel
        handled = panel.process_key_event(" ")
        assert panel._show_panel is True

    def test_process_key_event_space_does_not_toggle_in_picker(self):
        """Space should not toggle UI panel when preset picker is active."""
        panel = UIPanel()
        panel._show_panel = True
        panel._show_preset_picker = True
        handled = panel.process_key_event(" ")
        assert handled is False  # Not handled when picker active
        assert panel._show_panel is True  # Unchanged

    def test_process_key_event_s_selects_next(self):
        """process_key_event with s cycles selection."""
        panel = UIPanel()
        panel.register_stage(MockStage("noise"))
        panel.register_stage(MockStage("fade"))
        panel.register_stage(MockStage("glitch"))
        panel.select_stage("noise")
        handled = panel.process_key_event("s")
        assert handled is True
        assert panel.selected_stage == "fade"

    def test_process_key_event_hjkl_navigation(self):
        """process_key_event with HJKL keys."""
        panel = UIPanel()
        stage = MockStage("noise")
        panel.register_stage(stage)
        panel.select_stage("noise")

        # J or Down should scroll or adjust param
        assert panel.scroll_stages(1) is None  # Just test it doesn't error
        # H or Left should adjust param (when param selected)
        panel.selected_stage = "noise"
        panel._focused_param = "intensity"
        panel.stages["noise"].params["intensity"] = 0.5

        # Left/H should decrease
        handled = panel.process_key_event("h")
        assert handled is True
        # L or Right should increase
        handled = panel.process_key_event("l")
        assert handled is True

        # K should scroll up
        panel.selected_stage = None
        handled = panel.process_key_event("k")
        assert handled is True

    def test_set_event_callback(self):
        """set_event_callback registers callback."""
        panel = UIPanel()
        called = []

        def callback(stage_name, enabled):
            called.append((stage_name, enabled))

        panel.set_event_callback("stage_toggled", callback)
        panel.toggle_stage("test")  # No stage, won't trigger
        # Simulate toggle through event
        panel._emit_event("stage_toggled", stage_name="noise", enabled=False)
        assert called == [("noise", False)]

    def test_register_stage_returns_control(self):
        """register_stage should return the StageControl instance."""
        panel = UIPanel()
        stage = MockStage("noise_effect")
        control = panel.register_stage(stage, enabled=True)
        assert control is not None
        assert isinstance(control, StageControl)
        assert control.name == "noise_effect"
        assert control.enabled is True
