"""
VulnManager - FastAPI Application

Sichere Web-Applikation zur Verwaltung von Sicherheitslücken nach OWASP-Prinzipien.
"""
import os
import time
os.environ['TZ'] = 'Europe/Zurich'
if hasattr(time, 'tzset'):
    time.tzset()
import logging
from dotenv import load_dotenv

load_dotenv()

from contextlib import asynccontextmanager
from fastapi import FastAPI, Request, status, Depends, HTTPException
from fastapi.exceptions import RequestValidationError
from fastapi.middleware.cors import CORSMiddleware
from fastapi.middleware.trustedhost import TrustedHostMiddleware
from fastapi.middleware.gzip import GZipMiddleware
try:
    from starlette.middleware.proxy_headers import ProxyHeadersMiddleware
except ModuleNotFoundError:
    from uvicorn.middleware.proxy_headers import ProxyHeadersMiddleware
from fastapi.responses import JSONResponse
from slowapi import _rate_limit_exceeded_handler
from slowapi.errors import RateLimitExceeded



from app.routers import auth, auth_admin, vulnerabilities, assets, policies, scans, settings, notifications, groups, reports, audit, nessus, compliance
try:
    from app.routers import auth_oidc
    _HAS_OIDC = True
except Exception as _e:  # authlib missing or misconfigured
    auth_oidc = None  # type: ignore
    _HAS_OIDC = False
try:
    from app.routers import auth_saml
    _HAS_SAML = True
except Exception:
    auth_saml = None  # type: ignore
    _HAS_SAML = False
from app.database import engine, SessionLocal
from app.models.base import Base
from app.models.user import User, UserRole
from app.auth.jwt_handler import hash_password
from app.scheduler import start_scheduler, stop_scheduler
from app.db_init import create_initial_data
from app.rate_limiter import limiter, TRUST_PROXY_HEADERS

# Logging Configuration
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)

# Environment
ENV = os.getenv("ENV", "production")
DEBUG = ENV == "development"

# Rate Limiter (OWASP A04: Insecure Design)


# Lifecycle Events
@asynccontextmanager
async def lifespan(app: FastAPI):
    """
    Startup und Shutdown Events

    Startup:
        - Datenbank-Initialisierung
        - Admin-User Check
        - Health-Check-Logging

    Shutdown:
        - Cleanup von Ressourcen
    """
    logger.info("🚀 VulnManager startet...")
    logger.info(f"Environment: {ENV}")

    # Erstelle DB-Tabellen (nur Development - in Production: Alembic)
    if DEBUG:
        try:
            logger.warning("Development mode: Creating database tables...")
            Base.metadata.create_all(bind=engine)
        except Exception as e:
            logger.error(f"Database unreachable: {e}")
            logger.warning("App starting without DB connection - API calls will fail until DB is available")
    
    # Initiale Daten (Default Admin User) erstellen
    try:
        db = SessionLocal()
        create_initial_data(db)
        db.close()
    except Exception as e:
        logger.error(f"Error creating initial data: {e}")

    # Background-Scheduler für automatische Scans starten
    try:
        start_scheduler()
        logger.info("Background scheduler for automatic scans started")
    except Exception as e:
        logger.warning(f"Scheduler could not be started: {e}")

    yield

    stop_scheduler()
    logger.info("🛑 VulnManager wird heruntergefahren...")


# FastAPI App
app = FastAPI(
    title="VulnManager API",
    description="Vulnerability Management Dashboard mit Wazuh & KI-Integration",
    version="1.0.0",
    docs_url="/docs" if DEBUG else None,  # Swagger UI nur in Development
    redoc_url="/redoc" if DEBUG else None,
    lifespan=lifespan
)

# Rate Limiter State
app.state.limiter = limiter
app.add_exception_handler(RateLimitExceeded, _rate_limit_exceeded_handler)

@app.exception_handler(RequestValidationError)
async def validation_exception_handler(request: Request, exc: RequestValidationError):
    import logging
    logger = logging.getLogger("app.main")
    # Log only the error structure, not the offending body — Pydantic
    # echoes back submitted values which may include passwords / tokens.
    logger.error(
        "Validation Error at %s: %d field error(s)",
        request.url.path,
        len(exc.errors()),
    )
    return JSONResponse(
        status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
        content={"detail": exc.errors()},
    )


# CORS Origins configuration
allowed_origins = os.getenv("CORS_ORIGINS", "http://localhost:3000,http://localhost:5173").split(",")

# ============================================
# Security Middleware (OWASP A05: Security Misconfiguration)
# ============================================

if TRUST_PROXY_HEADERS:
    # Narrow the set of peers allowed to set forwarded-for headers. Wildcard
    # ("*") lets any upstream rewrite request.client.host, which defeats
    # rate-limit IP keying. Operators must list reverse-proxy IPs via
    # FORWARDED_ALLOW_IPS (uvicorn convention).
    _trusted_hosts = os.getenv("FORWARDED_ALLOW_IPS", "127.0.0.1").split(",")
    _trusted_hosts = [h.strip() for h in _trusted_hosts if h.strip()]
    app.add_middleware(ProxyHeadersMiddleware, trusted_hosts=_trusted_hosts)

# Query parameters whose value must be redacted before being logged.
# Add new sensitive param names here as they emerge.
_SENSITIVE_QUERY_PARAMS = {
    "token", "access_token", "refresh_token", "password", "api_key",
    "key", "secret", "code", "mfa_token",
}


