"""Package is used as a simulated UOSInterface for test purposes."""
from uoshardware import UOSCommunicationError
from uoshardware.abstractions import ComResult, UOSInterface


class Stub(UOSInterface):
    """Class can be used as a low level test endpoint."""

    def __init__(self, connection: str, errored: int = 0):
        """Instantiate an instance of the test stub."""
        self.__packet_buffer: list = []
        self.__open = False
        self.errored = errored
        self.connection = connection

    def execute_instruction(
        self,
        address: int,
        # Dead code false positive as this is over-riding an interface.
        payload: tuple[int, ...],  # dead: disable
        **kwargs,
    ) -> ComResult:
        """Simulate executing an instruction on a UOS endpoint.

        Should check whether the last instruction was valid and store
        it. This will allow read response to provide more realistic
        responses.
        """
        if not self.__open:
            raise UOSCommunicationError("Port must be open to execute instructions.")
        function = kwargs["function"]
        if function is not None:
            if function.ack:
                self.__packet_buffer.append(self.get_npc_packet(0, address, tuple([0])))
            for rx_packet in function.rx_packets_expected:
                self.__packet_buffer.append(
                    self.get_npc_packet(0, address, tuple(0 for _ in range(rx_packet)))
                )
            return ComResult(True)
        raise UOSCommunicationError("Cannot execute function 'None'.")

    # Dead code detection false positive due to abstract interface.
    def read_response(
        self, expect_packets: int, timeout_s: float  # dead: disable
    ) -> ComResult:
        """Simulate gathering the response from an instruction.

        Should have already executed an instruction. If no response is
        generated by instruction will error accordingly.
        """
        if not self.__open:
            raise UOSCommunicationError("Port must be open to read response.")
        result = ComResult(False)
        if len(self.__packet_buffer) > 0:
            result.ack_packet = self.__packet_buffer.pop(0)
            result.status = True
        for _ in self.__packet_buffer:
            result.rx_packets.append(self.__packet_buffer.pop(0))
        return result

    def hard_reset(self) -> ComResult:
        """Override base prototype, simulates reset."""
        if not self.__open:
            raise UOSCommunicationError("Port must be open to hard reset device.")
        return ComResult(status=True)

    def open(self):
        """Override base prototype, simulates opening a connection."""
        if len(self.connection) > 0:
            self.__open = True
            return
        raise UOSCommunicationError(
            f"Cannot open a connection to connection string '{self.connection}'"
        )

    def close(self):
        """Override base prototype, simulates closing a connection."""
        self.__open = False
        if self.errored != 0:
            raise UOSCommunicationError("Problem closing connection.")

    def is_active(self) -> bool:
        """Check if connection is active to the device."""
        return self.__open

    @staticmethod
    def enumerate_devices() -> list:
        """Return a list of test stubs implemented in the interface."""
        return [Stub("STUB")]  # The test stub is always available
