from types import SimpleNamespace
from typing import Any

import pytest
from pytest import MonkeyPatch


def test_detail_screen_updates_section_detail_view(tui_modules: SimpleNamespace) -> None:
    snapshot = tui_modules.cli_tui_app.DetailPageSnapshot(
        title='Jobs',
        subtitle='subtitle',
        sections=[
            tui_modules.cli_tui_adapters.DetailSectionSnapshot(title='Section A', status='ok', lines=['line a']),
            tui_modules.cli_tui_adapters.DetailSectionSnapshot(title='Section B', status='warn', lines=['line b']),
        ],
    )
    screen = tui_modules.cli_tui_detail.DetailScreen(
        snapshot,
        env='dev',
        active_view='jobs',
        navigation_items=tui_modules.cli_tui_app.NAVIGATION_ITEMS,
        refreshed_at='2026-04-30 10:00:00',
    )

    recorded_sections: list[object] = []

    class FakeSectionDetailView:
        def show_section(self, section: object, query: str = '') -> None:
            del query
            recorded_sections.append(section)

    screen.query_one = lambda widget_type: FakeSectionDetailView()  # type: ignore[method-assign]

    screen._update_selected_section(1)

    assert screen.selected_section_index == 1
    assert recorded_sections
    assert recorded_sections[0].title == 'Section B'


def test_detail_screen_search_submit_remembers_and_refreshes(
    monkeypatch: MonkeyPatch,
    tui_modules: SimpleNamespace,
) -> None:
    snapshot = tui_modules.cli_tui_app.DetailPageSnapshot(
        title='数据库',
        subtitle='subtitle',
        sections=[
            tui_modules.cli_tui_adapters.DetailSectionSnapshot(title='历史版本', status='ok', lines=['line a']),
        ],
        search=tui_modules.cli_tui_search.PageSearchContext(
            placeholder='按 revision 搜索',
            query='',
            suggestions=['head', 'base'],
        ),
    )
    screen = tui_modules.cli_tui_detail.DetailScreen(
        snapshot,
        env='dev',
        active_view='database',
        navigation_items=tui_modules.cli_tui_app.NAVIGATION_ITEMS,
        refreshed_at='2026-04-30 10:00:00',
    )

    recorded_queries: list[tuple[str, str]] = []
    refresh_calls: list[str] = []
    fake_app = SimpleNamespace(
        remember_browser_query=lambda view_key, query: recorded_queries.append((view_key, query)),
        action_refresh_current_view=lambda: refresh_calls.append('refresh'),
    )
    monkeypatch.setattr(tui_modules.cli_tui_detail.DetailScreen, 'app', property(lambda self: fake_app))

    screen._handle_search_submitted('head')

    assert recorded_queries == [('database', 'head')]
    assert refresh_calls == ['refresh']


def test_detail_screen_clear_search_remembers_empty_and_refreshes(
    monkeypatch: MonkeyPatch,
    tui_modules: SimpleNamespace,
) -> None:
    snapshot = tui_modules.cli_tui_app.DetailPageSnapshot(
        title='数据库',
        subtitle='subtitle',
        sections=[
            tui_modules.cli_tui_adapters.DetailSectionSnapshot(title='历史版本', status='ok', lines=['line a']),
        ],
        search=tui_modules.cli_tui_search.PageSearchContext(
            placeholder='按 revision 搜索',
            query='head',
            suggestions=['head', 'base'],
        ),
    )
    screen = tui_modules.cli_tui_detail.DetailScreen(
        snapshot,
        env='dev',
        active_view='database',
        navigation_items=tui_modules.cli_tui_app.NAVIGATION_ITEMS,
        refreshed_at='2026-04-30 10:00:00',
    )

    recorded_queries: list[tuple[str, str]] = []
    refresh_calls: list[str] = []
    fake_app = SimpleNamespace(
        remember_browser_query=lambda view_key, query: recorded_queries.append((view_key, query)),
        action_refresh_current_view=lambda: refresh_calls.append('refresh'),
    )
    monkeypatch.setattr(tui_modules.cli_tui_detail.DetailScreen, 'app', property(lambda self: fake_app))

    screen.action_clear_search()

    assert recorded_queries == [('database', '')]
    assert refresh_calls == ['refresh']


