"""
FastAPI application for SLTK.

Provides REST endpoints for all toolkit functionality.
Main application setup with router registration and middleware configuration.
"""

from __future__ import annotations

import asyncio
import logging
import os

from fastapi import FastAPI, Request
from fastapi.middleware.cors import CORSMiddleware
from starlette.middleware.base import BaseHTTPMiddleware
from starlette.middleware.gzip import GZipMiddleware

# Rate limiting support (optional)
try:
    from slowapi import Limiter, _rate_limit_exceeded_handler
    from slowapi.errors import RateLimitExceeded
    from slowapi.util import get_remote_address

    RATE_LIMITING_AVAILABLE = True
except ImportError:
    RATE_LIMITING_AVAILABLE = False
    Limiter = None  # type: ignore[misc, assignment]

logger = logging.getLogger(__name__)

# ============================================================================
# Security Headers Middleware
# ============================================================================


class SecurityHeadersMiddleware(BaseHTTPMiddleware):
    """
    Middleware to add security headers to all responses.

    Headers added:
    - X-Frame-Options: DENY - Prevents clickjacking attacks
    - X-Content-Type-Options: nosniff - Prevents MIME type sniffing
    - X-XSS-Protection: 1; mode=block - Enables XSS filter in older browsers
    - Content-Security-Policy: Restricts resource loading
    - Referrer-Policy: strict-origin-when-cross-origin - Controls referrer info
    - Permissions-Policy: Restricts browser features
    """

    async def dispatch(self, request: Request, call_next):
        response = await call_next(request)

        # Prevent clickjacking
        response.headers["X-Frame-Options"] = "DENY"

        # Prevent MIME type sniffing
        response.headers["X-Content-Type-Options"] = "nosniff"

        # XSS protection for older browsers
        response.headers["X-XSS-Protection"] = "1; mode=block"

        # Content Security Policy
        # Allow self for scripts/styles, data: URIs for inline images
        # Allow blob: for video streaming
        csp_directives = [
            "default-src 'self'",
            "script-src 'self' 'unsafe-inline' 'unsafe-eval'",  # Needed for some frontend frameworks
            "style-src 'self' 'unsafe-inline'",
            "img-src 'self' data: blob:",
            "media-src 'self' blob:",
            "connect-src 'self' ws: wss:",  # WebSocket connections
            "font-src 'self'",
            "frame-ancestors 'none'",
        ]
        response.headers["Content-Security-Policy"] = "; ".join(csp_directives)

        # Referrer policy
        response.headers["Referrer-Policy"] = "strict-origin-when-cross-origin"

        # Permissions Policy (formerly Feature-Policy)
        permissions = [
            "geolocation=()",
            "microphone=()",
            "camera=()",
            "payment=()",
            "usb=()",
        ]
        response.headers["Permissions-Policy"] = ", ".join(permissions)

        return response


# ============================================================================
# App Creation
# ============================================================================

app = FastAPI(
    title="SLTK API",
    description="Sign Language Toolkit - Sign Language Processing API",
    version="0.1.0",
)

# ============================================================================
# CORS Middleware
# ============================================================================

# CORS middleware for frontend
# Note: In production, remove wildcard and specify allowed origins
ALLOWED_ORIGINS = os.environ.get(
    "SLTK_CORS_ORIGINS", "http://localhost:5173,http://localhost:3000"
).split(",")
app.add_middleware(
    CORSMiddleware,
    allow_origins=ALLOWED_ORIGINS,
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

# Add security headers middleware
app.add_middleware(SecurityHeadersMiddleware)

# Add GZip compression for responses > 500 bytes (50-80% size reduction for JSON)
app.add_middleware(GZipMiddleware, minimum_size=500)

# ============================================================================
# Rate Limiting Setup
# ============================================================================

limiter: Limiter | None = None
if RATE_LIMITING_AVAILABLE:
    limiter = Limiter(key_func=get_remote_address)
    app.state.limiter = limiter
    app.add_exception_handler(RateLimitExceeded, _rate_limit_exceeded_handler)  # type: ignore[arg-type]

    # Set the global limiter in dependencies module
    from sltk.api.dependencies import set_limiter

    set_limiter(limiter)

# ============================================================================
# Router Registration
# ============================================================================

from sltk.api.routers import (
    admin_router,
    analysis_router,
    audio_router,
    chat_router,
    corpus_router,
    datasets_router,
    embeddings_router,
    extraction_router,
    features_router,
    jobs_router,
    linguistics_router,
    nm_annotator_router,
    nms_router,
    poses_router,
    processing_router,
    search_router,
    segmentation_router,
    settings_router,
    signrep_router,
    videos_router,
    visualization_router,
    workspace_router,
)

# Register all routers
app.include_router(videos_router)
app.include_router(extraction_router)
app.include_router(poses_router)
app.include_router(datasets_router)
app.include_router(features_router)
app.include_router(analysis_router)
app.include_router(linguistics_router)
app.include_router(embeddings_router)
app.include_router(search_router)
app.include_router(settings_router)
app.include_router(jobs_router)
app.include_router(admin_router)
app.include_router(visualization_router)
app.include_router(workspace_router)
app.include_router(audio_router)
app.include_router(corpus_router)
app.include_router(processing_router)
app.include_router(chat_router)
app.include_router(nm_annotator_router)
app.include_router(signrep_router)
app.include_router(segmentation_router)
app.include_router(nms_router)

# ============================================================================
# Startup Events
# ============================================================================


@app.on_event("startup")
async def start_job_cleanup_task():
    """Start the background task for periodic job cleanup."""
    from sltk.api.routers.admin import periodic_cleanup

    asyncio.create_task(periodic_cleanup())


# ============================================================================
# Factory Function
# ============================================================================


def create_app():
    """Factory function for creating the app."""
    return app


# ============================================================================
# Static File Serving (production Docker builds)
# ============================================================================

from pathlib import Path

from fastapi.responses import FileResponse
from fastapi.staticfiles import StaticFiles

_static_dir = Path(__file__).resolve().parent / "static"
if _static_dir.is_dir():
    app.mount("/assets", StaticFiles(directory=str(_static_dir / "assets")), name="static-assets")

    @app.get("/{full_path:path}")
    async def serve_spa(full_path: str):
        """SPA catch-all: serve index.html for any unmatched route."""
        return FileResponse(str(_static_dir / "index.html"))


# ============================================================================
# Main Entry Point
# ============================================================================

if __name__ == "__main__":
    import uvicorn

    uvicorn.run(app, host="0.0.0.0", port=8000)
