"""Textual pilot tests for TUI screens.

These tests render the actual TUI screens headlessly and exercise wizard
navigation to catch runtime errors (bad mount calls, missing widgets, etc.)
that unit tests on dataclasses alone cannot detect.
"""

from __future__ import annotations

import textwrap
from pathlib import Path
from unittest.mock import AsyncMock, patch

import pytest
import yaml

from textual.widgets import OptionList, Button, Input, RadioSet, SelectionList

from tui.app import LinuxAutomationApp


# ── helpers ───────────────────────────────────────────────────────


def _make_app(tmp_config_dir: Path) -> LinuxAutomationApp:
    """Create an app instance with a temporary config directory."""
    return LinuxAutomationApp(
        config_dir=tmp_config_dir,
        user_config_dir="",
    )


# ── Main menu ─────────────────────────────────────────────────────


class TestMainMenu:
    """Test the main menu screen loads and navigates."""

    @pytest.mark.asyncio
    async def test_main_menu_renders(self, tmp_config_dir: Path) -> None:
        """Main menu should render without errors."""
        app = _make_app(tmp_config_dir)
        async with app.run_test() as pilot:
            # The main menu option list should be present
            option_list = app.screen.query_one("#main-option-list", OptionList)
            assert option_list is not None

    @pytest.mark.asyncio
    async def test_navigate_to_build(self, tmp_config_dir: Path) -> None:
        """Pressing 'b' should push the TemplateBuildScreen."""
        app = _make_app(tmp_config_dir)
        async with app.run_test() as pilot:
            await pilot.press("b")
            await pilot.pause()
            from tui.screens.template_build import TemplateBuildScreen
            assert isinstance(app.screen, TemplateBuildScreen)

    @pytest.mark.asyncio
    async def test_navigate_to_deploy(self, tmp_config_dir: Path) -> None:
        """Pressing 'd' should push the VMDeployScreen."""
        app = _make_app(tmp_config_dir)
        async with app.run_test() as pilot:
            with patch(
                "tui.services.proxmox.ProxmoxService.get_templates",
                new_callable=AsyncMock,
                return_value=[],
            ):
                await pilot.press("d")
                await pilot.pause()
                from tui.screens.vm_deploy import VMDeployScreen
                assert isinstance(app.screen, VMDeployScreen)

    @pytest.mark.asyncio
    async def test_navigate_to_manage(self, tmp_config_dir: Path) -> None:
        """Pressing 'm' should push the VMManageScreen."""
        app = _make_app(tmp_config_dir)
        async with app.run_test() as pilot:
            with patch(
                "tui.services.proxmox.ProxmoxService.get_all_vms",
                new_callable=AsyncMock,
                return_value=[],
            ):
                await pilot.press("m")
                await pilot.pause()
                from tui.screens.vm_manage import VMManageScreen
                assert isinstance(app.screen, VMManageScreen)


# ── Template build wizard ─────────────────────────────────────────


