from contextlib import asynccontextmanager

from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from fastapi.middleware.trustedhost import TrustedHostMiddleware
from fastapi.openapi.docs import get_redoc_html, get_swagger_ui_html
from fastapi.staticfiles import StaticFiles
from slowapi import _rate_limit_exceeded_handler
from slowapi.errors import RateLimitExceeded

from app.core.config import settings
from app.core.database import engine, Base
from app.core.limiter import limiter
from app.routers import auth, users, companies
from app.routers import time_entries, absences, reports, ldap, smtp, caldav
from app.routers import import_kimai
from app.routers import kiosk
from app.routers import busylight
from app.routers import audit
from app.routers import special_assignments
from app.routers import hours_payouts
from app.routers import public_stamp
from app.routers import ical
from app.routers import reseller, tenants
from app.routers import tls_admin


@asynccontextmanager
async def lifespan(app: FastAPI):
    # Startup: Tabellen anlegen nur in Development/Test.
    # In Production verwaltet Alembic das Schema – create_all würde mit Migrationen kollidieren.
    import logging
    _log = logging.getLogger(__name__)
    if not settings.is_production:
        async with engine.begin() as conn:
            await conn.run_sync(Base.metadata.create_all)
        _log.info("Development-Modus: create_all ausgeführt.")
    else:
        _log.info("Production-Modus: create_all übersprungen — Alembic verwaltet das Schema.")

    # M-4: Warnung wenn Production ohne ALLOWED_HOSTS läuft
    if settings.is_production and not settings.allowed_hosts:
        _log.warning(
            "SICHERHEITSWARNUNG: ALLOWED_HOSTS ist nicht gesetzt. "
            "In Production sollte ALLOWED_HOSTS in .env konfiguriert sein "
            "um Host-Header-Injection zu verhindern."
        )

    # Erinnerungs-Scheduler (agent-11 PR3) – nicht im Test-Kontext starten
    import sys
    if settings.scheduler_enabled and "pytest" not in sys.modules:
        from app.services.scheduler_service import start as start_scheduler
        start_scheduler()

    yield
    # Shutdown
    from app.services.scheduler_service import shutdown as shutdown_scheduler
    shutdown_scheduler()
    from app.core.redis import close_async_redis
    await close_async_redis()
    await engine.dispose()


app = FastAPI(
    title=settings.app_name,
    version="0.1.0",
    docs_url=None,   # eigene Route unten – Swagger-Assets lokal statt CDN
    redoc_url=None,  # eigene Route unten – ReDoc-Assets lokal statt CDN
    lifespan=lifespan,
)

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

# Swagger/ReDoc-Assets lokal ausliefern statt von cdn.jsdelivr.net – Netzwerke ohne
# CDN-Zugriff (Firewall/Proxy) zeigten sonst eine leere /docs-Seite.
if not settings.is_production:
    app.mount("/static", StaticFiles(directory="static"), name="static")

    @app.get("/docs", include_in_schema=False)
    async def custom_swagger_ui_html():
        return get_swagger_ui_html(
            openapi_url=app.openapi_url,
            title=f"{app.title} - Swagger UI",
            swagger_js_url="/static/swagger-ui/swagger-ui-bundle.js",
            swagger_css_url="/static/swagger-ui/swagger-ui.css",
            swagger_favicon_url="/static/swagger-ui/favicon.png",
        )

    @app.get("/redoc", include_in_schema=False)
    async def custom_redoc_html():
        return get_redoc_html(
            openapi_url=app.openapi_url,
            title=f"{app.title} - ReDoc",
            redoc_js_url="/static/swagger-ui/redoc.standalone.js",
            redoc_favicon_url="/static/swagger-ui/favicon.png",
            with_google_fonts=False,
        )

# ── Middleware ────────────────────────────────────────────────────────────────

app.add_middleware(
    CORSMiddleware,
    allow_origins=[settings.frontend_url],
    allow_credentials=True,
    allow_methods=["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"],
    allow_headers=[
        "Content-Type",
        "Authorization",
        "X-Kiosk-Key-Id",
        "X-Kiosk-Timestamp",
        "X-Kiosk-Nonce",
        "X-Kiosk-Signature",
    ],
)

# TrustedHostMiddleware: aktiv sobald ALLOWED_HOSTS gesetzt (Development: leer = deaktiviert)
# Production: ALLOWED_HOSTS=timemaster.example.com in .env setzen
if settings.allowed_hosts:
    app.add_middleware(TrustedHostMiddleware, allowed_hosts=settings.allowed_hosts)

# ── Routers ───────────────────────────────────────────────────────────────────

API_PREFIX = "/api/v1"

app.include_router(auth.router,          prefix=API_PREFIX)
app.include_router(users.router,         prefix=API_PREFIX)
app.include_router(companies.router,     prefix=API_PREFIX)
app.include_router(time_entries.router,  prefix=API_PREFIX)
app.include_router(public_stamp.router,  prefix=API_PREFIX)
app.include_router(ical.router,          prefix=API_PREFIX)
app.include_router(absences.router,      prefix=API_PREFIX)
app.include_router(reports.router,       prefix=API_PREFIX)
app.include_router(ldap.router,          prefix=API_PREFIX)
app.include_router(smtp.router,          prefix=API_PREFIX)
app.include_router(caldav.router,        prefix=API_PREFIX)
app.include_router(import_kimai.router,  prefix=API_PREFIX)
app.include_router(kiosk.router,         prefix=API_PREFIX)
app.include_router(busylight.router,     prefix=API_PREFIX)
app.include_router(audit.router,         prefix=API_PREFIX)
app.include_router(special_assignments.router, prefix=API_PREFIX)
app.include_router(hours_payouts.router,      prefix=API_PREFIX)
app.include_router(reseller.router,           prefix=API_PREFIX)
app.include_router(tenants.router,            prefix=API_PREFIX)
app.include_router(tls_admin.router,           prefix=API_PREFIX)


# ── Health ────────────────────────────────────────────────────────────────────

@app.get("/health", tags=["System"])
async def health():
    return {"status": "ok", "app": settings.app_name, "env": settings.app_env}
