import time
from fastapi import FastAPI, Request
from fastapi.middleware.cors import CORSMiddleware
from starlette.middleware.base import BaseHTTPMiddleware
from crypticorn.common.logging import configure_logging
from contextlib import asynccontextmanager
from typing_extensions import deprecated
import warnings
from crypticorn.common.warnings import CrypticornDeprecatedSince217
from crypticorn.common.metrics import (
    HTTP_REQUESTS_COUNT,
    HTTP_REQUEST_DURATION,
    REQUEST_SIZE,
    RESPONSE_SIZE,
)


class PrometheusMiddleware(BaseHTTPMiddleware):
    async def dispatch(self, request: Request, call_next):

        if "authorization" in request.headers:
            auth_type = (
                request.headers["authorization"].split()[0]
                if " " in request.headers["authorization"]
                else "none"
            )
        elif "x-api-key" in request.headers:
            auth_type = "X-API-KEY"
        else:
            auth_type = "none"

        try:
            endpoint = request.get(
                "route"
            ).path  # use /time/{type} instead of dynamic route to avoid high cardinality
        except Exception:
            endpoint = request.url.path

        start = time.perf_counter()
        response = await call_next(request)
        duration = time.perf_counter() - start

        HTTP_REQUESTS_COUNT.labels(
            method=request.method,
            endpoint=endpoint,
            status_code=response.status_code,
            auth_type=auth_type,
        ).inc()

        try:
            body = await request.body()
            size = len(body)
        except Exception:
            size = 0

        REQUEST_SIZE.labels(
            method=request.method,
            endpoint=endpoint,
        ).observe(size)

        try:
            body = await response.body()
            size = len(body)
        except Exception:
            size = 0

        RESPONSE_SIZE.labels(
            method=request.method,
            endpoint=endpoint,
        ).observe(size)

        HTTP_REQUEST_DURATION.labels(
            endpoint=endpoint,
            method=request.method,
        ).observe(duration)

        return response


@deprecated("Use add_middleware instead", category=None)
def add_cors_middleware(app: "FastAPI"):
    warnings.warn(
        "add_cors_middleware is deprecated. Use add_middleware instead.",
        CrypticornDeprecatedSince217,
    )
    app.add_middleware(
        CORSMiddleware,
        allow_origins=[
            "http://localhost:5173",  # vite dev server
            "http://localhost:4173",  # vite preview server
        ],
        allow_origin_regex="^https://([a-zA-Z0-9-]+.)*crypticorn.(dev|com)/?$",  # matches (multiple or no) subdomains of crypticorn.dev and crypticorn.com
        allow_credentials=True,
        allow_methods=["*"],
        allow_headers=["*"],
    )


def add_middleware(app: "FastAPI"):
    app.add_middleware(
        CORSMiddleware,
        allow_origins=[
            "http://localhost:5173",  # vite dev server
            "http://localhost:4173",  # vite preview server
        ],
        allow_origin_regex="^https://([a-zA-Z0-9-]+.)*crypticorn.(dev|com)/?$",  # matches (multiple or no) subdomains of crypticorn.dev and crypticorn.com
        allow_credentials=True,
        allow_methods=["*"],
        allow_headers=["*"],
    )
    app.add_middleware(PrometheusMiddleware)


@asynccontextmanager
async def default_lifespan(app: FastAPI):
    """Default lifespan for the applications.
    This is used to configure the logging for the application.
    To override this, pass a different lifespan to the FastAPI constructor or call this lifespan within a custom lifespan.
    """
    configure_logging()
    yield