class TestTemplateBuildWizard:
    """Test the template build wizard step-by-step navigation."""

    @pytest.mark.asyncio
    async def test_step1_distribution_renders(self, tmp_config_dir: Path) -> None:
        """Step 1 should show the distribution option list."""
        app = _make_app(tmp_config_dir)
        async with app.run_test() as pilot:
            await pilot.press("b")
            await pilot.pause()

            option_list = app.screen.query_one("#distro-list", OptionList)
            assert option_list is not None

    @pytest.mark.asyncio
    async def test_full_wizard_walkthrough(self, tmp_config_dir: Path) -> None:
        """Walk through all 7 steps without crashing."""
        app = _make_app(tmp_config_dir)
        async with app.run_test() as pilot:
            await pilot.press("b")
            await pilot.pause()

            from tui.screens.template_build import TemplateBuildScreen
            screen = app.screen
            assert isinstance(screen, TemplateBuildScreen)

            # Step 1: Select distribution (ubuntu)
            distro_list = screen.query_one("#distro-list", OptionList)
            distro_list.action_select()
            await pilot.pause()

            # Step 2: Select version (first available)
            assert screen.step == 1
            version_list = screen.query_one("#version-list", OptionList)
            version_list.action_select()
            await pilot.pause()

            # Step 3: Package profile — accept default and click Next
            assert screen.step == 2
            next_btn = screen.query_one("#next", Button)
            await pilot.click(next_btn)
            await pilot.pause()

            # Step 4: Network config — accept default and click Next
            assert screen.step == 3
            await pilot.click(next_btn)
            await pilot.pause()

            # Step 5: Template config — accept defaults and click Next
            assert screen.step == 4
            await pilot.click(next_btn)
            await pilot.pause()

            # Step 6: Credentials — fill in and click Next
            assert screen.step == 5
            password_input = screen.query_one("#cloudinit-password", Input)
            confirm_input = screen.query_one("#cloudinit-password-confirm", Input)
            password_input.value = "testpass"
            confirm_input.value = "testpass"
            await pilot.click(next_btn)
            await pilot.pause()

            # Step 7: Confirm — should render summary without crashing
            assert screen.step == 6

    @pytest.mark.asyncio
    async def test_back_button_navigates(self, tmp_config_dir: Path) -> None:
        """Back button should go to previous step."""
        app = _make_app(tmp_config_dir)
        async with app.run_test() as pilot:
            await pilot.press("b")
            await pilot.pause()

            from tui.screens.template_build import TemplateBuildScreen
            screen = app.screen
            assert isinstance(screen, TemplateBuildScreen)

            # Select distro to advance to step 1
            distro_list = screen.query_one("#distro-list", OptionList)
            distro_list.action_select()
            await pilot.pause()
            assert screen.step == 1

            # Press back
            back_btn = screen.query_one("#back", Button)
            await pilot.click(back_btn)
            await pilot.pause()
            assert screen.step == 0

    @pytest.mark.asyncio
    async def test_escape_returns_to_menu(self, tmp_config_dir: Path) -> None:
        """Escape should return to main menu."""
        app = _make_app(tmp_config_dir)
        async with app.run_test() as pilot:
            await pilot.press("b")
            await pilot.pause()

            from tui.screens.template_build import TemplateBuildScreen
            assert isinstance(app.screen, TemplateBuildScreen)

            await pilot.press("escape")
            await pilot.pause()

            from tui.screens.main_menu import MainMenuScreen
            assert isinstance(app.screen, MainMenuScreen)

    @pytest.mark.asyncio
    async def test_confirm_step_renders_summary(self, tmp_config_dir: Path) -> None:
        """The confirm step should render all summary fields."""
        app = _make_app(tmp_config_dir)
        async with app.run_test() as pilot:
            await pilot.press("b")
            await pilot.pause()

            from tui.screens.template_build import TemplateBuildScreen
            screen = app.screen
            assert isinstance(screen, TemplateBuildScreen)

            # Pre-populate state to skip to confirm step
            screen.state.distro = "ubuntu"
            screen.state.version = "22.04"
            screen.state.profile = "base"
            screen.state.network_mode = "dhcp"
            screen.state.template_name = "ubuntu-22.04-base"
            screen.state.vm_cores = 2
            screen.state.vm_memory = 2048
            screen.state.vm_disk_size = "10G"
            screen.state.cloudinit_user = "admin"
            screen.state.cloudinit_password = "secret"

            # Jump directly to confirm step
            screen._show_step(6)
            await pilot.pause()

            assert screen.step == 6
            # Should find the summary panel
            summary = screen.query_one(".summary-panel")
            assert summary is not None


# ── VM deploy wizard ──────────────────────────────────────────────


