"""Tests for Activity focus management."""

from pyos import Keys
from pyos.Activity import Activity
from pyos.EventTypes import KeyStroke
from pyos.input_handlers import handle_text_box_input
from pyos.printers.TextInput import TextInput


class TestCycleFocus:
    def test_cycle_through_tab_order(self, app, mock_screen):
        class TwoPane(Activity):
            def on_start(self):
                self.tab_order = ["a", "b"]
                self.display_state = {
                    "a": {"focused": True, "layout": {"height": 1},
                           "line_generator": lambda ctx, h: []},
                    "b": {"focused": False, "layout": {"height": 1},
                           "line_generator": lambda ctx, h: []},
                }
                self.focus = "a"

        act = TwoPane()
        app.start_activity(act)

        assert act.focus == "a"
        assert act.display_state["a"]["focused"] is True

        act.cycle_focus()
        assert act.focus == "b"
        assert act.display_state["b"]["focused"] is True
        assert act.display_state["a"]["focused"] is False

    def test_cycle_wraps_around(self, app, mock_screen):
        class TwoPane(Activity):
            def on_start(self):
                self.tab_order = ["a", "b"]
                self.display_state = {
                    "a": {"focused": True, "layout": {"height": 1},
                           "line_generator": lambda ctx, h: []},
                    "b": {"focused": False, "layout": {"height": 1},
                           "line_generator": lambda ctx, h: []},
                }
                self.focus = "a"

        act = TwoPane()
        app.start_activity(act)

        act.cycle_focus()  # -> b
        act.cycle_focus()  # -> a (wrap)
        assert act.focus == "a"
        assert act.display_state["a"]["focused"] is True
        assert act.display_state["b"]["focused"] is False

    def test_cycle_noop_when_empty(self, app, mock_screen):
        class Empty(Activity):
            def on_start(self):
                self.display_state = {}

        act = Empty()
        app.start_activity(act)

        act.cycle_focus()  # should not raise
        assert act.focus is None


class TestSetFocus:
    def test_set_focus_updates_flags(self, app, mock_screen):
        class TwoPane(Activity):
            def on_start(self):
                self.tab_order = ["a", "b"]
                self.display_state = {
                    "a": {"focused": True, "layout": {"height": 1},
                           "line_generator": lambda ctx, h: []},
                    "b": {"focused": False, "layout": {"height": 1},
                           "line_generator": lambda ctx, h: []},
                }
                self.focus = "a"

        act = TwoPane()
        app.start_activity(act)

        act._set_focus("b")
        assert act.focus == "b"
        assert act.display_state["a"]["focused"] is False
        assert act.display_state["b"]["focused"] is True


class TestDelegateToFocused:
    def test_delegates_to_input_handler(self, app, mock_screen):
        called_with = []

        def mock_handler(name, ctx, event, eq):
            called_with.append((name, event.key))

        class WithHandler(Activity):
            def on_start(self):
                self.tab_order = ["field"]
                self.focus = "field"
                self.display_state = {
                    "field": {
                        "focused": True,
                        "input_handler": mock_handler,
                        "layout": {"height": 1},
                        "line_generator": lambda ctx, h: [],
                    },
                }

        act = WithHandler()
        app.start_activity(act)

        event = KeyStroke(ord("x"))
        result = act.delegate_to_focused(event)
        assert result is True
        assert called_with == [("field", ord("x"))]

    def test_returns_false_without_handler(self, app, mock_screen):
        class NoHandler(Activity):
            def on_start(self):
                self.tab_order = ["field"]
                self.focus = "field"
                self.display_state = {
                    "field": {
                        "focused": True,
                        "layout": {"height": 1},
                        "line_generator": lambda ctx, h: [],
                    },
                }

        act = NoHandler()
        app.start_activity(act)
        assert act.delegate_to_focused(KeyStroke(ord("x"))) is False

    def test_returns_false_when_no_focus(self, app, mock_screen):
        class NoFocus(Activity):
            def on_start(self):
                self.display_state = {}

        act = NoFocus()
        app.start_activity(act)
        assert act.delegate_to_focused(KeyStroke(ord("x"))) is False


class TestBackwardsCompat:
    """Activities that don't use focus management should still work."""

    def test_activity_without_tab_order(self, app, mock_screen):
        class Plain(Activity):
            def on_start(self):
                self.display_state = {
                    "content": {
                        "layout": {"height": 1},
                        "line_generator": lambda ctx, h: [],
                    },
                }

        act = Plain()
        app.start_activity(act)
        assert act.tab_order == []
        assert act.focus is None
        # cycle_focus is a no-op
        act.cycle_focus()
        assert act.focus is None
