"""Class for SIA Accounts."""
from __future__ import annotations

import logging
from dataclasses import dataclass, field, asdict
from typing import Any
from datetime import tzinfo
import pytz

from .errors import (
    InvalidAccountFormatError,
    InvalidAccountLengthError,
    InvalidKeyFormatError,
    InvalidKeyLengthError,
)

_LOGGER = logging.getLogger(__name__)


@dataclass
class SIAAccount:
    """Class for SIA Accounts."""

    account_id: str
    key: str | None = None
    allowed_timeband: tuple[int, int] = (40, 20)
    device_timezone: tzinfo = pytz.utc
    key_b: bytes | None = field(
        repr=False,
        default=None,  # metadata=config(exclude=Exclude.ALWAYS)  # type: ignore
    )

    def __post_init__(self) -> None:
        """Rewrite the key as bytes."""
        self.key_b = self.key.encode("utf-8") if self.key else None
        self.account_id = self.account_id.upper()

    @property
    def encrypted(self) -> bool:
        """Return true when encrypted."""
        return bool(self.key_b)

    @classmethod
    def validate_account(
        cls, account_id: str | None = None, key: str | None = None
    ) -> None:
        """Validate a accounts information, either with one of the fields or both.

        Keyword Arguments:
            account_id {str} -- The account id specified by the alarm system,
                should be 3-16 characters hexadecimal. (default: {None})
            key {str} -- The encryption key specified by the alarm system,
                should be 16,24 or 32 characters hexadecimal. (default: {None})

        Raises:
            InvalidKeyFormatError: If the key is not a valid hexadecimal string.
            InvalidKeyLengthError: If the key does not have 16, 24 or 32 characters.
            InvalidAccountFormatError: If the account id is not a valid hexadecimal string.
            InvalidAccountLengthError: If the account id does not have between 3 and 16 characters.

        """
        if account_id is not None:  # pragma: no cover
            try:
                int(account_id, 16)
            except ValueError as exc:
                raise InvalidAccountFormatError from exc
            try:
                assert 3 <= len(account_id) <= 16
            except AssertionError as exc:
                raise InvalidAccountLengthError from exc
        if key is not None:  # pragma: no cover
            try:
                int(key, 16)
            except ValueError as exc:
                raise InvalidKeyFormatError from exc
            try:
                assert len(key) in (16, 24, 32)
            except AssertionError as exc:
                raise InvalidKeyLengthError from exc

    def to_dict(self) -> dict[str, Any]:
        """Create a dict from the dataclass."""
        return asdict(self)

    @classmethod
    def from_dict(cls, acc: dict[str, Any]) -> SIAAccount:
        """Create a SIA Account from a dict."""
        return cls(**acc)