def _safe_query_string(query: str) -> str:
    """Redact values for sensitive query params; return the rest verbatim."""
    if not query:
        return ""
    parts = []
    for pair in query.split("&"):
        if "=" in pair:
            name, _, _ = pair.partition("=")
            if name.lower() in _SENSITIVE_QUERY_PARAMS:
                parts.append(f"{name}=***")
                continue
        parts.append(pair)
    return "?" + "&".join(parts)


@app.middleware("http")
async def log_requests(request: Request, call_next):
    safe_target = f"{request.url.path}{_safe_query_string(request.url.query)}"
    logger.info(f"➡️ Incoming Request: {request.method} {safe_target}")
    try:
        response = await call_next(request)
        logger.info(f"⬅️ Response: {response.status_code}")
        return response
    except Exception as e:
        logger.error(f"❌ Request Failed: {e}")
        raise

@app.middleware("http")
async def add_security_headers(request: Request, call_next):
    """
    Fügt Security-Headers zu allen Responses hinzu

    OWASP-Best-Practices:
        - X-Content-Type-Options: nosniff (Verhindert MIME-Type-Sniffing)
        - X-Frame-Options: DENY (Verhindert Clickjacking)
        - X-XSS-Protection: 1; mode=block (XSS-Filter)
        - Strict-Transport-Security: HSTS (HTTPS-Only)
        - Content-Security-Policy: CSP (XSS-Mitigation)
    """
    response = await call_next(request)

    response.headers["X-Content-Type-Options"] = "nosniff"
    response.headers["X-Frame-Options"] = "DENY"
    response.headers["X-XSS-Protection"] = "1; mode=block"
    response.headers["Referrer-Policy"] = "strict-origin-when-cross-origin"

    # HSTS (nur in Production mit HTTPS)
    if not DEBUG:
        response.headers["Strict-Transport-Security"] = "max-age=31536000; includeSubDomains"

    # Content-Security-Policy
    connect_src = " ".join(["'self'"] + allowed_origins)
    csp = (
        f"default-src 'self'; "
        f"script-src 'self'; "
        f"style-src 'self' 'unsafe-inline'; "
        f"img-src 'self' data: https:; "
        f"font-src 'self' data:; "
        f"connect-src {connect_src}"
    )
    response.headers["Content-Security-Policy"] = csp

    return response




app.add_middleware(
    CORSMiddleware,
    allow_origins=allowed_origins,
    allow_credentials=True,
    allow_methods=["GET", "POST", "PUT", "PATCH", "DELETE"],
    allow_headers=["Authorization", "Content-Type", "Accept"],
    expose_headers=["X-Total-Count"]  # Für Pagination
)

# Trusted Host Middleware (Host-Header-Validation)
if not DEBUG:
    # Include 'backend' for Docker internal network communication
    allowed_hosts = os.getenv("ALLOWED_HOSTS", "localhost,127.0.0.1,backend").split(",")
    app.add_middleware(TrustedHostMiddleware, allowed_hosts=allowed_hosts)

# GZip Compression
app.add_middleware(GZipMiddleware, minimum_size=1000)


# ============================================
# Exception Handlers
# ============================================

@app.exception_handler(Exception)
async def global_exception_handler(request: Request, exc: Exception):
    """
    Global Exception Handler (verhindert Information Disclosure)

    OWASP A09: Security Logging and Monitoring Failures
    """
    logger.error(f"Unhandled error: {exc}", exc_info=True)

    # In Production: Keine detaillierten Fehlermeldungen (Information Disclosure)
    if DEBUG:
        return JSONResponse(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            content={"detail": str(exc)}
        )
    else:
        return JSONResponse(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            content={"detail": "Internal Server Error"}
        )


# ============================================
# Health Check & Monitoring
# ============================================

@app.get("/health", tags=["Health"])
async def health_check():
    """
    Health-Check-Endpoint für Load-Balancer & Monitoring.

    Returns only liveness — version, environment, and other build/runtime
    info are not exposed here to avoid handing reconnaissance data to
    unauthenticated callers.
    """
    return {"status": "healthy"}


@app.get("/", tags=["Root"])
@limiter.limit("10/minute")
async def root(request: Request):
    """
    Root-Endpoint mit API-Info
    """
    return {
        "name": "VulnManager API",
        "version": "1.0.0",
        "docs": "/docs" if DEBUG else "Disabled in Production",
        "health": "/health"
    }


# ============================================
# Routers
# ============================================

app.include_router(auth.router)
app.include_router(auth_admin.router)
if _HAS_OIDC and auth_oidc is not None:
    app.include_router(auth_oidc.router)
if _HAS_SAML and auth_saml is not None:
    app.include_router(auth_saml.router)
app.include_router(vulnerabilities.router)
app.include_router(nessus.router)
app.include_router(assets.router)
app.include_router(policies.router)
app.include_router(scans.router)
app.include_router(settings.router)
app.include_router(notifications.router)
app.include_router(groups.router)
app.include_router(reports.router)
app.include_router(audit.router)
app.include_router(compliance.router)


# ============================================
# Startup-Banner
# ============================================

if __name__ == "__main__":
    import uvicorn

    logger.info("""
    ╔══════════════════════════════════════════════════════╗
    ║              VulnManager v1.0.0                      ║
    ║   Vulnerability Management Dashboard                 ║
    ║   🔒 OWASP-Compliant | 🚀 FastAPI | 🤖 AI-Powered   ║
    ╚══════════════════════════════════════════════════════╝
    """)

    uvicorn.run(
        "app.main:app",
        host="0.0.0.0",
        port=8000,
        reload=DEBUG,
        log_level="info"
    )
