"""Base class for fritzbox_callmonitor entities."""
from __future__ import annotations

from contextlib import suppress
from datetime import timedelta
import logging
import re

from fritzconnection.lib.fritzphonebook import FritzPhonebook

from homeassistant.util import Throttle

from .const import REGEX_NUMBER, UNKNOWN_NAME

_LOGGER = logging.getLogger(__name__)

# Return cached results if phonebook was downloaded less then this time ago.
MIN_TIME_PHONEBOOK_UPDATE = timedelta(hours=6)


class FritzBoxPhonebook:
    """This connects to a FritzBox router and downloads its phone book."""

    fph: FritzPhonebook
    phonebook_dict: dict[str, list[str]]
    number_dict: dict[str, str]

    def __init__(
        self,
        host: str,
        username: str,
        password: str,
        phonebook_id: int | None = None,
        prefixes: list[str] | None = None,
    ) -> None:
        """Initialize the class."""
        self.host = host
        self.username = username
        self.password = password
        self.phonebook_id = phonebook_id
        self.prefixes = prefixes

    def init_phonebook(self) -> None:
        """Establish a connection to the FRITZ!Box and check if phonebook_id is valid."""
        self.fph = FritzPhonebook(
            address=self.host,
            user=self.username,
            password=self.password,
        )
        self.update_phonebook()

    @Throttle(MIN_TIME_PHONEBOOK_UPDATE)
    def update_phonebook(self) -> None:
        """Update the phone book dictionary."""
        if self.phonebook_id is None:
            return

        self.phonebook_dict = self.fph.get_all_names(self.phonebook_id)
        self.number_dict = {
            re.sub(REGEX_NUMBER, "", nr): name
            for name, nrs in self.phonebook_dict.items()
            for nr in nrs
        }
        _LOGGER.info("Fritz!Box phone book successfully updated")

    def get_phonebook_ids(self) -> list[int]:
        """Return list of phonebook ids."""
        return self.fph.phonebook_ids  # type: ignore[no-any-return]

    def get_name(self, number: str) -> str:
        """Return a name for a given phone number."""
        number = re.sub(REGEX_NUMBER, "", str(number))

        with suppress(KeyError):
            return self.number_dict[number]

        if not self.prefixes:
            return UNKNOWN_NAME

        for prefix in self.prefixes:
            with suppress(KeyError):
                return self.number_dict[prefix + number]
            with suppress(KeyError):
                return self.number_dict[prefix + number.lstrip("0")]

        return UNKNOWN_NAME