"""SprintQuiz FastAPI application entry point."""
from contextlib import asynccontextmanager

# Force IPv4 resolution globally in Python socket library.
# This prevents Errno 99 (Cannot assign requested address) inside Docker on IPv4-only hosts.
import socket
_old_getaddrinfo = socket.getaddrinfo
def _new_getaddrinfo(*args, **kwargs):
    responses = _old_getaddrinfo(*args, **kwargs)
    return [r for r in responses if r[0] == socket.AF_INET]
socket.getaddrinfo = _new_getaddrinfo

import redis.asyncio as redis
from fastapi import FastAPI, Request
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse

from app.core.config import settings
from app.core.logging import get_logger, setup_logging
from app.routers import assignments, auth, documents, quizzes, reports, signoff, users

setup_logging()
logger = get_logger("app")


@asynccontextmanager
async def lifespan(app: FastAPI):
    """Startup and shutdown lifecycle."""
    logger.info("app_starting", env=settings.APP_ENV)
    # Redis connection
    app.state.redis = redis.from_url(settings.REDIS_URL, decode_responses=True)
    try:
        await app.state.redis.ping()
        logger.info("redis_connected")
    except Exception as e:
        logger.warning("redis_unavailable", error=str(e))

    yield

    # Shutdown
    await app.state.redis.aclose()
    logger.info("app_stopped")


app = FastAPI(
    title="SprintQuiz API",
    description="Internal L&D quiz platform for Credit Fair",
    version="1.0.0",
    lifespan=lifespan,
    docs_url="/api/docs",
    redoc_url="/api/redoc",
)

# CORS
app.add_middleware(
    CORSMiddleware,
    allow_origins=settings.cors_origins_list,
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

# Register routers
app.include_router(auth.router)
app.include_router(users.router)
app.include_router(documents.router)
app.include_router(quizzes.router)
app.include_router(assignments.router)
app.include_router(reports.router)
app.include_router(signoff.router)


# ── Health ──────────────────────────────────────────────
@app.get("/health", tags=["health"])
async def health_check() -> dict:
    """Health check endpoint."""
    db_status = "unknown"
    redis_status = "unknown"

    try:
        from sqlalchemy import text

        from app.db.base import engine
        async with engine.connect() as conn:
            await conn.execute(text("SELECT 1"))
        db_status = "ok"
    except Exception as e:
        db_status = f"error: {e}"

    try:
        await app.state.redis.ping()
        redis_status = "ok"
    except Exception as e:
        redis_status = f"error: {e}"

    return {
        "status": "ok" if db_status == "ok" and redis_status == "ok" else "degraded",
        "database": db_status,
        "redis": redis_status,
    }


@app.get("/readiness", tags=["health"])
async def readiness_check() -> dict:
    """Readiness check — requires DB."""
    try:
        from sqlalchemy import text

        from app.db.base import engine
        async with engine.connect() as conn:
            await conn.execute(text("SELECT 1"))
        return {"status": "ready"}
    except Exception as e:
        return JSONResponse(
            status_code=503,
            content={"status": "not_ready", "error": str(e)},
        )


# ── Global exception handler ────────────────────────────
@app.exception_handler(Exception)
async def unhandled_exception_handler(request: Request, exc: Exception):
    logger.error(
        "unhandled_exception",
        error=str(exc),
        error_type=type(exc).__name__,
        path=str(request.url),
    )
    return JSONResponse(
        status_code=500,
        content={"detail": "Internal server error", "type": type(exc).__name__},
    )