@pytest.mark.asyncio
async def test_detail_screen_execute_external_action_suspends_app(
    monkeypatch: MonkeyPatch,
    tui_modules: SimpleNamespace,
) -> None:
    snapshot = tui_modules.cli_tui_app.DetailPageSnapshot(
        title='数据库',
        subtitle='subtitle',
        sections=[
            tui_modules.cli_tui_adapters.DetailSectionSnapshot(title='迁移版本', status='ok', lines=['line a']),
        ],
    )
    screen = tui_modules.cli_tui_detail.DetailScreen(
        snapshot,
        env='dev',
        active_view='database',
        navigation_items=tui_modules.cli_tui_app.NAVIGATION_ITEMS,
        refreshed_at='2026-04-30 10:00:00',
    )
    action = tui_modules.cli_tui_detail.TUI_ACTION_REGISTRY.resolve_detail_action(
        view_key='database',
        slot='global',
        env='dev',
    )
    assert action is not None

    recorded_suspend: list[str] = []

    class DummySuspend:
        def __enter__(self) -> None:
            recorded_suspend.append('enter')

        def __exit__(
            self,
            exc_type: type[BaseException] | None,
            exc: BaseException | None,
            tb: Any,
        ) -> None:
            del exc_type, exc, tb
            recorded_suspend.append('exit')

    def build_suspend() -> DummySuspend:
        return DummySuspend()

    def refresh_current_view() -> None:
        pass

    fake_app = SimpleNamespace(
        suspend=build_suspend,
        action_refresh_current_view=refresh_current_view,
    )
    monkeypatch.setattr(tui_modules.cli_tui_detail.DetailScreen, 'app', property(lambda self: fake_app))
    monkeypatch.setattr(
        tui_modules.cli_tui_interactions,
        'TUI_ACTION_EXECUTION_SERVICE',
        SimpleNamespace(
            execute_external=lambda spec: tui_modules.cli_tui_detail.TuiActionResult(
                spec=spec,
                external_exit_code=0,
                external_message='外部交互命令已执行完成',
            ),
            build_result_lines=lambda result: [],
        ),
    )
    monkeypatch.setattr(screen, 'notify', lambda *args, **kwargs: None)

    await screen._execute_action(action)

    assert recorded_suspend == ['enter', 'exit']


@pytest.mark.asyncio
async def test_detail_screen_execute_nested_json_action_without_suspend(
    monkeypatch: MonkeyPatch,
    tui_modules: SimpleNamespace,
) -> None:
    snapshot = tui_modules.cli_tui_app.DetailPageSnapshot(
        title='传输加密',
        subtitle='subtitle',
        sections=[
            tui_modules.cli_tui_adapters.DetailSectionSnapshot(title='运行校验', status='ok', lines=['line a']),
        ],
    )
    screen = tui_modules.cli_tui_detail.DetailScreen(
        snapshot,
        env='dev',
        active_view='crypto',
        navigation_items=tui_modules.cli_tui_app.NAVIGATION_ITEMS,
        refreshed_at='2026-04-30 10:00:00',
    )
    action = tui_modules.cli_tui_detail.TUI_ACTION_REGISTRY.resolve_detail_action(
        view_key='crypto',
        slot='global',
        env='dev',
    )
    assert action is not None
    assert action.execution_mode == 'nested_json'

    suspend_calls: list[str] = []
    execute_calls: list[tuple[object, str]] = []

    class DummySuspend:
        def __enter__(self) -> None:
            suspend_calls.append('enter')

        def __exit__(
            self,
            exc_type: type[BaseException] | None,
            exc: BaseException | None,
            tb: Any,
        ) -> None:
            del exc_type, exc, tb
            suspend_calls.append('exit')

    def build_suspend() -> DummySuspend:
        return DummySuspend()

    def refresh_current_view() -> None:
        pass

    fake_app = SimpleNamespace(
        suspend=build_suspend,
        action_refresh_current_view=refresh_current_view,
    )
    monkeypatch.setattr(tui_modules.cli_tui_detail.DetailScreen, 'app', property(lambda self: fake_app))
    monkeypatch.setattr(
        tui_modules.cli_tui_interactions,
        'TUI_ACTION_EXECUTION_SERVICE',
        SimpleNamespace(
            execute=lambda spec, env: (
                execute_calls.append((spec, env))
                or tui_modules.cli_tui_detail.TuiActionResult(
                    spec=spec,
                    payload={'ok': True, 'message': '轮换预演完成'},
                )
            ),
            build_result_lines=lambda result: [],
        ),
    )
    monkeypatch.setattr(screen, 'notify', lambda *args, **kwargs: None)

    await screen._execute_action(action)

    assert suspend_calls == []
    assert execute_calls == [(action, 'dev')]


