# Copyright 2025 Acute Technology Inc. All rights reserved.
# SPDX-License-Identifier: BSD-3-Clause
"""UART Basic Bus Class."""

from typing import TYPE_CHECKING, ClassVar

import aqpxlib.message as pxmsg
from aqpxlib.abstract import PxAbstractBus, PxAbstractDevice
from aqpxlib.uart.uart_rx import PxUartRx
from aqpxlib.uart.uart_tx import PxUartTx

if TYPE_CHECKING:
    from aqpxlib.toplevel import AqProtocolExerciser


class PxUartBus(PxAbstractBus):
    """Uart Basic Bus Class."""

    # Used to identify the class
    identifier: str = "uart"

    controller_class: type[PxAbstractDevice] = PxUartTx

    # A mapping of device identifiers to device classes
    _available_devices: ClassVar[list[type[PxAbstractDevice]]] = [
        PxUartTx,
        PxUartRx,
    ]

    # Used to query the bus type from the protobuf messages
    protobuf_key: str = "uart"

    def __init__(self, exerciser: "AqProtocolExerciser", *args, **kwargs) -> None:
        """Initialize an UART bus."""
        super().__init__(exerciser)

        self.tx: int | None = kwargs.get("tx", 0)
        self.rx: int | None = kwargs.get("rx", 1)
        self._baud_rate: int | None = kwargs.get("baud_rate", 9600)
        self._data_bits: int | None = kwargs.get("data_bits", 8)
        self._stop_bits: int | None = kwargs.get("stop_bits", 1)

        handle_index = self._find_or_create_bus(tx=self.tx, rx=self.rx)
        if handle_index == -1:
            err_msg = "Failed to create I3C bus"
            raise ValueError(err_msg)

        self._handle_index = handle_index

    def _to_protobuf_handle_config(self, *args, **kwargs) -> pxmsg.PxHandle:
        """Convert the bus to a protobuf structure.

        This method is inherited from the abstract bus class.
        Here we expected to get the TX and RX pins from the kwargs, which
        are used to create a new protobuf structure.

        Args:
            *args: Additional arguments to pass to the bus constructor
            **kwargs: Additional keyword arguments to pass to the bus constructor

        Returns:
            pxmsg.PxHandle: The protobuf structure of the bus

        Raises:
            ValueError: If the TX and RX pins are not provided

        """
        if "tx" not in kwargs or "rx" not in kwargs:
            err_msg = "TX and RX pins are required to create a new UART bus"
            raise ValueError(err_msg)

        tx: int = kwargs.get("tx", 0)
        rx: int = kwargs.get("rx", 0)

        return pxmsg.PxHandle(
            uart=pxmsg.UartChannel(tx=tx, rx=rx),
        )

    def __eq__(self, other: object) -> bool:
        """Check if the bus is equal to another bus.

        This checks it the bus is equal to another bus or a protobuf structure of the bus.
        Possible other instances are:
            - PxI3CBus

        Args:
            other (Any): The other bus to compare with or a protobuf structure of the bus

        Returns:
            bool: True if the bus is equal to the other bus, False otherwise

        """
        if isinstance(other, PxUartBus):
            # TODO: should we check the config?
            return self.tx == other.tx and self.rx == other.rx

        if isinstance(other, pxmsg.UartChannel):
            return self.tx == other.tx and self.rx == other.rx

        return False

    def __str__(self) -> str:
        """Return string representation of the bus."""
        return f"UART Bus (TX: {self.tx}, RX: {self.rx})"

    def __repr__(self) -> str:
        """Representation of the bus."""
        return self.__str__()


__all__ = [
    "PxUartBus",
]
