#  Copyright (C) 2025
#  ABM, Moscow
#
#  UNPUBLISHED PROPRIETARY MATERIAL.
#  ALL RIGHTS RESERVED.
#
#  Authors: Mike Orlov <m.orlov@abm-jsc.ru>
import abc
# import typing
from dataclasses import dataclass, field
from functools import cached_property
from typing import Generic, ClassVar, Mapping

from frozendict import frozendict
from http_tools import IncomingRequest
from init_helpers import raise_if

from ..exceptions import Unauthorized
from .security_scheme import SecurityScheme, AuthInfo, AuthToken
from .security_scheme_type import SecuritySchemeType
from ... import SpecRef, SpecResource


@dataclass(frozen=True, slots=True, repr=False)
class HttpSecurityScheme(SecurityScheme, Generic[AuthInfo], abc.ABC):
    type_: ClassVar[SecuritySchemeType] = SecuritySchemeType.http
    header_scheme: ClassVar[str]

    def get_spec_dict(self, dependency_to_ref: Mapping[SpecResource, SpecRef]) -> frozendict:
        return SecurityScheme.get_spec_dict(self, dependency_to_ref) | {'scheme': self.header_scheme.strip().lower()}

    def get_key(self) -> str:
        return f'{self.type_.name}_{self.header_scheme}'.lower().strip()

    async def _extract_token(self, incoming_request: IncomingRequest) -> AuthToken:
        dirty_token: str = incoming_request.metadata.header_name_to_value.get("Authorization")
        raise_if(not isinstance(dirty_token, str), Unauthorized("Failed to get token from Authorization header"))
        raise_if(not dirty_token.startswith(self.header_scheme), Unauthorized("Wrong authorization scheme"))
        return dirty_token.removeprefix(self.header_scheme)


@dataclass(frozen=True, repr=False)
class HttpBearerSecurityScheme(HttpSecurityScheme, Generic[AuthInfo]):
    header_scheme: ClassVar[str] = 'Bearer '


@dataclass(frozen=True, repr=False)
class HttpBasicSecurityScheme(HttpSecurityScheme, Generic[AuthInfo]):
    header_scheme: ClassVar[str] = 'Basic '
