"""Native GPIO driver for HMC349A switch."""

from __future__ import annotations

from dataclasses import dataclass, field

from python_app.hardware_full.switch_drivers.gpio_uapi import GpioOutputLines


@dataclass(slots=True)
class HMC349ADriver:
    """Drive HMC349A using one control GPIO line."""

    name: str
    positions: int = 2
    default_position: int = 0
    gpio_chip: str = "/dev/gpiochip0"
    pin_a: int = 17
    invert_logic: bool = False
    _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()

        offsets = [self.pin_a]
        self._lines = GpioOutputLines(
            chip=self.gpio_chip,
            offsets=offsets,
            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}")

        control = int(position & 0x01)
        if self.invert_logic:
            control ^= 0x01

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

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

    def _validate(self) -> None:
        """Validate HMC349A driver parameters."""
        if self.positions <= 0 or self.positions > 2:
            raise ValueError(f"HMC349A positions must be in range [1,2] 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:
            raise ValueError(f"pin_a is invalid for {self.name}")
