"""Module for Anisette header providers."""
from __future__ import annotations

import base64
import locale
import logging
from abc import ABC, abstractmethod
from datetime import datetime, timezone

from typing_extensions import override

from findmy.util.closable import Closable
from findmy.util.http import HttpSession


def _gen_meta_headers(
    user_id: str,
    device_id: str,
    serial: str = "0",
) -> dict[str, str]:
    now = datetime.now(tz=timezone.utc)
    locale_str = locale.getdefaultlocale()[0] or "en_US"

    return {
        "X-Apple-I-Client-Time": now.replace(microsecond=0).isoformat() + "Z",
        "X-Apple-I-TimeZone": str(now.astimezone().tzinfo),
        "loc": locale_str,
        "X-Apple-Locale": locale_str,
        "X-Apple-I-MD-RINFO": "17106176",
        "X-Apple-I-MD-LU": base64.b64encode(str(user_id).upper().encode()).decode(),
        "X-Mme-Device-Id": str(device_id).upper(),
        "X-Apple-I-SRL-NO": serial,
    }


class BaseAnisetteProvider(Closable, ABC):
    """Abstract base class for Anisette providers."""

    @abstractmethod
    async def _get_base_headers(self) -> dict[str, str]:
        raise NotImplementedError

    async def get_headers(
        self,
        user_id: str,
        device_id: str,
        serial: str = "0",
    ) -> dict[str, str]:
        """
        Retrieve a complete dictionary of Anisette headers.

        Consider using `BaseAppleAccount.get_anisette_headers` instead.
        """
        base_headers = await self._get_base_headers()
        base_headers.update(_gen_meta_headers(user_id, device_id, serial))

        return base_headers


class RemoteAnisetteProvider(BaseAnisetteProvider):
    """Anisette provider. Fetches headers from a remote Anisette server."""

    def __init__(self, server_url: str) -> None:
        """Initialize the provider with URL to te remote server."""
        super().__init__()

        self._server_url = server_url

        self._http = HttpSession()

        logging.info("Using remote anisette server: %s", self._server_url)

    @override
    async def _get_base_headers(self) -> dict[str, str]:
        r = await self._http.get(self._server_url)
        headers = r.json()

        return {
            "X-Apple-I-MD": headers["X-Apple-I-MD"],
            "X-Apple-I-MD-M": headers["X-Apple-I-MD-M"],
        }

    @override
    async def close(self) -> None:
        """See `AnisetteProvider.close`."""
        await self._http.close()


# TODO(malmeloo): implement using pyprovision
# https://github.com/malmeloo/FindMy.py/issues/2
class LocalAnisetteProvider(BaseAnisetteProvider):
    """Anisette provider. Generates headers without a remote server using pyprovision."""

    def __init__(self) -> None:
        """Initialize the provider."""
        super().__init__()

    @override
    async def _get_base_headers(self) -> dict[str, str]:
        return NotImplemented

    @override
    async def close(self) -> None:
        """See `AnisetteProvider.close`."""
