from logging import Logger

import cbor2
from airthings_ble.atom.request import AtomRequestPath
from airthings_ble.connectivity_mode import AirthingsConnectivityMode
from airthings_ble.const import CONNECTIVITY_MODE


class AtomResponse:
    """Response for Airthings BLE Atom API"""

    _header = bytearray.fromhex("1001000345")
    response: bytes
    random_bytes: bytes
    path: AtomRequestPath

    def __init__(
        self,
        logger: Logger,
        response: bytes | None,
        random_bytes: bytes,
        path: AtomRequestPath,
    ) -> None:
        self.logger = logger
        if response is None:
            raise ValueError("Response cannot be None")
        self.response = response
        self.random_bytes = random_bytes
        self.path = path

    def parse(self) -> dict[str, float | str | None] | None:
        if self.response[0:5] != self._header:
            self.logger.error(
                "Invalid response header, expected %s, but got %s",
                self._header.hex(),
                self.response[0:5].hex(),
            )
            raise ValueError("Invalid response header")

        if self.response[5:7] != self.random_bytes:
            self.logger.debug(
                "Invalid response checksum, expected %s, but got %s",
                self.random_bytes.hex(),
                self.response[5:7].hex(),
            )
            raise ValueError("Invalid response checksum")

        if self.response[7] != 0x81:
            self.logger.debug(
                "Invalid response type, expected 81, but got %s", self.response[7]
            )
            raise ValueError("Invalid response type")

        if self.response[8] != 0xA2:
            self.logger.debug(
                "Invalid response array length, expected 2, but got %s",
                self.response[8],
            )
            raise ValueError("Invalid response array length")

        data_bytes = self.response[7:]
        decoded_data = cbor2.loads(data_bytes)

        if not isinstance(decoded_data, list):
            self.logger.debug("Parsed data is not a list, but a %s", type(decoded_data))
            raise ValueError("Invalid response data type")

        if path := decoded_data[0].get(0):
            if path != self.path.value:
                self.logger.error(
                    "Response path does not match request path, expected %s but got %s",
                    self.path.value,
                    path,
                )
                raise ValueError("Response path does not match request path")
        else:
            raise ValueError("Response path missing")

        if data := decoded_data[0].get(2):

            if self.path == AtomRequestPath.CONNECTIVITY_MODE and isinstance(data, int):
                return {
                    CONNECTIVITY_MODE: AirthingsConnectivityMode.from_atom_int(
                        data
                    ).value
                }

            if self.path == AtomRequestPath.LATEST_VALUES:
                if isinstance(data, bytes):
                    # Need to use cbor2 to decode the bytes again
                    data = cbor2.loads(data)

                if isinstance(data, dict):
                    return data

            self.logger.debug("Response data: %s", data)
            raise ValueError("Invalid response data type")
        raise ValueError("Response data missing")
