"""Tests for the SkilarkApp shell: launch, tab navigation, keybindings."""

import pytest

from skilark_cli.tui.app import SkilarkApp, HeaderBar, HelpScreen


@pytest.fixture
def app():
    return SkilarkApp(client=None)


class TestAppLaunch:
    async def test_app_starts(self, app):
        async with app.run_test() as pilot:
            assert app.is_running

    async def test_header_bar_present(self, app):
        async with app.run_test() as pilot:
            header = app.query_one(HeaderBar)
            assert header is not None

    async def test_header_bar_has_id(self, app):
        async with app.run_test() as pilot:
            header = app.query_one("#header-bar")
            assert header is not None

    async def test_default_tab_is_drill(self, app):
        async with app.run_test() as pilot:
            assert app._active_tab == 0


class TestTabNavigation:
    async def test_switch_to_drill(self, app):
        async with app.run_test() as pilot:
            await pilot.press("1")
            assert app._active_tab == 0

    async def test_switch_to_signals(self, app):
        async with app.run_test() as pilot:
            await pilot.press("2")
            assert app._active_tab == 1

    async def test_switch_to_jobs(self, app):
        async with app.run_test() as pilot:
            await pilot.press("3")
            assert app._active_tab == 2

    async def test_switch_to_profile(self, app):
        async with app.run_test() as pilot:
            await pilot.press("4")
            assert app._active_tab == 3

    async def test_same_tab_noop(self, app):
        """Pressing the current tab key doesn't remount."""
        async with app.run_test() as pilot:
            await pilot.press("1")  # already on drill
            assert app._active_tab == 0  # unchanged


class TestHelpScreen:
    async def test_help_opens_modal(self, app):
        async with app.run_test() as pilot:
            await pilot.press("question_mark")
            assert isinstance(app.screen, HelpScreen)

    async def test_help_closes_with_question_mark(self, app):
        async with app.run_test() as pilot:
            await pilot.press("question_mark")
            assert isinstance(app.screen, HelpScreen)
            await pilot.press("question_mark")
            assert not isinstance(app.screen, HelpScreen)

    async def test_help_closes_with_escape(self, app):
        async with app.run_test() as pilot:
            await pilot.press("question_mark")
            assert isinstance(app.screen, HelpScreen)
            await pilot.press("escape")
            assert not isinstance(app.screen, HelpScreen)

    async def test_help_blocks_tab_switch(self, app):
        """Number keys while help is open should not switch tabs."""
        async with app.run_test() as pilot:
            await pilot.press("question_mark")
            await pilot.press("3")
            # Tab should not have changed
            assert app._active_tab == 0
            # Modal should still be open (keys are blocked, not dismissed)
            assert isinstance(app.screen, HelpScreen)

    async def test_help_blocks_quit(self, app):
        """q while help is open should not quit the app."""
        async with app.run_test() as pilot:
            await pilot.press("question_mark")
            await pilot.press("q")
            assert isinstance(app.screen, HelpScreen)
            assert app.is_running


class TestAppConstructor:
    def test_app_stores_topics(self):
        """AC15: SkilarkApp stores topics for DrillPane to use."""
        app = SkilarkApp(topics=["python", "dsa"])
        assert app.topics == ["python", "dsa"]

    def test_app_stores_coding_language(self):
        """SkilarkApp stores coding_language for future Drill coding phase."""
        app = SkilarkApp(coding_language="python")
        assert app.coding_language == "python"

    def test_app_defaults_topics_to_empty(self):
        app = SkilarkApp()
        assert app.topics == []

    def test_app_defaults_coding_language_to_none(self):
        app = SkilarkApp()
        assert app.coding_language is None


class TestThemeCycle:
    async def test_default_theme_is_dark(self, app):
        async with app.run_test():
            assert app.theme == "textual-dark"

    async def test_cycle_advances_to_next_theme(self, app):
        async with app.run_test() as pilot:
            themes = sorted(app.available_themes)
            idx = themes.index("textual-dark")
            expected = themes[(idx + 1) % len(themes)]
            await pilot.press("t")
            assert app.theme == expected

    async def test_cycle_wraps_around(self, app):
        async with app.run_test() as pilot:
            themes = sorted(app.available_themes)
            for _ in range(len(themes)):
                await pilot.press("t")
            assert app.theme == "textual-dark"  # back to start

    async def test_theme_blocked_during_help(self, app):
        async with app.run_test() as pilot:
            await pilot.press("question_mark")
            assert isinstance(app.screen, HelpScreen)
            await pilot.press("t")
            assert app.theme == "textual-dark"  # unchanged

    def test_legacy_light_theme_from_config(self):
        app = SkilarkApp(theme="light")
        assert app.theme == "textual-light"

    def test_named_theme_from_config(self):
        app = SkilarkApp(theme="dracula")
        assert app.theme == "dracula"

    async def test_cycle_persists_to_config_store(self, tmp_path):
        from skilark_cli.config_store import ConfigStore

        store = ConfigStore(config_dir=tmp_path)
        store.save(user_id="abc", topics=[])
        app = SkilarkApp(config_store=store)
        async with app.run_test() as pilot:
            await pilot.press("t")
        config = store.load()
        assert config["theme"] == app.theme

    async def test_direct_theme_set_persists(self, tmp_path):
        """Setting app.theme directly (as palette does) also persists."""
        from skilark_cli.config_store import ConfigStore

        store = ConfigStore(config_dir=tmp_path)
        store.save(user_id="abc", topics=[])
        app = SkilarkApp(config_store=store)
        async with app.run_test():
            app.theme = "dracula"
        config = store.load()
        assert config["theme"] == "dracula"


class TestQuit:
    async def test_single_q_does_not_quit(self, app):
        async with app.run_test() as pilot:
            await pilot.press("q")
            assert app.is_running

    async def test_double_q_quits(self, app):
        async with app.run_test() as pilot:
            await pilot.press("q")
            await pilot.press("q")
        assert not app.is_running

    async def test_q_after_timeout_resets(self, app):
        app._quit_timeout = 0.1  # shorten for test
        async with app.run_test() as pilot:
            await pilot.press("q")
            import asyncio
            await asyncio.sleep(0.15)
            await pilot.press("q")
            assert app.is_running  # reset, need another q

    async def test_quit_blocked_during_help(self, app):
        async with app.run_test() as pilot:
            await pilot.press("question_mark")
            await pilot.press("q")
            await pilot.press("q")
            assert app.is_running  # blocked by help modal
