import ipaddress
from contextlib import asynccontextmanager, suppress

from fastapi import FastAPI, Request
from fastapi.exceptions import HTTPException
from fastapi.responses import JSONResponse

from app.auth.rate_limiter import LoginRateLimiter
from app.config import get_settings
from app.database import Base, get_engine


@asynccontextmanager
async def lifespan(application: FastAPI):
    settings = get_settings()
    application.state.login_rate_limiter = LoginRateLimiter(
        max_failures=settings.login_max_failures,
        window_seconds=settings.login_window_seconds,
        cooldown_seconds=settings.login_cooldown_seconds,
    )
    trusted_networks = []
    for part in settings.login_trusted_proxy_ips.split(","):
        part = part.strip()
        if part:
            with suppress(ValueError):
                trusted_networks.append(ipaddress.ip_network(part, strict=False))
    application.state.login_trusted_networks = trusted_networks
    engine = get_engine()
    async with engine.begin() as conn:
        # In production, Alembic handles migrations; this is a dev convenience
        await conn.run_sync(Base.metadata.create_all)
    yield
    await engine.dispose()


_settings = get_settings()

app = FastAPI(
    title="Reactbin API",
    version="1.0.0",
    lifespan=lifespan,
    docs_url="/docs" if _settings.api_docs_enabled else None,
    redoc_url="/redoc" if _settings.api_docs_enabled else None,
    openapi_url="/openapi.json" if _settings.api_docs_enabled else None,
)

# Defaults so app.state is populated even when lifespan doesn't run (e.g. tests)
app.state.login_rate_limiter = LoginRateLimiter()
app.state.login_trusted_networks = []


@app.exception_handler(HTTPException)
async def http_exception_handler(request: Request, exc: HTTPException):
    if isinstance(exc.detail, dict):
        return JSONResponse(status_code=exc.status_code, content=exc.detail)
    return JSONResponse(status_code=exc.status_code, content={"detail": exc.detail})


@app.get("/api/v1/health")
async def health():
    return {"status": "ok"}


# Routers registered after all modules are defined to avoid circular imports
from app.routers import auth, images, tags  # noqa: E402

app.include_router(auth.router, prefix="/api/v1")
app.include_router(images.router, prefix="/api/v1")
app.include_router(tags.router, prefix="/api/v1")