class TestVMDeployWizard:
    """Test the VM deployment wizard."""

    @pytest.mark.asyncio
    async def test_deploy_screen_no_templates(self, tmp_config_dir: Path) -> None:
        """Deploy screen should handle no templates gracefully."""
        app = _make_app(tmp_config_dir)
        async with app.run_test() as pilot:
            with patch(
                "tui.services.proxmox.ProxmoxService.get_templates",
                new_callable=AsyncMock,
                return_value=[],
            ):
                await pilot.press("d")
                await pilot.pause()
                # Allow the async worker to complete
                await pilot.pause()

                from tui.screens.vm_deploy import VMDeployScreen
                assert isinstance(app.screen, VMDeployScreen)

    @pytest.mark.asyncio
    async def test_deploy_wizard_with_templates(self, tmp_config_dir: Path) -> None:
        """Deploy screen with mock templates should render template list."""
        mock_templates = [
            {"vmid": 9200, "name": "ubuntu-22.04-base", "status": "stopped", "template": 1},
            {"vmid": 9201, "name": "rocky-9-base", "status": "stopped", "template": 1},
        ]
        app = _make_app(tmp_config_dir)
        async with app.run_test() as pilot:
            with patch(
                "tui.services.proxmox.ProxmoxService.get_templates",
                new_callable=AsyncMock,
                return_value=mock_templates,
            ):
                await pilot.press("d")
                await pilot.pause()
                await pilot.pause()

                template_list = app.screen.query_one("#template-list", OptionList)
                assert template_list is not None

    @pytest.mark.asyncio
    async def test_deploy_confirm_renders(self, tmp_config_dir: Path) -> None:
        """Deploy confirm step should render summary without crashing."""
        mock_templates = [
            {"vmid": 9200, "name": "ubuntu-22.04-base", "status": "stopped", "template": 1},
        ]
        app = _make_app(tmp_config_dir)
        async with app.run_test() as pilot:
            with patch(
                "tui.services.proxmox.ProxmoxService.get_templates",
                new_callable=AsyncMock,
                return_value=mock_templates,
            ):
                await pilot.press("d")
                await pilot.pause()
                await pilot.pause()

                from tui.screens.vm_deploy import VMDeployScreen
                screen = app.screen
                assert isinstance(screen, VMDeployScreen)

                # Pre-populate state
                screen.state.template_id = 9200
                screen.state.template_name = "ubuntu-22.04-base"
                screen.state.vm_name = "test-vm"
                screen.state.vm_cores = 2
                screen.state.vm_memory = 2048
                screen.state.vm_disk_size = "20G"
                screen.state.network_mode = "dhcp"
                screen.state.clone_type = "linked"
                screen.state.playbooks = ["base-config"]

                # Jump to confirm step (step 4)
                screen._show_step(4)
                await pilot.pause()

                assert screen.step == 4
                summary = screen.query_one(".summary-panel")
                assert summary is not None


# ── VM manage screen ──────────────────────────────────────────────


class TestVMManageScreen:
    """Test the VM management screen."""

    @pytest.mark.asyncio
    async def test_manage_screen_no_vms(self, tmp_config_dir: Path) -> None:
        """Manage screen should handle no VMs gracefully."""
        app = _make_app(tmp_config_dir)
        async with app.run_test() as pilot:
            with patch(
                "tui.services.proxmox.ProxmoxService.get_all_vms",
                new_callable=AsyncMock,
                return_value=[],
            ):
                await pilot.press("m")
                await pilot.pause()
                await pilot.pause()

                from tui.screens.vm_manage import VMManageScreen
                assert isinstance(app.screen, VMManageScreen)

    @pytest.mark.asyncio
    async def test_manage_screen_with_vms(self, tmp_config_dir: Path) -> None:
        """Manage screen with mock VMs should render selection list."""
        mock_vms = [
            {"vmid": 100, "name": "test-vm", "status": "running", "template": 0},
            {"vmid": 9200, "name": "ubuntu-template", "status": "stopped", "template": 1},
        ]
        app = _make_app(tmp_config_dir)
        async with app.run_test() as pilot:
            with patch(
                "tui.services.proxmox.ProxmoxService.get_all_vms",
                new_callable=AsyncMock,
                return_value=mock_vms,
            ):
                await pilot.press("m")
                await pilot.pause()
                await pilot.pause()

                selection_list = app.screen.query_one("#vm-selection", SelectionList)
                assert selection_list is not None

    @pytest.mark.asyncio
    async def test_manage_escape_returns(self, tmp_config_dir: Path) -> None:
        """Escape from manage screen should return to main menu."""
        app = _make_app(tmp_config_dir)
        async with app.run_test() as pilot:
            with patch(
                "tui.services.proxmox.ProxmoxService.get_all_vms",
                new_callable=AsyncMock,
                return_value=[],
            ):
                await pilot.press("m")
                await pilot.pause()

                await pilot.press("escape")
                await pilot.pause()

                from tui.screens.main_menu import MainMenuScreen
                assert isinstance(app.screen, MainMenuScreen)


# ── Dialog widgets ────────────────────────────────────────────────


class TestDialogs:
    """Test dialog widget rendering."""

    @pytest.mark.asyncio
    async def test_message_dialog_renders(self, tmp_config_dir: Path) -> None:
        """MessageDialog should render and dismiss on button press."""
        app = _make_app(tmp_config_dir)
        async with app.run_test() as pilot:
            # Push build-all which shows a MessageDialog
            await pilot.press("a")
            await pilot.pause()

            ok_btn = app.screen.query_one("#ok", Button)
            assert ok_btn is not None

            await pilot.click(ok_btn)
            await pilot.pause()

            from tui.screens.main_menu import MainMenuScreen
            assert isinstance(app.screen, MainMenuScreen)
