from abc import ABC, abstractmethod
from collections.abc import Awaitable, Callable
from http import HTTPStatus
from logging import Logger

from fastapi import APIRouter, FastAPI, HTTPException

from phederation.api.base import BaseAPI
from phederation.federation import ActivityPubServer
from phederation.federation.middleware import ActivityPubMiddleware
from phederation.utils.logging import configure_logger


class BaseRoute(ABC):
    """The base class for Route instances.
    Route objects add routing methods to an app.
    """

    async def initialize(self, app: FastAPI, api: BaseAPI, middleware: ActivityPubMiddleware, server: ActivityPubServer) -> None:
        self.app: FastAPI = app
        self.api: BaseAPI = api
        self.middleware: ActivityPubMiddleware = middleware
        self.server: ActivityPubServer = server
        self.router: APIRouter = APIRouter()
        self.logger: Logger = configure_logger(
            f"{".".join(__name__.split('.')[:-1])}.{type(self).__name__.lower()}", prefix=server.settings.federation.logging_prefix
        )
        self.setup()

    @abstractmethod
    def setup(self) -> None:
        pass


def admin_route(self: BaseRoute):
    def admin_route[**Params, ReturnType](
        function: Callable[Params, Awaitable[ReturnType]],
    ) -> Callable[Params, Awaitable[ReturnType]]:
        """This decorator verifies that the route is running on an instance in admin mode.
        If it fails, a HTTPException(status_code=METHOD_NOT_ALLOWED) is thrown."""

        async def check_is_admin(*args_is_admin: Params.args, **kwargs_is_admin: Params.kwargs) -> ReturnType:
            if not self.server.settings.federation.admin_mode:
                raise HTTPException(
                    status_code=HTTPStatus.METHOD_NOT_ALLOWED, detail={"status": "Error", "description": "Instance is not in admin mode"}
                )
            return await function(*args_is_admin, **kwargs_is_admin)

        return check_is_admin

    return admin_route
