"""
FastAPI REST API for Educational Content Evaluator.

This module provides a REST API for evaluating educational content across
multiple dimensions including accuracy, curriculum alignment, and engagement.

The API is designed to work seamlessly with both AWS Lambda (via Mangum)
and traditional server deployments (EC2, Docker, etc.).
"""

import logging
import time
from contextlib import asynccontextmanager

from fastapi import FastAPI, HTTPException, Request, status
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse

from .dependencies import EvaluationServiceDep
from .models import (
    CurriculumsResponse,
    ErrorResponse,
    EvaluationRequest,
    HealthResponse,
)
from ..config.settings import settings

logger = logging.getLogger(__name__)

# API Version
API_VERSION = "1.0.0"


@asynccontextmanager
async def lifespan(app: FastAPI):
    """
    Lifespan context manager for FastAPI application.
    
    Handles startup and shutdown events.
    """
    # Startup
    logger.info(f"Starting Educational Content Evaluator API v{API_VERSION}")
    
    yield
    
    # Shutdown
    logger.info("Shutting down Educational Content Evaluator API")


# Create FastAPI application
app = FastAPI(
    title="Educational Content Evaluator API",
    description=(
        "AI-powered educational content evaluation service that assesses questions, "
        "quizzes, reading passages, and other educational materials across multiple "
        "quality dimensions including accuracy, curriculum alignment, and engagement."
    ),
    version=API_VERSION,
    lifespan=lifespan,
    docs_url="/docs",
    redoc_url="/redoc",
    openapi_url="/openapi.json",
)

# CORS middleware (configure for your deployment)
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],  # Configure this for production
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)


# Request timing middleware
@app.middleware("http")
async def add_process_time_header(request: Request, call_next):
    """Add processing time header to responses."""
    start_time = time.time()
    response = await call_next(request)
    process_time = time.time() - start_time
    response.headers["X-Process-Time"] = str(process_time)
    return response


# Exception handlers
@app.exception_handler(ValueError)
async def value_error_handler(request: Request, exc: ValueError):
    """Handle ValueError exceptions."""
    logger.warning(f"ValueError: {exc}")
    return JSONResponse(
        status_code=status.HTTP_400_BAD_REQUEST,
        content=ErrorResponse(
            error="ValidationError",
            message=str(exc)
        ).model_dump()
    )


@app.exception_handler(Exception)
async def general_exception_handler(request: Request, exc: Exception):
    """Handle unexpected exceptions."""
    logger.error(f"Unexpected error: {exc}", exc_info=True)
    return JSONResponse(
        status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
        content=ErrorResponse(
            error="InternalServerError",
            message="An unexpected error occurred",
            detail=str(exc) if settings.LOG_LEVEL == "DEBUG" else None
        ).model_dump()
    )


# API Endpoints
@app.get(
    "/health",
    response_model=HealthResponse,
    tags=["Health"],
    summary="Health check endpoint",
    description="Check if the service is healthy and get version information"
)
async def health_check() -> HealthResponse:
    """
    Health check endpoint.
    
    Returns service health status and version information.
    """
    return HealthResponse(
        status="healthy",
        version=API_VERSION,
        service="Educational Content Evaluator"
    )


@app.get(
    "/curriculums",
    response_model=CurriculumsResponse,
    tags=["Metadata"],
    summary="List available curriculums",
    description=(
        "Get information about curriculum support. The evaluation service uses "
        "InceptAPI for curriculum search, which maintains the authoritative list "
        "of supported curricula. This endpoint returns the default curriculum; "
        "other curricula may be supported - the API will return an error if an "
        "unsupported curriculum is requested."
    )
)
async def list_curriculums() -> CurriculumsResponse:
    """
    List curriculum information.
    
    Returns the default curriculum. The InceptAPI handles curriculum validation
    and will return descriptive errors if an unsupported curriculum is requested.
    """
    return CurriculumsResponse(
        curriculums=[settings.DEFAULT_CURRICULUM],
        default=settings.DEFAULT_CURRICULUM
    )


@app.post(
    "/evaluate",
    tags=["Evaluation"],
    summary="Evaluate educational content",
    description=(
        "Evaluate educational content (questions, quizzes, reading passages, etc.) "
        "across multiple quality dimensions. Returns structured evaluation results "
        "with scores, reasoning, and suggested improvements."
    ),
    response_description="Structured evaluation results with content-specific metrics"
)
async def evaluate_content(
    request: EvaluationRequest,
    service: EvaluationServiceDep
) -> dict:
    """
    Evaluate educational content.
    
    This endpoint accepts any educational content and:
    1. Classifies the content type (question, quiz, reading passage, etc.)
    2. Routes to the appropriate evaluator
    3. Returns structured evaluation results with scores and suggestions
    
    Args:
        request: EvaluationRequest with content and optional curriculum
        service: Injected EvaluationService instance
    
    Returns:
        Dictionary with evaluation results including:
        - content_type: The classified type of content
        - overall: Overall quality score with reasoning
        - factual_accuracy: Binary accuracy score
        - educational_accuracy: Binary educational intent score
        - Additional content-specific metrics
    
    Raises:
        HTTPException: If evaluation fails or curriculum is invalid
    """
    logger.info(
        f"Evaluating content (length: {len(request.content)} chars, "
        f"curriculum: {request.curriculum}"
        f"{', with generation_prompt' if request.generation_prompt else ''})"
    )
    
    try:
        # Perform evaluation (returns Pydantic model)
        # InceptAPI will validate curriculum and return error if unsupported
        result = await service.evaluate(
            content=request.content,
            curriculum=request.curriculum,
            generation_prompt=request.generation_prompt
        )
        
        # Convert to dictionary for JSON response
        result_dict = result.model_dump()
        
        logger.info(
            f"Evaluation complete. Type: {result_dict['content_type']}, "
            f"Overall: {result_dict['overall']['score']:.2f}"
        )
        
        return result_dict
        
    except ValueError as e:
        # Validation errors (e.g., unsupported curriculum)
        logger.warning(f"Validation error during evaluation: {e}")
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=str(e)
        )
    except Exception as e:
        # Unexpected errors
        logger.error(f"Error during evaluation: {e}", exc_info=True)
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"Evaluation failed: {str(e)}"
        )


# Root endpoint
@app.get(
    "/",
    include_in_schema=False,
    tags=["Root"]
)
async def root():
    """Root endpoint - provides API information."""
    return {
        "service": "Educational Content Evaluator API",
        "version": API_VERSION,
        "docs": "/docs",
        "health": "/health",
        "endpoints": {
            "evaluate": "POST /evaluate",
            "curriculums": "GET /curriculums",
            "health": "GET /health"
        }
    }


# For local development and testing
if __name__ == "__main__":
    import uvicorn
    
    uvicorn.run(
        "inceptbench_new.api.main:app",
        host="0.0.0.0",
        port=8000,
        reload=True,
        log_level="info"
    )
