"""Layer 3 address configuration widget."""

from __future__ import annotations

from textual import on
from textual.app import ComposeResult
from textual.binding import Binding
from textual.containers import Grid
from textual.message import Message
from textual.reactive import var
from textual.widgets import Label

from flux_networking_shared.tui.validators.network_validator import NetworkValidator
from flux_networking_shared.tui.widgets.labels import InvalidLabel, WarningLabel
from flux_networking_shared.tui.widgets.validate_blur_input import ValidateBlurInput


class Layer3Builder(Grid):
    """Form for configuring IP address settings.

    Collects subnet, IP address, gateway, and DNS server information
    with real-time validation.
    """

    class Layer3StateChanged(Message):
        """Posted when the form validity state changes."""

        def __init__(self, layer3: Layer3Builder, valid: bool):
            super().__init__()
            self.layer3 = layer3
            self.valid = valid

    DEFAULT_CSS = """
        Layer3Builder {
            grid-size: 4;
            grid-columns: auto 1fr auto 1fr;
            grid-gutter: 1;
            height: auto;
            padding: 1;
        }

        Layer3Builder .text-label {
            height: 3;
            content-align: right middle;
            padding: 0 1;
        }
    """

    BINDINGS = [Binding("escape", "dismiss", "Dismiss", show=False)]

    subnet = var("")
    address = var("")
    gateway = var("")
    dns = var("")

    complete = var(False)

    @property
    def dns_as_list(self) -> list[str]:
        """Get DNS servers as a list."""
        return list(filter(None, (x.strip() for x in self.dns.split(","))))

    def __init__(
        self, subnet: str, address: str, default_gateway: str, resolved_dns: str
    ) -> None:
        """Initialize the Layer3Builder.

        Args:
            subnet: Initial subnet value (CIDR notation)
            address: Initial IP address
            default_gateway: Initial gateway address
            resolved_dns: Initial DNS servers (comma-separated)
        """
        super().__init__()

        self._subnet = subnet
        self._address = address
        self._gateway = default_gateway
        self._dns = resolved_dns

        self.address_validator = NetworkValidator("address", self.subnet)

    def clear_values(self) -> None:
        """Clear all form values."""
        self.subnet = ""
        self.address = ""
        self.gateway = ""
        self.dns = ""

        inputs = self.query(ValidateBlurInput)
        invalid_labels = self.query(InvalidLabel)

        for invalid_label in invalid_labels:
            invalid_label.update("")
            invalid_label.visible = False

        for input in inputs:
            input.value = ""
            input.remove_class("-valid")
            input.remove_class("-invalid")

    def get_selected_values(self) -> tuple[str, str, str, list[str]]:
        """Get the current form values.

        Returns:
            Tuple of (subnet, address, gateway, dns_servers)
        """
        return self.subnet, self.address, self.gateway, self.dns_as_list

    def watch_address(self, old: str, new: str) -> None:
        if old == new:
            return

        address = self.query_one("#address-input", ValidateBlurInput)
        address.value = new

    def watch_gateway(self, old: str, new: str) -> None:
        if old == new:
            return

        gateway = self.query_one("#gateway-input", ValidateBlurInput)
        gateway.value = new

    def watch_dns(self, old: str, new: str) -> None:
        if old == new:
            return

        dns = self.query_one("#dns-input", ValidateBlurInput)
        dns.value = new

    def watch_subnet(self, old: str, new: str) -> None:
        if old == new:
            return

        self.address_validator.subnet = new
        subnet = self.query_one("#subnet-input", ValidateBlurInput)
        subnet.value = new

    def compute_complete(self) -> bool:
        """Form is complete when subnet and address are valid."""
        return all([self.subnet, self.address])

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

        self.post_message(self.Layer3StateChanged(layer3=self, valid=new))

    def compose(self) -> ComposeResult:
        yield Label("Subnet:", classes="text-label")
        yield ValidateBlurInput(
            self._subnet,
            placeholder="172.16.32.0/24",
            validate_on=[],
            validators=[NetworkValidator("subnet")],
            id="subnet-input",
        )
        yield Label("Address:", classes="text-label")
        yield ValidateBlurInput(
            self._address,
            placeholder="172.16.32.12",
            validate_on=[],
            validators=[self.address_validator],
            id="address-input",
        )
        yield InvalidLabel("", id="subnet-input-invalid")
        yield InvalidLabel("", id="address-input-invalid")
        yield Label("Gateway:", classes="text-label")
        yield ValidateBlurInput(
            self._gateway,
            placeholder="172.16.32.1",
            validate_on=[],
            validators=[NetworkValidator("gateway")],
            id="gateway-input",
        )
        yield Label("DNS:", classes="text-label")
        yield ValidateBlurInput(
            self._dns,
            placeholder="1.1.1.1, 8.8.8.8",
            validate_on=[],
            validators=[NetworkValidator("dns")],
            id="dns-input",
        )
        yield InvalidLabel("", id="gateway-input-invalid")
        yield InvalidLabel("", id="dns-input-invalid")
        yield WarningLabel(
            "Warning: if gateway is not present, and this is your primary "
            "interface, you will not have internet",
            id="gateway-warning",
        )

    def on_mount(self) -> None:
        self.subnet = self._subnet
        self.address = self._address
        self.gateway = self._gateway
        self.dns = self._dns

    @on(ValidateBlurInput.BlurValidationMessage)
    def show_invalid_reason(
        self, event: ValidateBlurInput.BlurValidationMessage
    ) -> None:
        """Update validation display when an input loses focus."""
        validation_result = event.validation_result
        input = event.input
        input_id = input.id
        value = input.value

        if not validation_result:
            return

        is_valid = validation_result.is_valid

        label = self.query_one(f"#{event.input.id}-invalid", InvalidLabel)
        label.visible = not is_valid

        label.set_class(not is_valid, "-show-error")

        msg = "" if is_valid else "\n".join(validation_result.failure_descriptions)
        label.update(msg)

        if input_id == "subnet-input":
            self.subnet = value if is_valid else ""
        elif input_id == "address-input":
            self.address = value if is_valid else ""
        elif input_id == "gateway-input":
            self.gateway = value if is_valid else ""
            # Show/hide gateway warning based on whether gateway is empty
            warning_label = self.query_one("#gateway-warning", WarningLabel)
            show_warning = is_valid and not value.strip()
            warning_label.visible = show_warning
            warning_label.set_class(show_warning, "-show-warning")
        elif input_id == "dns-input":
            self.dns = value if is_valid else ""
