from http import HTTPStatus
from typing import Annotated, override

from fastapi import HTTPException, Path, Security

from phederation.api.routes.base import BaseRoute
from phederation.models import APPublicKey, ErrorMessageKeyNotFound
from phederation.models.keys import ErrorMessageKeyRestricted
from phederation.security.authentication import UserInfo
from phederation.utils.base import UrlType, assemble_id_url


class KeyRoute(BaseRoute):

    @override
    def setup(self):

        @self.router.get(
            "/keys/{key_primary}",
            status_code=HTTPStatus.OK,
            response_model_exclude_none=True,
            responses={
                HTTPStatus.NOT_FOUND: {
                    "model": ErrorMessageKeyNotFound,
                    "description": "If the key with the given primary cannot be found on this instance.",
                },
            },
            tags=["keys"],
        )
        async def get_key(  # pyright: ignore[reportUnusedFunction]
            key_primary: Annotated[str, Path(description="The identifier of the key (without the URL) on this instance.")],
            user_info: Annotated[UserInfo, Security(self.middleware.authentication, scopes=["user"])],
        ) -> APPublicKey:
            """Handle requests for public keys."""
            self.logger.debug(f"Received request for key primary: {key_primary}")

            # Return key document with proper JSON-LD context
            requested_key_url = assemble_id_url(type=UrlType.Keys, base_url=self.api.settings.domain.base_url, primary=key_primary)
            key_response = await self.server.key_manager.get_public_key_APObject(key_id=requested_key_url)

            actor_requesting_access = user_info.actor_id if user_info else None
            key_with_access = await self.api.server.resolver.resolve_access_type(
                object=key_response, actor_requesting_access=actor_requesting_access
            )
            if not key_with_access or not isinstance(key_with_access, APPublicKey):
                self.logger.warning(f"Key visibility restricted, user: {user_info} cannot access it")
                raise HTTPException(
                    status_code=HTTPStatus.NOT_FOUND,
                    detail=ErrorMessageKeyRestricted().message,
                )
            if not key_response:
                self.logger.error(f"No key found with primary '{key_primary}'")
                raise HTTPException(detail=ErrorMessageKeyNotFound().message, status_code=HTTPStatus.NOT_FOUND)

            return key_response
