"""Sort controller for porTUI port table."""

from __future__ import annotations

import ipaddress
from typing import Callable

from portui.models import PortInfo


def _ip_sort_key(p: PortInfo) -> tuple:
    """Numerical IP sort key — IPv4 before IPv6, then by address value."""
    try:
        addr = ipaddress.ip_address(p.ip)
        return (0, addr.version, addr)
    except (ValueError, TypeError):
        return (1, 0, p.ip or "")


# Dispatch table: column key -> key function for sorted()
_SORT_KEYS: dict[str, Callable[[PortInfo], object]] = {
    "port": lambda p: p.port,
    "ip": _ip_sort_key,
    "proto": lambda p: p.protocol,
    "process": lambda p: p.process_name.lower(),
    "pid": lambda p: p.pid,
    "user": lambda p: p.username.lower(),
    "state": lambda p: (p.state or "").lower(),
    "cmdline": lambda p: p.cmdline.lower(),
}

# Ordered list of column keys used to cycle through sort columns.
SORT_COLUMNS: list[str] = list(_SORT_KEYS.keys())


class SortController:
    """Manages the active sort column and applies sorting to port lists."""

    def __init__(self) -> None:
        self.column: str | None = None
        self.ascending: bool = True

    def cycle(self) -> None:
        """Advance to the next sort column (wraps back to None after the last)."""
        if self.column is None:
            self.column = SORT_COLUMNS[0]
            self.ascending = True
        elif self.column in SORT_COLUMNS:
            idx = SORT_COLUMNS.index(self.column)
            if idx >= len(SORT_COLUMNS) - 1:
                self.column = None
            else:
                self.column = SORT_COLUMNS[idx + 1]
        else:
            self.column = None

    def apply(self, ports: list[PortInfo]) -> list[PortInfo]:
        """Return *ports* sorted by the current column, or by port number if
        no column is active."""
        if self.column is None:
            return sorted(ports, key=lambda p: p.port)
        key_fn = _SORT_KEYS.get(self.column)
        if key_fn is None:
            return list(ports)
        return sorted(ports, key=key_fn, reverse=not self.ascending)  # type: ignore[arg-type]
