"""Analytics API router (experience stats, result trends, Pareto, sensitivity)."""
from fastapi import APIRouter, Depends, HTTPException, Query
from sqlalchemy.orm import Session

from ..database import get_db
from ..models.experience_case import ExperienceCase
from ..models.simulation_plan import SimulationPlan
from ..models.simulation_result import SimulationResult
from ..services.analytics import (
    compute_experience_stats,
    find_similar_cases,
    compute_trend_data,
    compute_pareto_frontier,
    compute_sensitivity,
    get_metric_defs,
)

router = APIRouter(prefix="/api/analytics", tags=["analytics"])


def _result_to_dict(r: SimulationResult) -> dict:
    return {
        "id": r.id,
        "plan_id": r.plan_id,
        "run_index": r.run_index,
        "status": r.status,
        "solve_time_s": r.solve_time_s,
        "params": r.get_params(),
        "metrics": r.get_metrics(),
        "error_message": r.error_message or "",
    }


def _case_to_dict(c: ExperienceCase) -> dict:
    return {
        "id": c.id,
        "source_plan_id": c.source_plan_id or "",
        "topology": c.topology or "SSSR",
        "model_path": c.model_path or "",
        "params": c.get_params(),
        "metrics": c.get_metrics(),
        "conclusion": c.conclusion or "",
        "tags": [t.strip() for t in (c.tags or "").split(",") if t.strip()],
        "rating": c.rating or 0,
        "created_at": c.created_at,
    }


# ---------------------------------------------------------------------------
# Metric definitions
# ---------------------------------------------------------------------------

@router.get("/metrics")
def list_metrics():
    """List all available metric definitions for frontend charts."""
    return {"metrics": get_metric_defs()}


# ---------------------------------------------------------------------------
# Experience library analytics
# ---------------------------------------------------------------------------

@router.get("/experience/stats")
def experience_stats(
    topology: str | None = None,
    db: Session = Depends(get_db),
):
    """Compute aggregate statistics for the experience library."""
    query = db.query(ExperienceCase)
    if topology:
        query = query.filter(ExperienceCase.topology == topology)
    cases = [_case_to_dict(c) for c in query.all()]
    return compute_experience_stats(cases)


@router.post("/experience/similar")
def experience_similar(
    data: dict,
    topology: str | None = None,
    top_k: int = Query(5, ge=1, le=50),
    tolerance: float = Query(0.3, ge=0.0, le=1.0),
    db: Session = Depends(get_db),
):
    """Find experience cases similar to target parameters.

    Request body: {"params": {"Airgap": 1.0, "RMSCurrent": 21, ...}}
    """
    target_params = data.get("params", {})
    if not target_params:
        raise HTTPException(status_code=400, detail="params field is required")

    query = db.query(ExperienceCase)
    if topology:
        query = query.filter(ExperienceCase.topology == topology)
    cases = [_case_to_dict(c) for c in query.all()]
    similar = find_similar_cases(target_params, cases, top_k=top_k, tolerance=tolerance)
    return {"total": len(similar), "items": similar}


# ---------------------------------------------------------------------------
# Simulation result analytics
# ---------------------------------------------------------------------------

@router.get("/plans/{plan_id}/trend")
def plan_trend(
    plan_id: int,
    param_key: str = Query(..., description="Parameter name for X axis"),
    metric_key: str = Query(..., description="Metric name for Y axis"),
    db: Session = Depends(get_db),
):
    """Compute trend data for a parameter vs metric scatter plot."""
    plan = db.query(SimulationPlan).filter(SimulationPlan.id == plan_id).first()
    if not plan:
        raise HTTPException(status_code=404, detail="Plan not found")
    results = [_result_to_dict(r) for r in db.query(SimulationResult).filter(
        SimulationResult.plan_id == plan_id
    ).order_by(SimulationResult.run_index.asc()).all()]
    return compute_trend_data(results, param_key, metric_key)


@router.get("/plans/{plan_id}/pareto")
def plan_pareto(
    plan_id: int,
    x_metric: str = Query("total_losses_w", description="X axis metric"),
    y_metric: str = Query("efficiency_pct", description="Y axis metric"),
    db: Session = Depends(get_db),
):
    """Compute Pareto frontier for two metrics in a plan."""
    plan = db.query(SimulationPlan).filter(SimulationPlan.id == plan_id).first()
    if not plan:
        raise HTTPException(status_code=404, detail="Plan not found")
    results = [_result_to_dict(r) for r in db.query(SimulationResult).filter(
        SimulationResult.plan_id == plan_id
    ).all()]
    return compute_pareto_frontier(results, x_metric=x_metric, y_metric=y_metric)


@router.get("/plans/{plan_id}/sensitivity")
def plan_sensitivity(
    plan_id: int,
    metric_key: str = Query(..., description="Target metric for sensitivity analysis"),
    db: Session = Depends(get_db),
):
    """Compute parameter sensitivity ranking for a target metric."""
    plan = db.query(SimulationPlan).filter(SimulationPlan.id == plan_id).first()
    if not plan:
        raise HTTPException(status_code=404, detail="Plan not found")
    results = [_result_to_dict(r) for r in db.query(SimulationResult).filter(
        SimulationResult.plan_id == plan_id
    ).all()]
    sensitivities = compute_sensitivity(results, metric_key)
    return {"metric": metric_key, "total_params": len(sensitivities), "items": sensitivities}


# ---------------------------------------------------------------------------
# Project-level analytics (aggregate all plans in a project)
# ---------------------------------------------------------------------------

@router.get("/projects/{project_id}/overview")
def project_overview(
    project_id: int,
    db: Session = Depends(get_db),
):
    """Get overview analytics for a project (all plans and results)."""
    from ..models.project import Project

    project = db.query(Project).filter(Project.id == project_id).first()
    if not project:
        raise HTTPException(status_code=404, detail="Project not found")

    plans = db.query(SimulationPlan).filter(SimulationPlan.project_id == project_id).all()
    plan_ids = [p.id for p in plans]

    total_results = 0
    ok_results = 0
    failed_results = 0
    all_results = []

    if plan_ids:
        results = db.query(SimulationResult).filter(
            SimulationResult.plan_id.in_(plan_ids)
        ).all()
        total_results = len(results)
        ok_results = sum(1 for r in results if r.status == "OK")
        failed_results = sum(1 for r in results if r.status != "OK")
        all_results = [_result_to_dict(r) for r in results]

    # Best efficiency and torque from OK results
    best_eff = 0.0
    best_torque = 0.0
    for r in all_results:
        if r["status"] == "OK":
            eff = r["metrics"].get("efficiency_pct", 0)
            torque = r["metrics"].get("tavg_nm", 0)
            if isinstance(eff, (int, float)):
                best_eff = max(best_eff, eff)
            if isinstance(torque, (int, float)):
                best_torque = max(best_torque, torque)

    return {
        "project_id": project_id,
        "project_name": project.name,
        "total_plans": len(plans),
        "total_results": total_results,
        "ok_results": ok_results,
        "failed_results": failed_results,
        "best_efficiency_pct": round(best_eff, 2),
        "best_torque_nm": round(best_torque, 4),
        "plans": [
            {
                "id": p.id,
                "name": p.name,
                "plan_id": p.plan_id,
                "status": p.status,
                "estimated_points": p.estimated_points,
                "result_count": sum(1 for r in all_results if r["plan_id"] == p.id),
            }
            for p in plans
        ],
    }
