"""Package setup screen for missing Python drivers."""

from __future__ import annotations

from collections.abc import Callable
from typing import cast

from textual.app import ComposeResult
from textual.binding import Binding
from textual.screen import ModalScreen
from textual.widgets import OptionList, Static
from textual.widgets.option_list import Option

from sqlit.domains.connections.app.install_strategy import InstallOption
from sqlit.domains.connections.providers.exceptions import MissingDriverError
from sqlit.shared.app.services import InstallStrategyProvider
from sqlit.shared.ui.widgets import Dialog


class PackageSetupScreen(ModalScreen):
    """Screen that shows install options for a missing Python package."""

    BINDINGS = [
        Binding("enter", "install", "Install", priority=True),
        Binding("y", "yank", "Copy"),
        Binding("escape", "cancel", "Cancel", priority=True),
    ]

    CSS = """
    PackageSetupScreen {
        align: center middle;
        background: transparent;
    }

    #package-dialog {
        width: 80;
        height: auto;
        max-height: 90%;
    }

    #package-message {
        margin-bottom: 1;
    }

    #install-options {
        height: auto;
        max-height: 12;
        border: solid $primary-darken-2;
        background: $surface-darken-1;
        margin-top: 1;
    }

    #install-options > .option-list--option {
        padding: 0 1;
    }

    #install-options > .option-list--option-highlighted {
        background: $primary-darken-1;
    }
    """

    def __init__(
        self,
        error: MissingDriverError,
        *,
        on_success: Callable[[], None] | None = None,
    ):
        super().__init__()
        self.error = error
        self._on_success = on_success
        self._install_options: list[InstallOption] = []
        self._install_strategy: InstallStrategyProvider | None = None

    def _get_install_strategy(self) -> InstallStrategyProvider:
        if self._install_strategy is not None:
            return self._install_strategy
        services = getattr(self.app, "services", None)
        if services is not None:
            strategy = getattr(services, "install_strategy", None)
            if strategy is not None:
                self._install_strategy = cast(InstallStrategyProvider, strategy)
                return self._install_strategy
        from sqlit.shared.core.system_probe import SystemProbe

        self._install_strategy = InstallStrategyProvider(SystemProbe())
        assert self._install_strategy is not None
        return self._install_strategy

    def compose(self) -> ComposeResult:
        has_import_error = bool(getattr(self.error, "import_error", None))
        title = "Driver import failed" if has_import_error else "Missing package"

        message = (
            f"This connection requires the [bold]{self.error.driver_name}[/] driver.\n"
            f"Package: [bold]{self.error.package_name}[/]\n\n"
            f"[bold]Install the driver using your preferred package manager:[/]"
        )

        shortcuts = [("Install", "<enter>"), ("Copy", "y"), ("Cancel", "<esc>")]

        strategy = self._get_install_strategy()
        self._install_options = strategy.get_install_options(
            extra_name=self.error.extra_name,
            package_name=self.error.package_name,
        )

        with Dialog(id="package-dialog", title=title, shortcuts=shortcuts):
            yield Static(message, id="package-message")

            detected = strategy.detect_install_method()
            option_list = OptionList(id="install-options")
            for opt in self._install_options:
                if opt.label == detected:
                    label = f"[bold]{opt.label:<8}[/] {opt.command}  [dim](Detected)[/]"
                else:
                    label = f"[bold]{opt.label:<8}[/] {opt.command}"
                option_list.add_option(Option(label, id=opt.label))
            option_list.highlighted = 0
            yield option_list

    def on_mount(self) -> None:
        self.query_one("#install-options", OptionList).focus()

    def _get_selected_option(self) -> str | None:
        """Get the command for the currently selected option."""
        option_list = self.query_one("#install-options", OptionList)
        highlighted = option_list.highlighted
        if highlighted is not None and highlighted < len(self._install_options):
            return self._install_options[highlighted].command
        return None

    def action_install(self) -> None:
        from .install_progress import InstallProgressScreen

        command = self._get_selected_option()
        if command:

            def on_install_complete(success: bool | None) -> None:
                if success and self._on_success:
                    # Caller handles success (e.g., connection screen caches form and restarts)
                    self._on_success()
                    self.dismiss(None)
                elif success:
                    # Default: show notification and restart
                    self.app.notify(
                        f"{self.error.driver_name} installed successfully. Restarting...",
                        timeout=3,
                    )
                    self.dismiss(None)
                    restart = getattr(self.app, "restart", None)
                    if callable(restart):
                        restart()
                else:
                    self.dismiss(None)

            self.app.push_screen(
                InstallProgressScreen(self.error.package_name, command),
                on_install_complete,
            )

    def action_yank(self) -> None:
        from sqlit.shared.ui.widgets import flash_widget

        command = self._get_selected_option()
        if command:
            copy_fn = getattr(self.app, "_copy_text", None)
            if callable(copy_fn):
                copy_fn(command)
            else:
                self.app.copy_to_clipboard(command)
            flash_widget(self.query_one("#install-options", OptionList))

    def action_cancel(self) -> None:
        self.dismiss(None)
