"""A response is a special form of telegram usually sent by an EnOcean module to the host.

The cases are defined in ENOCEAN SERIAL PROTOCOL (ESP3) - SPECIFICATION, Section 1.9:

 > Case 1 : ESP3 packets of the type RADIO_ERP1, RADIO_SUB_TEL or REMOTE_MAN are bidirectional, that is, after sending a packet (host -> module) it is mandatory to wait for the RESPONSE message, to confirm the telegram has been processed and will subsequently be transmitted.
 After receiving (module -> host) a packet no RESPONSE is required (see RADIO_ERP1 no. <3> and <4>).

 > Case 2 : Only a host sends a ESP3 COMMAND (COMMON, SMART ACK) to an EnOcean module. Each REQUEST is answered with a RESPONSE message (OK, error, etc.). The reverse direction module-to-host is not possible.

 > Case 3 : Only an EnOcean module sends an EVENT to a host.The type of the EVENT defines whether a RESPONSE message is required or not.
"""

from dataclasses import dataclass
from enum import IntEnum

from .packet import ESP3Packet, ESP3PacketType


class ResponseCode(IntEnum):
    """Response codes for EnOcean ESP3 packets."""

    OK = 0x00
    ERROR = 0x01
    NOT_SUPPORTED = 0x02
    WRONG_PARAMETER = 0x03
    OPERATION_DENIED = 0x04
    DUTY_CYCLE_LOCK = 0x05
    BUFFER_TOO_SMALL = 0x06
    NO_FREE_BUFFER = 0x07
    BASEID_OUT_OF_RANGE = 0x90
    BASEID_MAX_REACHED = 0x91

    def __repr__(self) -> str:
        return f"{self.name} (0x{self.value:02X})"


@dataclass
class ResponseTelegram:
    """Represents an EnOcean ESP3 response telegram."""

    return_code: ResponseCode = ResponseCode.OK
    response_data: bytes = b""
    optional_data: bytes = b""

    @classmethod
    def from_esp3_packet(cls, packet: ESP3Packet) -> "ResponseTelegram":
        """Create ResponseTelegram from an ESP3 packet."""

        if packet.packet_type != ESP3PacketType.RESPONSE:
            raise ValueError("ESP3Packet is not a response telegram")

        if len(packet.data) < 1:
            raise ValueError("ESP3Packet is not a valid response; no data")

        try:
            return_code = ResponseCode(packet.data[0])
        except ValueError:
            raise ValueError("Invalid response code in ESP3Packet")

        response_data = packet.data[1:]

        return ResponseTelegram(return_code, response_data, packet.optional)
