"""Native GPIO driver for H7992 switch."""

from __future__ import annotations

from dataclasses import dataclass, field

from python_app.hardware_full.switch_drivers.gpio_uapi import GpioOutputLines


_POSITION_TO_AB = (
    (0, 0),
    (0, 1),
    (1, 0),
    (1, 1),
)


@dataclass(slots=True)
class H7992Driver:
    """Drive H7992 using two GPIO lines (A/B)."""

    name: str
    positions: int = 4
    default_position: int = 0
    gpio_chip: str = "/dev/gpiochip0"
    pin_a: int = 17
    pin_b: int = 27
    _lines: GpioOutputLines | None = field(init=False, default=None, repr=False)
    _is_open: bool = field(init=False, default=False, repr=False)
    _current_position: int = field(init=False, default=0, repr=False)

    def __post_init__(self) -> None:
        """Initialize runtime state."""
        self._lines: GpioOutputLines | None = None
        self._is_open = False
        self._current_position = 0

    def open(self) -> None:
        """Open GPIO lines and switch to default position."""
        if self._is_open:
            return

        self._validate()
        self._lines = GpioOutputLines(
            chip=self.gpio_chip,
            offsets=(self.pin_a, self.pin_b),
            consumer=f"radar_{self.name}",
        )
        self._lines.open()
        self._is_open = True
        self.switch_to(self.default_position)

    def close(self) -> None:
        """Close GPIO lines."""
        if self._lines is not None:
            self._lines.close()
            self._lines = None
        self._is_open = False

    def position_count(self) -> int:
        """Return number of supported positions."""
        return self.positions

    def switch_to(self, position: int) -> None:
        """Switch hardware to selected position."""
        if not self._is_open or self._lines is None:
            raise RuntimeError(f"Switch driver is not open for {self.name}")
        if position < 0 or position >= self.positions:
            raise ValueError(f"Position out of range for {self.name}: {position}")

        self._lines.set_values(_POSITION_TO_AB[position])
        self._current_position = int(position)

    @property
    def current_position(self) -> int:
        """Return current position."""
        return self._current_position

    def _validate(self) -> None:
        """Validate H7992 driver parameters."""
        if self.positions <= 0 or self.positions > 4:
            raise ValueError(f"H7992 positions must be in range [1,4] for {self.name}")
        if self.default_position < 0 or self.default_position >= self.positions:
            raise ValueError(f"default_position out of range for {self.name}")
        if self.pin_a < 0 or self.pin_b < 0 or self.pin_a == self.pin_b:
            raise ValueError(f"pin_a/pin_b are invalid for {self.name}")
