# ABOUTME: FastAPI application factory for vibetuner frontend.
# ABOUTME: Loads user config from tune.py and wires routes, middleware, etc.
from typing import Any

from fastapi import Depends, FastAPI, Request
from fastapi.responses import HTMLResponse, RedirectResponse
from fastapi.staticfiles import StaticFiles

import vibetuner.frontend.lifespan as lifespan_module
from vibetuner.config import settings
from vibetuner.loader import load_app_config
from vibetuner.logging import logger
from vibetuner.paths import paths

from .lifespan import ctx
from .middleware import middlewares
from .oauth import auto_register_providers
from .routes import auth, debug, health, language, meta, user
from .routes.auth import register_oauth_routes
from .templates import render_template


# Load user's app configuration
_app_config = load_app_config()

# Add user middleware to the list (before app creation)
for mw in _app_config.middleware:
    middlewares.append(mw)

dependencies: list[Any] = [
    # Add any dependencies that should be available globally
]

app = FastAPI(
    debug=ctx.DEBUG,
    lifespan=lifespan_module.lifespan,
    docs_url="/docs" if ctx.DEBUG else None,
    redoc_url="/redoc" if ctx.DEBUG else None,
    openapi_url="/openapi.json" if ctx.DEBUG else None,
    middleware=middlewares,
    dependencies=dependencies,
)

# Rate limiting setup (slowapi requires app.state.limiter)
if settings.rate_limit.enabled:
    from slowapi import _rate_limit_exceeded_handler
    from slowapi.errors import RateLimitExceeded

    from vibetuner.ratelimit import limiter

    app.state.limiter = limiter
    app.add_exception_handler(RateLimitExceeded, _rate_limit_exceeded_handler)

# Static files
app.mount(f"/static/v{ctx.v_hash}/css", StaticFiles(directory=paths.css), name="css")
app.mount(f"/static/v{ctx.v_hash}/img", StaticFiles(directory=paths.img), name="img")
app.mount(f"/static/v{ctx.v_hash}/js", StaticFiles(directory=paths.js), name="js")

app.mount("/static/favicons", StaticFiles(directory=paths.favicons), name="favicons")
app.mount("/static/fonts", StaticFiles(directory=paths.fonts), name="fonts")


@app.get(
    "/static/v{v_hash}/css/{subpath:path}",
    response_class=RedirectResponse,
    include_in_schema=False,
)
@app.get(
    "/static/css/{subpath:path}",
    response_class=RedirectResponse,
    include_in_schema=False,
)
def css_redirect(request: Request, subpath: str):
    return request.url_for("css", path=subpath).path


@app.get(
    "/static/v{v_hash}/img/{subpath:path}",
    response_class=RedirectResponse,
    include_in_schema=False,
)
@app.get(
    "/static/img/{subpath:path}",
    response_class=RedirectResponse,
    include_in_schema=False,
)
def img_redirect(request: Request, subpath: str):
    return request.url_for("img", path=subpath).path


@app.get(
    "/static/v{v_hash}/js/{subpath:path}",
    response_class=RedirectResponse,
    include_in_schema=False,
)
@app.get(
    "/static/js/{subpath:path}",
    response_class=RedirectResponse,
    include_in_schema=False,
)
def js_redirect(request: Request, subpath: str):
    return request.url_for("js", path=subpath).path


if ctx.DEBUG:
    from .hotreload import hotreload

    app.add_websocket_route(
        "/hot-reload",
        route=hotreload,  # type: ignore
        name="hot-reload",
    )

# Auto-register OAuth providers from config + env vars
auto_register_providers(_app_config.oauth_providers, _app_config.custom_oauth_providers)

# Register OAuth routes on auth.router (must happen before include_router)
register_oauth_routes()

# Core routes (hidden from OpenAPI schema)
app.include_router(meta.router, include_in_schema=False)
app.include_router(auth.router, include_in_schema=False)
app.include_router(user.router, include_in_schema=False)
app.include_router(language.router, include_in_schema=False)

# User frontend routes from tune.py (hidden from OpenAPI schema)
for router in _app_config.routes:
    app.include_router(router, include_in_schema=False)
    logger.debug(f"Registered user router: {router}")

# User API routes from tune.py (visible in OpenAPI schema)
for router in _app_config.api_routes:
    app.include_router(router)
    logger.debug(f"Registered user API router: {router}")


@app.get("/", name="homepage", response_class=HTMLResponse, include_in_schema=False)
def default_index(request: Request) -> HTMLResponse:
    return render_template("index.html.jinja", request)


# Debug and health routes (always last, hidden from OpenAPI schema)
app.include_router(debug.auth_router, include_in_schema=False)
app.include_router(debug.router, include_in_schema=False)

# Mount Streaq task queue UI at /debug/tasks when workers are configured
if settings.workers_available:
    try:
        from streaq.ui import router as streaq_ui_router

        app.include_router(
            streaq_ui_router,
            prefix="/debug/tasks",
            dependencies=[Depends(debug.check_debug_access)],
            tags=["debug"],
            include_in_schema=False,
        )
        logger.debug("Streaq task queue UI mounted at /debug/tasks")
    except ImportError:
        pass

app.include_router(health.router, include_in_schema=False)
