"""Tests for the drill BrowserView widget (side-by-side DataTables)."""

import pytest
from textual.app import App, ComposeResult
from textual.widgets import DataTable

from skilark_cli.tui.widgets.browser_view import BrowserView


MOCK_TOPICS = [
    {"topic": "python", "total": 45, "completed": 23, "correct": 18, "accuracy": 0.78},
    {"topic": "go", "total": 30, "completed": 12, "correct": 10, "accuracy": 0.83},
    {"topic": "sql", "total": 25, "completed": 0, "correct": 0, "accuracy": 0.0},
]

MOCK_CATEGORIES = [
    {"category": "arrays", "total": 12, "solved": 5},
    {"category": "strings", "total": 8, "solved": 3},
]


class BrowserApp(App):
    def __init__(self, topics=None, categories=None, configured_topics=None):
        super().__init__()
        self._topics = topics or []
        self._categories = categories or []
        self._configured = configured_topics or []

    def compose(self) -> ComposeResult:
        yield BrowserView(id="browser")

    def on_mount(self) -> None:
        browser = self.query_one("#browser", BrowserView)
        browser.load(self._topics, self._categories, self._configured)


@pytest.mark.asyncio
async def test_browser_mounts():
    """Browser widget mounts without error."""
    app = BrowserApp(topics=MOCK_TOPICS, categories=MOCK_CATEGORIES, configured_topics=["python"])
    async with app.run_test() as pilot:
        browser = app.query_one("#browser", BrowserView)
        assert browser is not None


@pytest.mark.asyncio
async def test_browser_has_two_datatables():
    """Browser contains a quiz DataTable and a coding DataTable."""
    app = BrowserApp(topics=MOCK_TOPICS, categories=MOCK_CATEGORIES, configured_topics=["python"])
    async with app.run_test() as pilot:
        quiz_table = app.query_one("#quiz-topic-table", DataTable)
        code_table = app.query_one("#coding-category-table", DataTable)
        assert quiz_table is not None
        assert code_table is not None


@pytest.mark.asyncio
async def test_browser_loads_topics():
    """Browser loads quiz items after load()."""
    app = BrowserApp(topics=MOCK_TOPICS, configured_topics=["python", "go"])
    async with app.run_test() as pilot:
        browser = app.query_one("#browser", BrowserView)
        assert len(browser.quiz_items) == 3


@pytest.mark.asyncio
async def test_browser_configured_topics_first():
    """Configured topics appear before unconfigured ones."""
    app = BrowserApp(topics=MOCK_TOPICS, configured_topics=["go"])
    async with app.run_test() as pilot:
        browser = app.query_one("#browser", BrowserView)
        assert browser.quiz_items[0]["topic"] == "go"


@pytest.mark.asyncio
async def test_browser_loads_categories():
    """Browser loads category items after load()."""
    app = BrowserApp(categories=MOCK_CATEGORIES, configured_topics=[])
    async with app.run_test() as pilot:
        browser = app.query_one("#browser", BrowserView)
        assert len(browser.category_items) == 2
        assert browser.category_items[0]["category"] == "arrays"


@pytest.mark.asyncio
async def test_browser_empty_data():
    """Browser handles empty topics and categories gracefully."""
    app = BrowserApp(topics=[], categories=[], configured_topics=[])
    async with app.run_test() as pilot:
        browser = app.query_one("#browser", BrowserView)
        assert browser.quiz_items == []
        assert browser.category_items == []


@pytest.mark.asyncio
async def test_quiz_table_row_count():
    """Quiz DataTable has one row per visible topic."""
    app = BrowserApp(topics=MOCK_TOPICS, configured_topics=["python"])
    async with app.run_test() as pilot:
        table = app.query_one("#quiz-topic-table", DataTable)
        assert table.row_count == 3  # all 3 shown (< 4 total)


@pytest.mark.asyncio
async def test_coding_table_row_count():
    """Coding DataTable has one row per visible category."""
    app = BrowserApp(categories=MOCK_CATEGORIES, configured_topics=[])
    async with app.run_test() as pilot:
        table = app.query_one("#coding-category-table", DataTable)
        assert table.row_count == 2


@pytest.mark.asyncio
async def test_topic_selected_message():
    """Selecting a quiz topic row posts TopicSelected message."""
    messages = []

    class TestApp(BrowserApp):
        def on_browser_view_topic_selected(self, event):
            messages.append(event.topic)

    app = TestApp(topics=MOCK_TOPICS, configured_topics=["python"])
    async with app.run_test() as pilot:
        table = app.query_one("#quiz-topic-table", DataTable)
        table.focus()
        await pilot.pause()
        await pilot.press("enter")
        await pilot.pause()
        assert len(messages) == 1
        # First row is "python" (configured, sorted first)
        assert messages[0] == "python"


@pytest.mark.asyncio
async def test_category_selected_message():
    """Selecting a coding category row posts CategorySelected message."""
    messages = []

    class TestApp(BrowserApp):
        def on_browser_view_category_selected(self, event):
            messages.append(event.category)

    app = TestApp(categories=MOCK_CATEGORIES, configured_topics=[])
    async with app.run_test() as pilot:
        table = app.query_one("#coding-category-table", DataTable)
        table.focus()
        await pilot.pause()
        await pilot.press("enter")
        await pilot.pause()
        assert len(messages) == 1
        assert messages[0] == "arrays"


# --- Toggle show-all tests ---

MANY_TOPICS = [
    {"topic": f"topic-{i}", "total": 10, "completed": i, "correct": i, "accuracy": i / 10}
    for i in range(8)
]


@pytest.mark.asyncio
async def test_toggle_show_all_quiz_focused():
    """Pressing toggle_show_all with quiz table focused expands quiz topics."""
    app = BrowserApp(topics=MANY_TOPICS, categories=MOCK_CATEGORIES, configured_topics=["topic-0"])
    async with app.run_test() as pilot:
        browser = app.query_one("#browser", BrowserView)
        table = app.query_one("#quiz-topic-table", DataTable)
        table.focus()
        await pilot.pause()
        # Initially shows max(1 configured, 4) = 4 topics
        assert table.row_count == 4
        browser.toggle_show_all()
        assert table.row_count == 8


@pytest.mark.asyncio
async def test_toggle_show_all_coding_focused():
    """Pressing toggle_show_all with coding table focused expands categories."""
    many_cats = [
        {"category": f"cat-{i}", "total": 10, "solved": i} for i in range(6)
    ]
    app = BrowserApp(topics=MOCK_TOPICS, categories=many_cats, configured_topics=[])
    async with app.run_test() as pilot:
        browser = app.query_one("#browser", BrowserView)
        table = app.query_one("#coding-category-table", DataTable)
        table.focus()
        await pilot.pause()
        assert table.row_count == 4
        browser.toggle_show_all()
        assert table.row_count == 6


@pytest.mark.asyncio
async def test_toggle_show_all_no_focus_is_noop():
    """toggle_show_all does nothing when neither DataTable is focused."""
    app = BrowserApp(topics=MANY_TOPICS, categories=MOCK_CATEGORIES, configured_topics=[])
    async with app.run_test() as pilot:
        browser = app.query_one("#browser", BrowserView)
        quiz_table = app.query_one("#quiz-topic-table", DataTable)
        code_table = app.query_one("#coding-category-table", DataTable)
        # Move focus away from both DataTables
        app.set_focus(None)
        await pilot.pause()
        quiz_before = quiz_table.row_count
        code_before = code_table.row_count
        browser.toggle_show_all()
        assert quiz_table.row_count == quiz_before
        assert code_table.row_count == code_before
