"""
Unit Analytics API - Routes.

All API endpoints for learning gain, stop-level, misconception,
student timeline, class comparison, export, and dashboard analytics.
"""

import logging
import statistics
from datetime import datetime
from typing import Optional, Dict, Any, List

from fastapi import APIRouter, Query

from .analytics_models import (
    TimeRange,
    LearningGainData,
    LearningGainSummary,
    StopPerformance,
    UnitPerformanceDetail,
    MisconceptionEntry,
    MisconceptionReport,
    StudentProgressTimeline,
    ClassComparisonData,
)
from .analytics_helpers import (
    get_analytics_database,
    calculate_gain_distribution,
    calculate_trend,
    calculate_difficulty_rating,
)

logger = logging.getLogger(__name__)

router = APIRouter(tags=["Unit Analytics"])


# ==============================================
# API Endpoints - Learning Gain
# ==============================================

# NOTE: Static routes must come BEFORE dynamic routes like /{unit_id}
@router.get("/learning-gain/compare")
async def compare_learning_gains(
    unit_ids: str = Query(..., description="Comma-separated unit IDs"),
    class_id: Optional[str] = Query(None),
    time_range: TimeRange = Query(TimeRange.MONTH),
) -> Dict[str, Any]:
    """
    Compare learning gains across multiple units.
    """
    unit_list = [u.strip() for u in unit_ids.split(",")]
    comparisons = []

    for unit_id in unit_list:
        try:
            summary = await get_learning_gain_analysis(unit_id, class_id, time_range)
            comparisons.append({
                "unit_id": unit_id,
                "avg_gain": summary.avg_gain,
                "median_gain": summary.median_gain,
                "total_students": summary.total_students,
                "positive_rate": summary.positive_gain_count / max(summary.total_students, 1),
            })
        except Exception as e:
            logger.error(f"Failed to get comparison for {unit_id}: {e}")

    return {
        "time_range": time_range.value,
        "class_id": class_id,
        "comparisons": sorted(comparisons, key=lambda x: x["avg_gain"], reverse=True),
    }


@router.get("/learning-gain/{unit_id}", response_model=LearningGainSummary)
async def get_learning_gain_analysis(
    unit_id: str,
    class_id: Optional[str] = Query(None, description="Filter by class"),
    time_range: TimeRange = Query(TimeRange.MONTH, description="Time range for analysis"),
) -> LearningGainSummary:
    """
    Get detailed pre/post learning gain analysis for a unit.
    """
    db = await get_analytics_database()
    individual_gains = []

    if db:
        try:
            sessions = await db.get_unit_sessions_with_scores(
                unit_id=unit_id,
                class_id=class_id,
                time_range=time_range.value
            )

            for session in sessions:
                if session.get("precheck_score") is not None and session.get("postcheck_score") is not None:
                    gain = session["postcheck_score"] - session["precheck_score"]
                    individual_gains.append(LearningGainData(
                        student_id=session["student_id"],
                        student_name=session.get("student_name", session["student_id"][:8]),
                        unit_id=unit_id,
                        precheck_score=session["precheck_score"],
                        postcheck_score=session["postcheck_score"],
                        learning_gain=gain,
                    ))
        except Exception as e:
            logger.error(f"Failed to get learning gain data: {e}")

    # Calculate statistics
    if not individual_gains:
        return LearningGainSummary(
            unit_id=unit_id,
            unit_title=f"Unit {unit_id}",
            total_students=0,
            avg_precheck=0.0, avg_postcheck=0.0,
            avg_gain=0.0, median_gain=0.0, std_deviation=0.0,
            positive_gain_count=0, negative_gain_count=0, no_change_count=0,
            gain_distribution={}, individual_gains=[],
        )

    gains = [g.learning_gain for g in individual_gains]
    prechecks = [g.precheck_score for g in individual_gains]
    postchecks = [g.postcheck_score for g in individual_gains]

    avg_gain = statistics.mean(gains)
    median_gain = statistics.median(gains)
    std_dev = statistics.stdev(gains) if len(gains) > 1 else 0.0

    # Calculate percentiles
    sorted_gains = sorted(gains)
    for data in individual_gains:
        rank = sorted_gains.index(data.learning_gain) + 1
        data.percentile = rank / len(sorted_gains) * 100

    return LearningGainSummary(
        unit_id=unit_id,
        unit_title=f"Unit {unit_id}",
        total_students=len(individual_gains),
        avg_precheck=statistics.mean(prechecks),
        avg_postcheck=statistics.mean(postchecks),
        avg_gain=avg_gain,
        median_gain=median_gain,
        std_deviation=std_dev,
        positive_gain_count=sum(1 for g in gains if g > 0.01),
        negative_gain_count=sum(1 for g in gains if g < -0.01),
        no_change_count=sum(1 for g in gains if -0.01 <= g <= 0.01),
        gain_distribution=calculate_gain_distribution(gains),
        individual_gains=sorted(individual_gains, key=lambda x: x.learning_gain, reverse=True),
    )


