# -*- coding: utf-8 -*-
from __future__ import annotations

import uuid

from hotpocket_backend.apps.accounts.services import (
    AccessTokensService as BackendAccessTokensService,
)
from hotpocket_soa.dto.accounts import (
    AccessTokenMetaUpdateIn,
    AccessTokenOut,
    AccessTokensQuery,
)

from .base import ProxyService, SOAError


class AccessTokensService(ProxyService):
    class AccessTokensServiceError(SOAError):
        pass

    class AccessTokenNotFound(AccessTokensServiceError):
        pass

    class AccessTokenAccessDenied(AccessTokensServiceError):
        pass

    def __init__(self):
        super().__init__()
        self.backend_access_tokens_service = BackendAccessTokensService()

    def wrap_exception(self, exception: Exception) -> Exception:
        new_exception_args = []
        if len(exception.args) > 0:
            new_exception_args = [exception.args[0]]

        return self.AccessTokensServiceError(*new_exception_args)

    def create(self,
               *,
               account_uuid: uuid.UUID,
               origin: str,
               meta: dict,
               ) -> AccessTokenOut:
        return AccessTokenOut.model_validate(
            self.call(
                self.backend_access_tokens_service,
                'create',
                account_uuid=account_uuid,
                origin=origin,
                meta=meta,
            ),
            from_attributes=True,
        )

    def get(self,
            *,
            account_uuid: uuid.UUID,
            pk: uuid.UUID,
            ) -> AccessTokenOut:
        try:
            result = AccessTokenOut.model_validate(
                self.call(
                    self.backend_access_tokens_service,
                    'get',
                    pk=pk,
                ),
                from_attributes=True,
            )

            if result.account_uuid != account_uuid:
                raise self.AccessTokenAccessDenied(
                    f'account_uuid=`{account_uuid}` pk=`{pk}`',
                )

            return result
        except SOAError as exception:
            if isinstance(exception.__cause__, BackendAccessTokensService.AccessTokenNotFound) is True:
                raise self.AccessTokenNotFound(*exception.args) from exception
            else:
                raise

    def get_by_key(self,
                   *,
                   account_uuid: uuid.UUID | None,
                   key: str,
                   ) -> AccessTokenOut:
        try:
            result = AccessTokenOut.model_validate(
                self.call(
                    self.backend_access_tokens_service,
                    'get_by_key',
                    key=key,
                ),
                from_attributes=True,
            )

            if result.account_uuid != account_uuid:
                raise self.AccessTokenAccessDenied(
                    f'account_uuid=`{account_uuid}` key=`{key}`',
                )

            return result
        except SOAError as exception:
            if isinstance(exception.__cause__, BackendAccessTokensService.AccessTokenNotFound) is True:
                raise self.AccessTokenNotFound(f'account_uuid=`{account_uuid}` pk=`{key}`') from exception
            else:
                raise

    def search(self,
               *,
               query: AccessTokensQuery,
               limit: int,
               ) -> list[AccessTokenOut]:
        return [
            AccessTokenOut.model_validate(row, from_attributes=True)
            for row
            in self.call(
                self.backend_access_tokens_service,
                'search',
                query=query,
                limit=limit,
            )
        ]

    def delete(self, *, access_token: AccessTokenOut) -> bool:
        return self.call(
            self.backend_access_tokens_service,
            'delete',
            pk=access_token.pk,
        )

    def update_meta(self,
                    *,
                    access_token: AccessTokenOut,
                    update: AccessTokenMetaUpdateIn,
                    ) -> AccessTokenOut:
        return AccessTokenOut.model_validate(
            self.call(
                self.backend_access_tokens_service,
                'update_meta',
                pk=access_token.pk,
                update=update,
            ),
            from_attributes=True,
        )
