from typing import Any, Dict
from fastapi import FastAPI
from fastapi.routing import APIRoute
from fastapi.openapi.utils import get_openapi

from endpoints.routes import get_safe_endpoint_urls
from config import api_config


class OpenAPISchemaCreator:
    """
    OpenAPI schema creator and customizer for FastAPI applications.
    """

    def __init__(self, app: FastAPI):
        """
        Initialize the OpenAPI schema creator.

        Args:
            app: FastAPI application instance
        """
        self.app = app
        self.safe_endpoint_list: list[tuple[str, str]] = get_safe_endpoint_urls()
        self.routers_list = self.app.routes

    @staticmethod
    def create_security_schemes() -> Dict[str, Any]:
        """
        Create security scheme definitions.

        Returns:
            Dict[str, Any]: Security scheme configurations
        """

        return {
            "BearerAuth": {
                "type": "apiKey",
                "in": "header",
                "name": api_config.ACCESS_TOKEN_TAG,
                "description": "Enter: **'Bearer &lt;JWT&gt;'**, where JWT is the access token",
            }
        }

    def configure_route_security(
        self, path: str, method: str, schema: Dict[str, Any]
    ) -> None:
        """
        Configure security requirements for a specific route.

        Args:
            path: Route path
            method: HTTP method
            schema: OpenAPI schema to modify
        """
        if not schema.get("paths", {}).get(path, {}).get(method):
            return

        # Check if endpoint is in safe list
        endpoint_path = f"{path}:{method}"
        list_of_safe_endpoints = [
            f"{e[0]}:{str(e[1]).lower()}" for e in self.safe_endpoint_list
        ]
        if endpoint_path not in list_of_safe_endpoints:
            if "security" not in schema["paths"][path][method]:
                schema["paths"][path][method]["security"] = []
            schema["paths"][path][method]["security"].append({"BearerAuth": []})

    def create_schema(self) -> Dict[str, Any]:
        """
        Create the complete OpenAPI schema.

        Returns:
            Dict[str, Any]: Complete OpenAPI schema
        """
        openapi_schema = get_openapi(
            title=api_config.TITLE,
            description=api_config.DESCRIPTION,
            version=api_config.VERSION,
            routes=self.app.routes,
        )

        # Add security schemes
        if "components" not in openapi_schema:
            openapi_schema["components"] = {}

        openapi_schema["components"]["securitySchemes"] = self.create_security_schemes()

        # Configure route security and responses
        for route in self.app.routes:
            if isinstance(route, APIRoute) and route.include_in_schema:
                path = str(route.path)
                methods = [method.lower() for method in route.methods]
                for method in methods:
                    self.configure_route_security(path, method, openapi_schema)

        # Add custom documentation extensions
        openapi_schema["x-documentation"] = {
            "postman_collection": "/docs/postman",
            "swagger_ui": "/docs",
            "redoc": "/redoc",
        }
        return openapi_schema


def create_openapi_schema(app: FastAPI) -> Dict[str, Any]:
    """
    Create OpenAPI schema for a FastAPI application.

    Args:
        app: FastAPI application instance

    Returns:
        Dict[str, Any]: Complete OpenAPI schema
    """
    creator = OpenAPISchemaCreator(app)
    return creator.create_schema()
