from collections.abc import AsyncIterator
from contextlib import asynccontextmanager

from fastapi import FastAPI, Request, Response
from fastapi.middleware.cors import CORSMiddleware
from starlette.middleware.base import BaseHTTPMiddleware, RequestResponseEndpoint

from .api import main_router
from .config import SETTINGS
from .kafka.producer import get_producer
from .storage.fdb_client import ensure_directories, init_fdb


class TrailingSlashMiddleware(BaseHTTPMiddleware):
    """Normalize request paths so that ``/foo`` matches routes defined as ``/foo/``.

    If the incoming path does not end with ``/``, append one before
    dispatching.  This avoids 307 redirects that break CORS preflight.
    """

    async def dispatch(self, request: Request, call_next: RequestResponseEndpoint) -> Response:
        if not request.url.path.endswith("/"):
            request.scope["path"] = request.url.path + "/"
        return await call_next(request)


@asynccontextmanager
async def lifespan(_app: FastAPI) -> AsyncIterator[None]:
    init_fdb()
    ensure_directories()
    producer = get_producer()
    await producer.start()
    try:
        yield
    finally:
        await producer.stop()


app = FastAPI(title="Matyan Server", lifespan=lifespan)

app.add_middleware(TrailingSlashMiddleware)  # ty:ignore[invalid-argument-type]

app.add_middleware(
    CORSMiddleware,  # ty:ignore[invalid-argument-type]
    allow_origins=SETTINGS.cors_origins,
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

app.include_router(main_router, prefix="/api/v1")
