from datetime import datetime, timezone
from typing import Dict, Union

from aiohttp import ClientResponse
from smb.common.http_client import HttpClient, collect_errors


class YavClientException(Exception):
    pass


class AccessError(YavClientException):
    pass


class InvalidOAuthToken(YavClientException):
    pass


class InvalidUUID(YavClientException):
    pass


_code_to_exc = {
    "access_error": AccessError,
    "invalid_uuid_value": InvalidUUID,
    "invalid_oauth_token_error": InvalidOAuthToken,
}


class YavClient(HttpClient):
    __slots__ = ("_headers",)

    YAV_URL: str = "https://vault-api.passport.yandex.net"

    _headers: Dict[str, str]

    def __init__(self, token: str):
        self._headers = {"Authorization": f"OAuth {token}"}
        super().__init__(self.YAV_URL)

    @collect_errors
    async def retrieve_secret_head(
        self, secret_id: str
    ) -> Dict[str, Union[str, datetime, int, Dict[str, str]]]:
        got = await self.request(
            method="GET",
            uri=f"/1/versions/{secret_id}/",
            headers=self._headers,
            expected_statuses=[200],
            metric_name="/1/versions/{secret_id}/"
        )
        version = got.pop("version")

        version["value"] = {el["key"]: el["value"] for el in version["value"]}
        version["created_at"] = datetime.fromtimestamp(
            version["created_at"], tz=timezone.utc
        )

        return version

    async def _handle_custom_errors(self, response: ClientResponse) -> None:
        if response.status in (400, 401):
            body = await response.json()
            exc = _code_to_exc.get(body.get("code"))
            if exc:
                raise exc(body)

        return await self._raise_unknown_response(response)
