"""Network interface group widget."""

from __future__ import annotations

from textual import on
from textual.app import ComposeResult
from textual.containers import Grid
from textual.events import DescendantFocus, Key
from textual.message import Message
from textual.reactive import var

from flux_networking_shared.tui.messages import FocusTabsRequested
from flux_networking_shared.tui.widgets.interface import Interface


class FocusButtonsRequested(Message):
    """Request focus on buttons container."""


class InterfaceGroup(Grid):
    """Grid container for network interface widgets."""

    class InterfaceModalRequested(Message):
        """Request to open interface configuration modal."""

        def __init__(self, interface: Interface, in_use_vlans: list[int]) -> None:
            super().__init__()
            self.interface = interface
            self.in_use_vlans = in_use_vlans

    class NoInterfacesModalRequested(Message):
        """Request to show 'no interfaces' dialog."""

    focused_child: var[int | str] = var("")

    DEFAULT_CSS = """
    InterfaceGroup {
        grid-size: 2;
        grid-gutter: 1;
    }
    """

    def __init__(self, interfaces: list[Interface] | None = None):
        """Initialize the interface group.

        Args:
            interfaces: List of Interface widgets to display
        """
        super().__init__()
        self.interfaces = interfaces or []

    @property
    def last_interface(self) -> bool:
        """Check if focused on last interface."""
        if isinstance(self.focused_child, str):
            return False
        return self.focused_child + 1 == len(self.children)

    @property
    def first_interface(self) -> bool:
        """Check if focused on first interface."""
        if isinstance(self.focused_child, str):
            return True
        return self.focused_child == 0

    def get_child_interface_names(self, interface: Interface) -> list[str]:
        """Get names of child VLAN interfaces.

        Args:
            interface: Parent interface

        Returns:
            List of child interface names
        """
        return [
            x.interface_name
            for x in self.interfaces
            if x.interface_type == "vlan" and x.parent_ifindex == interface.ifindex
        ]

    def update_from_dict(self, interface_data: dict) -> None:
        """Update an interface from dictionary data.

        Args:
            interface_data: Dictionary with interface data
        """
        name = interface_data.get("name")
        if not name:
            return

        interface = next(
            (x for x in self.interfaces if x.interface_name == name),
            None,
        )

        if not interface:
            # Create new interface
            interface = Interface.from_dict(interface_data)
            interface.id = f"int-{len(self.interfaces)}"
            self.interfaces.append(interface)

            if self.is_mounted:
                self.mount(interface)

            return

        # Update existing interface
        interface.update_from_dict(interface_data)

    def id_to_interface(self, id: int | str) -> Interface:
        """Get interface by numeric ID.

        Args:
            id: Interface ID number

        Returns:
            Interface widget
        """
        child: Interface = self.get_child_by_id(f"int-{id}")  # type: ignore
        return child

    def compose(self) -> ComposeResult:
        """Compose the interface grid."""
        yield from self.interfaces

    def in_use_vlans(self, interface: Interface) -> list[int]:
        """Get VLAN IDs already in use by this interface.

        Args:
            interface: Parent interface

        Returns:
            List of VLAN IDs
        """
        return [
            x.vlan
            for x in self.interfaces
            if x.parent_ifindex == interface.ifindex and x.vlan is not None
        ]

    async def add_vlan_subinterface(
        self, parent: Interface, vlan_id: int, set_loading: bool = False
    ) -> Interface:
        """Add a new VLAN subinterface.

        Args:
            parent: Parent interface
            vlan_id: VLAN ID
            set_loading: Whether to show loading indicator

        Returns:
            The new VLAN interface widget
        """
        vlan_interface = Interface(
            type="vlan",
            name=f"{parent.interface_name}.{vlan_id}",
            state="DOWN",
            ifindex=-1,
            mac_addr=parent.mac_addr,
            ip_allocation="disabled",
            network_vendor="",
            network_type="",
            vlan=vlan_id,
            parent_ifindex=parent.ifindex,
            id=f"int-{len(self.interfaces)}",
        )
        vlan_interface.loading = set_loading

        self.interfaces.append(vlan_interface)

        index = len(self.interfaces) - 1

        await self.mount(vlan_interface)
        self.set_child_focus(first=False, index=index)

        return vlan_interface

    def set_child_focus(self, first: bool = True, index: int | None = None) -> None:
        """Set focus to a child interface.

        Args:
            first: If True, focus first interface
            index: Specific index to focus
        """
        if first:
            idx = 0
        elif index is not None:
            idx = index
        else:
            idx = len(self.children) - 1

        self.focused_child = idx

    def watch_focused_child(self, id: int | str) -> None:
        """Focus the child when focused_child changes."""
        if id == "":
            return

        interface = self.id_to_interface(id)
        interface.focus()

    def blur_children(self) -> None:
        """Blur all children."""
        self.focused_child = ""

    def on_descendant_focus(self, event: DescendantFocus) -> None:
        """Handle descendant focus events."""
        if self.focused_child == "" and event.widget.id:
            try:
                self.focused_child = int(event.widget.id.split("-")[-1])
            except (ValueError, IndexError):
                pass

    @on(Interface.InterfaceClicked)
    def on_interface_clicked(self, event: Interface.InterfaceClicked) -> None:
        """Handle interface click."""
        self.post_message(
            self.InterfaceModalRequested(
                event.interface, self.in_use_vlans(event.interface)
            )
        )

    def on_key(self, event: Key) -> None:
        """Handle keyboard navigation."""
        key = event.name

        if key not in [
            "left",
            "up",
            "right",
            "down",
            "tab",
            "shift_tab",
            "enter",
            "space",
        ]:
            return

        if (
            (not self.last_interface and key == "tab")
            or (not self.first_interface and key == "shift_tab")
            or key == "down"
            or key == "up"
        ):
            event.stop()

        interface_count = len(self.children)
        if interface_count == 0:
            return

        row_count = (interface_count // 2) + (interface_count % 2)
        current_focused = (
            self.focused_child if isinstance(self.focused_child, int) else 0
        )
        current_row = current_focused // 2

        if key == "tab":
            if self.last_interface:
                self.focused_child = ""
                self.post_message(FocusButtonsRequested())
            else:
                self.focused_child = current_focused + 1
        elif key == "shift_tab":
            if self.first_interface:
                self.focused_child = ""
                self.post_message(FocusTabsRequested())
            else:
                self.focused_child = current_focused - 1
        elif key == "right":
            self.focused_child = (current_focused + 1) % interface_count
        elif key == "left":
            self.focused_child = (
                current_focused + interface_count - 1
            ) % interface_count
        elif key == "up":
            if current_row == 0:
                self.focused_child = ""
                self.post_message(FocusTabsRequested())
            else:
                self.focused_child = current_focused - 2
        elif key == "down":
            if row_count > current_row + 1:
                self.focused_child = min(interface_count - 1, current_focused + 2)
            else:
                self.focused_child = ""
                self.post_message(FocusButtonsRequested())

        elif key in ["enter", "space"]:
            interface = self.id_to_interface(current_focused)
            self.post_message(
                self.InterfaceModalRequested(interface, self.in_use_vlans(interface))
            )