# ==============================================
# API Endpoints - Stop-Level Analytics
# ==============================================

@router.get("/unit/{unit_id}/stops", response_model=UnitPerformanceDetail)
async def get_unit_stop_analytics(
    unit_id: str,
    class_id: Optional[str] = Query(None),
    time_range: TimeRange = Query(TimeRange.MONTH),
) -> UnitPerformanceDetail:
    """
    Get detailed stop-level performance analytics.
    """
    db = await get_analytics_database()
    stops_data = []

    if db:
        try:
            stop_stats = await db.get_stop_performance(
                unit_id=unit_id, class_id=class_id, time_range=time_range.value
            )

            for stop in stop_stats:
                difficulty = calculate_difficulty_rating(
                    stop.get("success_rate", 0.5),
                    stop.get("avg_attempts", 1.0)
                )
                stops_data.append(StopPerformance(
                    stop_id=stop["stop_id"],
                    stop_label=stop.get("stop_label", stop["stop_id"]),
                    attempts_total=stop.get("total_attempts", 0),
                    success_rate=stop.get("success_rate", 0.0),
                    avg_time_seconds=stop.get("avg_time_seconds", 0.0),
                    avg_attempts_before_success=stop.get("avg_attempts", 1.0),
                    common_errors=stop.get("common_errors", []),
                    difficulty_rating=difficulty,
                ))

            unit_stats = await db.get_unit_overall_stats(unit_id, class_id, time_range.value)
        except Exception as e:
            logger.error(f"Failed to get stop analytics: {e}")
            unit_stats = {}
    else:
        unit_stats = {}

    # Identify bottleneck stops
    bottlenecks = [
        s.stop_id for s in stops_data
        if s.difficulty_rating > 3.5 or s.success_rate < 0.6
    ]

    return UnitPerformanceDetail(
        unit_id=unit_id,
        unit_title=f"Unit {unit_id}",
        template=unit_stats.get("template", "unknown"),
        total_sessions=unit_stats.get("total_sessions", 0),
        completed_sessions=unit_stats.get("completed_sessions", 0),
        completion_rate=unit_stats.get("completion_rate", 0.0),
        avg_duration_minutes=unit_stats.get("avg_duration_minutes", 0.0),
        stops=stops_data,
        bottleneck_stops=bottlenecks,
    )


# ==============================================
# API Endpoints - Misconception Tracking
# ==============================================

@router.get("/misconceptions", response_model=MisconceptionReport)
async def get_misconception_report(
    class_id: Optional[str] = Query(None),
    unit_id: Optional[str] = Query(None),
    time_range: TimeRange = Query(TimeRange.MONTH),
    limit: int = Query(20, ge=1, le=100),
) -> MisconceptionReport:
    """
    Get comprehensive misconception report.
    """
    db = await get_analytics_database()
    misconceptions = []

    if db:
        try:
            raw_misconceptions = await db.get_misconceptions(
                class_id=class_id, unit_id=unit_id,
                time_range=time_range.value, limit=limit
            )

            for m in raw_misconceptions:
                misconceptions.append(MisconceptionEntry(
                    concept_id=m["concept_id"],
                    concept_label=m["concept_label"],
                    misconception_text=m["misconception_text"],
                    frequency=m["frequency"],
                    affected_student_ids=m.get("student_ids", []),
                    unit_id=m["unit_id"],
                    stop_id=m["stop_id"],
                    detected_via=m.get("detected_via", "unknown"),
                    first_detected=m.get("first_detected", datetime.utcnow()),
                    last_detected=m.get("last_detected", datetime.utcnow()),
                ))
        except Exception as e:
            logger.error(f"Failed to get misconceptions: {e}")

    # Group by unit
    by_unit = {}
    for m in misconceptions:
        if m.unit_id not in by_unit:
            by_unit[m.unit_id] = []
        by_unit[m.unit_id].append(m)

    trending_up = misconceptions[:3] if misconceptions else []
    resolved = []

    return MisconceptionReport(
        class_id=class_id,
        time_range=time_range.value,
        total_misconceptions=sum(m.frequency for m in misconceptions),
        unique_concepts=len(set(m.concept_id for m in misconceptions)),
        most_common=sorted(misconceptions, key=lambda x: x.frequency, reverse=True)[:10],
        by_unit=by_unit,
        trending_up=trending_up,
        resolved=resolved,
    )


