from logging import Logger
from typing import Any
from urllib.parse import urlparse

from fastapi import FastAPI, Request, Response
from starlette.background import BackgroundTask

from phederation.storage.base import StorageBackend
from phederation.utils.logging import configure_logger
from phederation.utils.settings import PhedSettings


class Statistics:
    """Statistics class.
    Can be used for logging url requests and corresponding responses from the API, for debugging or for web statistics.
    CAREFUL: This can be used to store sensitive information, like authentication tokens and hidden messages from users, so use carefully.
    The StatisticsSettings can be used to disable certain routes, like '/auth' and '/keys', to mitigate this.
    """

    def __init__(self, settings: PhedSettings, app: FastAPI, storage: StorageBackend):
        self.app: FastAPI = app
        self.settings: PhedSettings = settings
        self.logger: Logger = configure_logger(__name__, prefix=self.settings.federation.logging_prefix)

    def log_statistics(
        self,
        extra: dict[str, Any],
        req_headers: dict[str, str | None] | None = None,
        res_headers: dict[str, str | None] | None = None,
    ):
        path = urlparse(str(extra["req"]["url"])).path  # pyright: ignore[reportAny]
        self.logger.info(f"Statistics: logging '{path}', req_headers={req_headers}, res_headers={res_headers}, extra: {extra}")

    async def initialize(self):
        if self.settings.statistics.enabled:
            self.logger.info("Initializing Statistics module.")

    async def log(self, request: Request, response: Response):
        """
        Logs statistics about the given request and response. Called in middleware.
        Inspired by https://stackoverflow.com/questions/69670125/how-to-log-raw-http-request-response-in-fastapi/73464007#73464007
        """
        if not self.settings.statistics.enabled or not self.settings.statistics.log_middleware:
            return response
        else:
            path = urlparse(str(request.url)).path

            req_headers_obj = request.headers
            req_headers = {key.lower(): req_headers_obj.get(key) for key in req_headers_obj.keys()}
            res_headers_obj = response.headers
            res_headers = {key.lower(): res_headers_obj.get(key) for key in res_headers_obj.keys()}

            # avoid logging authorization tokens
            if "authorization" in req_headers.keys():
                req_headers["authorization"] = "******"
            if "authorization" in res_headers.keys():
                res_headers["authorization"] = "******"

            if not self.settings.statistics.disable_routes or not any([path.startswith(route) for route in self.settings.statistics.disable_routes]):
                extra = {
                    "req": {"method": request.method, "url": str(request.url)},
                    "res": {
                        "status_code": response.status_code,
                        "media_type": response.media_type,
                    },
                }
                task = BackgroundTask(
                    self.log_statistics,
                    req_headers=req_headers,
                    res_headers=res_headers,
                    extra=extra
                )
            else:
                task = None
            response.background = task
            return response
