"""UPnP action bar widget."""

from __future__ import annotations

from typing import Literal

from textual.app import ComposeResult
from textual.containers import Horizontal
from textual.dom import NoMatches
from textual.message import Message
from textual.reactive import var
from textual.widget import Widget
from textual.widgets import Button, Switch

from flux_networking_shared.tui.widgets.label_switch import LabelSwitch


class UpnpActionBar(Horizontal, can_focus=True):
    """Action bar for UPnP port reservation controls.

    Contains Cancel, Reserve buttons and an Override switch for
    selecting ports that are already in use.
    """

    class CancelPressed(Message):
        """Posted when Cancel button is pressed."""

    class ReservePressed(Message):
        """Posted when Reserve button is pressed."""

    class OverrideChanged(Message):
        """Posted when Override switch is toggled."""

        def __init__(self, override_enabled: bool) -> None:
            super().__init__()
            self.override_enabled = override_enabled

    DEFAULT_CSS = """
        UpnpActionBar {
            height: auto;
            align: center middle;
            padding: 1;
        }

        UpnpActionBar Button {
            margin: 0 1;
        }

        UpnpActionBar LabelSwitch {
            margin-left: 2;
        }
    """

    override_enabled = var(False)
    cancel_disabled = var(True)
    reserve_disabled = var(True)

    def __init__(
        self,
        override_enabled: bool = False,
        cancel_disabled: bool = True,
        reserve_disabled: bool = True,
    ) -> None:
        """Initialize the action bar.

        Args:
            override_enabled: Initial state of override switch
            cancel_disabled: Whether cancel button starts disabled
            reserve_disabled: Whether reserve button starts disabled
        """
        super().__init__()

        self._override_enabled = override_enabled
        self._cancel_disabled = cancel_disabled
        self._reserve_disabled = reserve_disabled

        self.switch = LabelSwitch(
            "Override", value=self._override_enabled, id="override"
        )

    def compose(self) -> ComposeResult:
        yield Button("Cancel", disabled=self._cancel_disabled, id="cancel-port")
        yield Button("Reserve", disabled=self._reserve_disabled, id="reserve-port")
        yield self.switch

    def on_mount(self) -> None:
        self.override_enabled = self._override_enabled
        self.cancel_disabled = self._cancel_disabled
        self.reserve_disabled = self._reserve_disabled

    def focus_button(self, button_id: Literal["cancel-port", "reserve-port"]) -> None:
        """Focus a specific button by ID.

        Args:
            button_id: The button ID to focus
        """
        try:
            button = self.query_one(f"#{button_id}", Button)
        except NoMatches:
            return

        button.focus()

    def update_switch_prevent(self, value: bool) -> None:
        """Update switch value without triggering Changed event.

        Args:
            value: New switch value
        """
        with self.prevent(Switch.Changed):
            self.switch.value = value

    def watch_cancel_disabled(self, old: bool, new: bool) -> None:
        if old == new:
            return

        self._cancel_disabled = new

        try:
            button = self.query_one("#cancel-port", Button)
        except NoMatches:
            return

        button.disabled = new

    def watch_reserve_disabled(self, old: bool, new: bool) -> None:
        if old == new:
            return

        self._reserve_disabled = new

        try:
            button = self.query_one("#reserve-port", Button)
        except NoMatches:
            return

        button.disabled = new

    def watch_override_enabled(self, old: bool, new: bool) -> None:
        if old == new:
            return

        self._override_enabled = new

        try:
            switch = self.query_one("#override", LabelSwitch)
        except NoMatches:
            return

        switch.disabled = new

    def on_button_pressed(self, event: Button.Pressed) -> None:
        """Handle button presses."""
        event.stop()

        if event.button.id == "cancel-port":
            self.post_message(self.CancelPressed())
        elif event.button.id == "reserve-port":
            self.post_message(self.ReservePressed())

    def on_switch_changed(self, event: Switch.Changed) -> None:
        """Handle switch changes."""
        event.stop()
        self.post_message(self.OverrideChanged(event.value))

    def on_focus(self) -> None:
        """Focus the first focusable child when this widget receives focus."""

        def find_first_focusable(widget: Widget, rev: bool) -> Widget | None:
            children = widget.children[::-1] if rev else widget.children

            for child in children:
                if child.can_focus and not child.disabled:
                    return child

                if focusable := find_first_focusable(child, rev):
                    return focusable

            return None

        focusable = find_first_focusable(self, False)

        if focusable:
            focusable.focus()
