from fastapi import Depends, FastAPI, Request, Response, status
from fastapi.middleware.trustedhost import TrustedHostMiddleware
from redis.exceptions import RedisError
from sqlalchemy import text
from sqlalchemy.exc import SQLAlchemyError

from .cache import get_cache
from .settings import get_settings
from .db import engine
from .routers import domains, accounts, aliases, redirects, reputation, admin
from .security import require_admin

settings = get_settings()

app = FastAPI(title="Limristem eMail API", version=settings.app_version)
app.include_router(domains.router)
app.include_router(accounts.router)
app.include_router(aliases.router)
app.include_router(redirects.router)
app.include_router(reputation.router)
app.include_router(admin.router)


@app.middleware("http")
async def add_security_headers(request: Request, call_next):
    """Add security hardening headers to every response."""
    response: Response = await call_next(request)
    response.headers["X-Content-Type-Options"] = "nosniff"
    response.headers["X-Frame-Options"] = "DENY"
    response.headers["X-XSS-Protection"] = "0"
    response.headers["Referrer-Policy"] = "strict-origin-when-cross-origin"
    response.headers["Permissions-Policy"] = "geolocation=(), microphone=(), camera=()"
    if settings.ssl_mode != "plain":
        response.headers["Strict-Transport-Security"] = "max-age=63072000; includeSubDomains; preload"
    return response


def collect_health() -> dict:
    checks = {
        "database": {"status": "ok"},
        "redis": {"status": "ok"},
    }
    overall = "ok"

    try:
        with engine.connect() as connection:
            connection.execute(text("SELECT 1"))
    except SQLAlchemyError as exc:
        checks["database"] = {"status": "error", "detail": exc.__class__.__name__}
        overall = "degraded"

    try:
        get_cache().ping()
    except RedisError as exc:
        checks["redis"] = {"status": "error", "detail": exc.__class__.__name__}
        overall = "degraded"

    return {"status": overall, "checks": checks}


@app.get("/health")
def health(response: Response):
    payload = collect_health()
    if payload["status"] != "ok":
        response.status_code = status.HTTP_503_SERVICE_UNAVAILABLE
    return payload


@app.get("/health/details")
def health_details(response: Response, _: str = Depends(require_admin)):
    payload = collect_health()
    payload["hostname"] = settings.hostname
    payload["mail_home"] = str(settings.mail_home)
    payload["dkim_keys_dir"] = str(settings.dkim_keys_dir)
    if payload["status"] != "ok":
        response.status_code = status.HTTP_503_SERVICE_UNAVAILABLE
    return payload