def test_detail_screen_support_builds_summary_actions_and_fallbacks(
    tui_modules: SimpleNamespace,
) -> None:
    support = tui_modules.cli_tui_detail.DetailScreenSupport()
    snapshot = tui_modules.cli_tui_app.DetailPageSnapshot(
        title='数据库',
        subtitle='subtitle',
        sections=[
            tui_modules.cli_tui_adapters.DetailSectionSnapshot(title='迁移版本', status='ok', lines=['line a']),
            tui_modules.cli_tui_adapters.DetailSectionSnapshot(title='Heads 状态', status='warn', lines=['line b']),
        ],
        search=tui_modules.cli_tui_search.PageSearchContext(
            placeholder='按 revision 搜索',
            query='head',
            suggestions=['head'],
        ),
    )

    summary = support.build_summary_text(snapshot, 'database')
    query = support.current_search_query(snapshot)
    action = support.resolve_action(active_view='database', slot='global', env='dev')
    empty_section = support.build_empty_section()

    assert '2 个分区' in summary
    assert query == 'head'
    assert action is not None
    assert action.command_args[:2] == ('wizard', 'db-upgrade')
    assert empty_section.title == tui_modules.cli_tui_copy.TUI_COPY.build_detail_empty_section_copy('title')


def test_detail_screen_focus_service_moves_and_scrolls_between_focus_targets(
    tui_modules: SimpleNamespace,
) -> None:
    focus_service = tui_modules.cli_tui_detail.DetailScreenFocusService()
    focused: list[str] = []
    sidebar = SimpleNamespace(focus=lambda: focused.append('sidebar'))
    sections = SimpleNamespace(focus=lambda: focused.append('sections'))
    detail = SimpleNamespace(focus=lambda: focused.append('detail'))
    workspace_main = object()
    fake_app = SimpleNamespace(focused=None)
    fake_screen = SimpleNamespace(
        app=fake_app,
        query_one=lambda selector, widget_type=None: {
            tui_modules.cli_tui_widgets.WorkspaceSidebar: sidebar,
            tui_modules.cli_tui_widgets.SectionNavigator: sections,
            tui_modules.cli_tui_widgets.SectionDetailView: detail,
            '#workspace-main': workspace_main,
        }[selector],
    )

    focus_service.move_focus(fake_screen, 1)
    fake_app.focused = sections
    focus_service.move_focus(fake_screen, 1)
    fake_app.focused = object()
    scroll_target = focus_service.get_scroll_target(fake_screen)

    assert focused == ['sidebar', 'detail']
    assert scroll_target is workspace_main


def test_detail_screen_unmount_cancels_action_task(tui_modules: SimpleNamespace) -> None:
    snapshot = tui_modules.cli_tui_app.DetailPageSnapshot(
        title='数据库',
        subtitle='subtitle',
        sections=[],
    )
    screen = tui_modules.cli_tui_detail.DetailScreen(
        snapshot,
        env='dev',
        active_view='database',
        navigation_items=tui_modules.cli_tui_app.NAVIGATION_ITEMS,
        refreshed_at='2026-04-30 10:00:00',
    )

    cancelled: list[str] = []

    class DummyTask:
        def done(self) -> bool:
            return False

        def cancel(self) -> None:
            cancelled.append('action')

    screen._action_task = DummyTask()  # type: ignore[assignment]

    screen.on_unmount()

    assert cancelled == ['action']


@pytest.mark.asyncio
async def test_detail_screen_scrolls_in_small_viewport(tui_modules: SimpleNamespace) -> None:
    thin_scrollbar_size = 1
    app = tui_modules.cli_tui_app.ShierfengTuiApp('dev')
    app.action_show_dashboard = lambda: None  # type: ignore[method-assign]
    app.current_view = 'app'
    snapshot = tui_modules.cli_tui_app.DetailPageSnapshot(
        title='应用',
        subtitle='超长详情',
        sections=[
            tui_modules.cli_tui_adapters.DetailSectionSnapshot(
                title='配置总览',
                status='warn',
                lines=[f'第{i:02d}行 内容很长 内容很长 内容很长 内容很长' for i in range(1, 40)],
            )
        ],
    )
    screen = app.screen_factory.build(
        snapshot=snapshot,
        env=app.env,
        active_view=app.current_view,
        navigation_items=tui_modules.cli_tui_app.NAVIGATION_ITEMS,
        action_feedback_lines=app.get_action_feedback_lines(app.current_view),
    )

    async with app.run_test(size=(80, 24)) as pilot:
        app.screen_navigator.show(screen)
        await pilot.pause()
        await pilot.pause()

        main = app.screen.query_one('#workspace-main')
        detail_body = app.screen.query_one('#detail-body')
        detail_view = app.screen.query_one(tui_modules.cli_tui_widgets.SectionDetailView)

        assert main.styles.scrollbar_size_vertical == thin_scrollbar_size
        assert main.styles.scrollbar_size_horizontal == thin_scrollbar_size
        assert main.virtual_size.height > main.size.height
        assert detail_body.styles.scrollbar_size_vertical == thin_scrollbar_size
        assert detail_body.styles.scrollbar_size_horizontal == thin_scrollbar_size
        assert detail_view.styles.scrollbar_size_vertical == thin_scrollbar_size
        assert detail_view.styles.scrollbar_size_horizontal == thin_scrollbar_size
