from typing import Any, Dict

from fastapi import FastAPI, status
from fastapi.middleware.cors import CORSMiddleware
from starlette.responses import RedirectResponse

from opyrator import Opyrator
from opyrator.api.fastapi_utils import patch_fastapi


def launch_api(opyrator_path: str, port: int = 8501, host: str = "0.0.0.0") -> None:
    import uvicorn

    from opyrator import Opyrator
    from opyrator.api import create_api

    app = create_api(Opyrator(opyrator_path))
    uvicorn.run(app, host=host, port=port, log_level="info")


def create_api(opyrator: Opyrator) -> FastAPI:

    title = opyrator.name
    if "opyrator" not in opyrator.name.lower():
        title += " - Opyrator"

    # TODO what about version?
    app = FastAPI(title=title, description=opyrator.description)

    patch_fastapi(app)

    app.add_middleware(
        CORSMiddleware,
        allow_origins=["*"],
        allow_credentials=True,
        allow_methods=["*"],
        allow_headers=["*"],
    )

    @app.post(
        "/call",
        operation_id="call",
        response_model=opyrator.output_type,
        # response_model_exclude_unset=True,
        summary="Execute the opyrator.",
        status_code=status.HTTP_200_OK,
    )
    def call(input: opyrator.input_type) -> Any:  # type: ignore
        """Executes this opyrator."""
        return opyrator(input)

    @app.get(
        "/info",
        operation_id="info",
        response_model=Dict,
        # response_model_exclude_unset=True,
        summary="Get info metadata.",
        status_code=status.HTTP_200_OK,
    )
    def info() -> Any:  # type: ignore
        """Returns informational metadata about this Opyrator."""
        return {}

    # Redirect to docs
    @app.get("/", include_in_schema=False)
    def root() -> Any:
        return RedirectResponse("./docs")

    return app
