"""Definition of an ElkM1 Area"""
import datetime as dt
import time
from typing import Any, Optional

from .connection import Connection
from .const import ElkRPStatus
from .elements import Element
from .message import lw_encode, rw_encode, sp_encode, ss_encode, sw_encode, vn_encode


class Panel(Element):
    """Class representing the overall Elk panel"""

    def __init__(self, connection: Connection) -> None:
        super().__init__(0, connection)
        self.real_time_clock = None
        self.elkm1_version = None
        self.xep_version = None
        self.remote_programming_status = 0
        self.system_trouble_status = ""
        self.temperature_units = None
        self.user_code_length = None
        self._configured = True
        self.setattr("name", "ElkM1", True)

        self._connection.msg_decode.add_handler("VN", self._vn_handler)
        self._connection.msg_decode.add_handler("XK", self._xk_handler)
        self._connection.msg_decode.add_handler(
            "RR", self._xk_handler
        )  # RR/XK use same handler
        self._connection.msg_decode.add_handler("RP", self._rp_handler)
        self._connection.msg_decode.add_handler("SS", self._ss_handler)
        self._connection.msg_decode.add_handler("UA", self._ua_handler)

    def sync(self) -> None:
        """Retrieve panel information from ElkM1"""
        self._connection.send(vn_encode())
        self._connection.send(lw_encode())
        self._connection.send(ss_encode())
        # Don't sync UA from here as it is used as a "sync complete" marker

    def speak_word(self, word: int) -> None:
        """(Helper) Speak word."""
        self._connection.send(sw_encode(word))

    def speak_phrase(self, phrase: int) -> None:
        """(Helper) Speak phrase."""
        self._connection.send(sp_encode(phrase))

    def set_time(self, datetime: Optional[dt.datetime] = None) -> None:
        """(Helper) Set the time given a datetime."""
        if datetime is None:
            struct_time = time.localtime()
            datetime = dt.datetime(*struct_time[:6])
        self._connection.send(rw_encode(datetime))

    def _vn_handler(self, elkm1_version: str, xep_version: str) -> None:
        self.setattr("elkm1_version", elkm1_version, False)
        self.setattr("xep_version", xep_version, True)

    def _xk_handler(self, real_time_clock: str) -> None:
        self.setattr("real_time_clock", real_time_clock, True)

    def _ss_handler(self, system_trouble_status: str) -> None:
        def _get_status(index: int, trouble: str, zone_encoded: bool = False) -> None:
            if system_trouble_status[index] != "0":
                if zone_encoded:
                    zone = ord(system_trouble_status[index]) - 0x30
                    statuses.append(f"{trouble} zone {zone}")
                else:
                    statuses.append(trouble)

        statuses: list[str] = []
        _get_status(0, "AC Fail")
        _get_status(1, "Box Tamper", True)
        _get_status(2, "Fail To Communicate")
        _get_status(3, "EEProm Memory Error")
        _get_status(4, "Low Battery Control")
        _get_status(5, "Transmitter Low Battery", True)
        _get_status(6, "Over Current")
        _get_status(7, "Telephone Fault")
        _get_status(9, "Output 2")
        _get_status(10, "Missing Keypad")
        _get_status(11, "Zone Expander")
        _get_status(12, "Output Expander")
        _get_status(14, "ELKRP Remote Access")
        _get_status(16, "Common Area Not Armed")
        _get_status(17, "Flash Memory Error")
        _get_status(18, "Security Alert", True)
        _get_status(19, "Serial Port Expander")
        _get_status(20, "Lost Transmitter", True)
        _get_status(21, "GE Smoke CleanMe")
        _get_status(22, "Ethernet")
        _get_status(31, "Display Message In Keypad Line 1")
        _get_status(32, "Display Message In Keypad Line 2")
        _get_status(33, "Fire", True)
        self.setattr("system_trouble_status", ", ".join(statuses), True)

    def _rp_handler(self, remote_programming_status: int) -> None:
        if remote_programming_status == ElkRPStatus.DISCONNECTED.value:
            self._connection.resume()
        else:
            self._connection.pause()
        self.setattr("remote_programming_status", remote_programming_status, True)

    def _ua_handler(self, **kwargs: dict[str, Any]) -> None:
        self.setattr("user_code_length", kwargs["user_code_length"], False)
        self.setattr("temperature_units", kwargs["temperature_units"], True)
