"""AI Result Analysis router (P3-M4).

Endpoints for AI-powered simulation result analysis,
multi-fidelity calibration, confidence grading, and convergence checks.
"""
from typing import Dict, Any, Optional, List
from fastapi import APIRouter, HTTPException
from pydantic import BaseModel, Field

from ..services.result_analyst import get_result_analyst, FIDELITY_LEVELS

router = APIRouter(prefix="/api/analysis", tags=["Result Analysis"])


class AnalyzeRequest(BaseModel):
    """Request for result analysis."""
    results: List[Dict[str, Any]] = Field(..., description="List of simulation result dicts")
    targets: Optional[Dict[str, float]] = Field(default=None, description="Target values for key metrics")
    fidelity: str = Field(default="L3", description="Simulation fidelity level (L0-L4)")
    scan_parameters: Optional[List[str]] = Field(default=None, description="List of scanned parameter names")


class CalibrateRequest(BaseModel):
    """Request for multi-fidelity calibration."""
    metric: str = Field(..., description="Metric name (tavg_nm, efficiency_pct, etc.)")
    value: float = Field(..., description="Raw value from simulation")
    fidelity: str = Field(..., description="Fidelity level (L0-L4)")


class UpdateCalibrationRequest(BaseModel):
    """Request to update calibration factors."""
    low_fidelity_results: Dict[str, float]
    high_fidelity_results: Dict[str, float]
    low_fidelity: str
    high_fidelity: str = Field(default="L4")


@router.post("/analyze")
def analyze_results(request: AnalyzeRequest):
    """Analyze simulation results with AI and quantitative methods.

    Returns comprehensive analysis including:
    - Summary and key metrics
    - Target comparison
    - Multi-fidelity calibration
    - Six convergence criteria checks
    - Confidence grade (A-D)
    - AI-powered trend analysis and optimization suggestions
    """
    if not request.results:
        raise HTTPException(status_code=400, detail="No results provided")

    if request.fidelity not in FIDELITY_LEVELS:
        raise HTTPException(status_code=400, detail=f"Invalid fidelity level: {request.fidelity}. Use L0-L4.")

    try:
        analyst = get_result_analyst()
        result = analyst.analyze(
            results=request.results,
            targets=request.targets,
            fidelity=request.fidelity,
            scan_parameters=request.scan_parameters,
        )
        return result
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"Analysis failed: {str(e)}")


@router.post("/calibrate")
def calibrate_result(request: CalibrateRequest):
    """Calibrate a low-fidelity result to high-fidelity equivalent.

    Uses multi-fidelity calibration factors to correct known biases
    between different simulation fidelity levels.
    """
    if request.fidelity not in FIDELITY_LEVELS:
        raise HTTPException(status_code=400, detail=f"Invalid fidelity level: {request.fidelity}")

    analyst = get_result_analyst()
    result = analyst.calibrator.calibrate(request.metric, request.value, request.fidelity)
    return result


@router.post("/calibration/update")
def update_calibration(request: UpdateCalibrationRequest):
    """Update calibration factors using paired low-high fidelity results.

    When you have both low-fidelity and high-fidelity results for the
    same design point, use this to refine the calibration factors.
    """
    if request.low_fidelity not in FIDELITY_LEVELS:
        raise HTTPException(status_code=400, detail=f"Invalid low fidelity: {request.low_fidelity}")
    if request.high_fidelity not in FIDELITY_LEVELS:
        raise HTTPException(status_code=400, detail=f"Invalid high fidelity: {request.high_fidelity}")

    analyst = get_result_analyst()
    analyst.calibrator.update_calibration(
        low_fidelity_results=request.low_fidelity_results,
        high_fidelity_results=request.high_fidelity_results,
        low_fidelity=request.low_fidelity,
        high_fidelity=request.high_fidelity,
    )
    return {
        "status": "updated",
        "current_factors": analyst.calibrator.calibration_factors,
        "n_calibration_points": len(analyst.calibrator.calibration_data),
    }


@router.get("/fidelity-levels")
def get_fidelity_levels():
    """Get available fidelity levels and their properties."""
    return {
        "levels": FIDELITY_LEVELS,
        "description": "Multi-fidelity hierarchy per third-party review. L0=analytic, L4=full 3D transient+thermal.",
    }


@router.get("/confidence/scale")
def get_confidence_scale():
    """Get confidence grade scale definition."""
    return {
        "grades": {
            "A": {"min_score": 85, "description": "High confidence. High fidelity, sufficient samples, converged, no anomalies."},
            "B": {"min_score": 70, "description": "Medium-high confidence. Good fidelity, reasonable samples, mostly converged."},
            "C": {"min_score": 50, "description": "Medium confidence. Lower fidelity or limited samples. Use with caution."},
            "D": {"min_score": 0, "description": "Low confidence. Insufficient data or significant anomalies. Results unreliable."},
        },
        "scoring": {
            "fidelity": "40% (L4=40, L3=32, L2=24, L1=12, L0=4)",
            "sample_density": "25% (min(25, points_per_dimension * 2.5))",
            "convergence": "25% (passed_criteria / 6 * 25)",
            "anomaly_penalty": "-10% max (min(10, anomalies * 3))",
        },
    }


@router.get("/convergence/criteria")
def get_convergence_criteria():
    """Get six convergence criteria definitions."""
    return {
        "criteria": [
            {"id": 1, "name": "objective_stability", "description": "Objective function change rate < 1% over last 5 points"},
            {"id": 2, "name": "optimum_stability", "description": "Optimum location stable over last 5 batches"},
            {"id": 3, "name": "surrogate_error", "description": "Surrogate model prediction error < 5%"},
            {"id": 4, "name": "constraint_satisfaction", "description": "Constraint satisfaction rate > 95%"},
            {"id": 5, "name": "sample_density", "description": "Sample density > 10 points per dimension"},
            {"id": 6, "name": "physical_consistency", "description": "All metrics within physically reasonable bounds"},
        ],
        "convergence_threshold": ">= 4 of 6 criteria passed",
    }