@router.get("/misconceptions/student/{student_id}")
async def get_student_misconceptions(
    student_id: str,
    time_range: TimeRange = Query(TimeRange.ALL),
) -> Dict[str, Any]:
    """
    Get misconceptions for a specific student.
    """
    db = await get_analytics_database()

    if db:
        try:
            misconceptions = await db.get_student_misconceptions(
                student_id=student_id, time_range=time_range.value
            )
            return {
                "student_id": student_id,
                "misconceptions": misconceptions,
                "recommended_remediation": [
                    {"concept": m["concept_label"], "activity": f"Review {m['unit_id']}/{m['stop_id']}"}
                    for m in misconceptions[:5]
                ]
            }
        except Exception as e:
            logger.error(f"Failed to get student misconceptions: {e}")

    return {
        "student_id": student_id,
        "misconceptions": [],
        "recommended_remediation": [],
    }


# ==============================================
# API Endpoints - Student Progress Timeline
# ==============================================

@router.get("/student/{student_id}/timeline", response_model=StudentProgressTimeline)
async def get_student_timeline(
    student_id: str,
    time_range: TimeRange = Query(TimeRange.ALL),
) -> StudentProgressTimeline:
    """
    Get detailed progress timeline for a student.
    """
    db = await get_analytics_database()
    timeline = []
    scores = []

    if db:
        try:
            sessions = await db.get_student_sessions(
                student_id=student_id, time_range=time_range.value
            )

            for session in sessions:
                timeline.append({
                    "date": session.get("started_at"),
                    "unit_id": session.get("unit_id"),
                    "completed": session.get("completed_at") is not None,
                    "precheck": session.get("precheck_score"),
                    "postcheck": session.get("postcheck_score"),
                    "duration_minutes": session.get("duration_seconds", 0) // 60,
                })
                if session.get("postcheck_score") is not None:
                    scores.append(session["postcheck_score"])
        except Exception as e:
            logger.error(f"Failed to get student timeline: {e}")

    trend = calculate_trend(scores) if scores else "insufficient_data"

    return StudentProgressTimeline(
        student_id=student_id,
        student_name=f"Student {student_id[:8]}",
        units_completed=sum(1 for t in timeline if t["completed"]),
        total_time_minutes=sum(t["duration_minutes"] for t in timeline),
        avg_score=statistics.mean(scores) if scores else 0.0,
        trend=trend,
        timeline=timeline,
    )


# ==============================================
# API Endpoints - Class Comparison
# ==============================================

@router.get("/compare/classes", response_model=List[ClassComparisonData])
async def compare_classes(
    class_ids: str = Query(..., description="Comma-separated class IDs"),
    time_range: TimeRange = Query(TimeRange.MONTH),
) -> List[ClassComparisonData]:
    """
    Compare performance across multiple classes.
    """
    class_list = [c.strip() for c in class_ids.split(",")]
    comparisons = []

    db = await get_analytics_database()
    if db:
        for class_id in class_list:
            try:
                stats = await db.get_class_aggregate_stats(class_id, time_range.value)
                comparisons.append(ClassComparisonData(
                    class_id=class_id,
                    class_name=stats.get("class_name", f"Klasse {class_id[:8]}"),
                    student_count=stats.get("student_count", 0),
                    units_assigned=stats.get("units_assigned", 0),
                    avg_completion_rate=stats.get("avg_completion_rate", 0.0),
                    avg_learning_gain=stats.get("avg_learning_gain", 0.0),
                    avg_time_per_unit=stats.get("avg_time_per_unit", 0.0),
                ))
            except Exception as e:
                logger.error(f"Failed to get stats for class {class_id}: {e}")

    return sorted(comparisons, key=lambda x: x.avg_learning_gain, reverse=True)


