"""
FastAPI routes for Dashboard, Executive Dashboard, and Reports.

Endpoints:
- /dashboard: Main compliance dashboard
- /dashboard/executive: Executive summary for managers
- /dashboard/trend: Compliance score trend over time
- /score: Quick compliance score
- /reports: Report generation
"""

import logging
from datetime import datetime, timedelta
from calendar import month_abbr
from typing import Optional

from fastapi import APIRouter, Depends, HTTPException, Query
from sqlalchemy.orm import Session

from classroom_engine.database import get_db

from ..db import (
    RegulationRepository,
    RequirementRepository,
    ControlRepository,
    EvidenceRepository,
    RiskRepository,
)
from .schemas import (
    DashboardResponse,
    ExecutiveDashboardResponse,
    TrendDataPoint,
    RiskSummary,
    DeadlineItem,
    TeamWorkloadItem,
)

logger = logging.getLogger(__name__)
router = APIRouter(tags=["compliance-dashboard"])


# ============================================================================
# Dashboard
# ============================================================================

@router.get("/dashboard", response_model=DashboardResponse)
async def get_dashboard(db: Session = Depends(get_db)):
    """Get compliance dashboard statistics."""
    reg_repo = RegulationRepository(db)
    req_repo = RequirementRepository(db)
    ctrl_repo = ControlRepository(db)
    evidence_repo = EvidenceRepository(db)
    risk_repo = RiskRepository(db)

    # Regulations
    regulations = reg_repo.get_active()
    requirements = req_repo.get_all()

    # Controls statistics
    ctrl_stats = ctrl_repo.get_statistics()
    controls = ctrl_repo.get_all()

    # Group controls by domain
    controls_by_domain = {}
    for ctrl in controls:
        domain = ctrl.domain.value if ctrl.domain else "unknown"
        if domain not in controls_by_domain:
            controls_by_domain[domain] = {"total": 0, "pass": 0, "partial": 0, "fail": 0, "planned": 0}
        controls_by_domain[domain]["total"] += 1
        status = ctrl.status.value if ctrl.status else "planned"
        if status in controls_by_domain[domain]:
            controls_by_domain[domain][status] += 1

    # Evidence statistics
    evidence_stats = evidence_repo.get_statistics()

    # Risk statistics
    risks = risk_repo.get_all()
    risks_by_level = {"low": 0, "medium": 0, "high": 0, "critical": 0}
    for risk in risks:
        level = risk.inherent_risk.value if risk.inherent_risk else "low"
        if level in risks_by_level:
            risks_by_level[level] += 1

    # Calculate compliance score - use pre-calculated score from get_statistics()
    # or compute from by_status dict
    score = ctrl_stats.get("compliance_score", 0.0)

    return DashboardResponse(
        compliance_score=round(score, 1),
        total_regulations=len(regulations),
        total_requirements=len(requirements),
        total_controls=ctrl_stats.get("total", 0),
        controls_by_status=ctrl_stats.get("by_status", {}),
        controls_by_domain=controls_by_domain,
        total_evidence=evidence_stats.get("total", 0),
        evidence_by_status=evidence_stats.get("by_status", {}),
        total_risks=len(risks),
        risks_by_level=risks_by_level,
        recent_activity=[],
    )


@router.get("/score")
async def get_compliance_score(db: Session = Depends(get_db)):
    """Get just the compliance score."""
    ctrl_repo = ControlRepository(db)
    stats = ctrl_repo.get_statistics()

    total = stats.get("total", 0)
    passing = stats.get("pass", 0)
    partial = stats.get("partial", 0)

    if total > 0:
        score = ((passing + partial * 0.5) / total) * 100
    else:
        score = 0

    return {
        "score": round(score, 1),
        "total_controls": total,
        "passing_controls": passing,
        "partial_controls": partial,
    }


# ============================================================================
# Executive Dashboard (Phase 3 - Sprint 1)
# ============================================================================

@router.get("/dashboard/executive", response_model=ExecutiveDashboardResponse)
async def get_executive_dashboard(db: Session = Depends(get_db)):
    """
    Get executive dashboard for managers and decision makers.

    Provides:
    - Traffic light status (green/yellow/red)
    - Overall compliance score with trend
    - Top 5 open risks
    - Upcoming deadlines (control reviews, evidence expiry)
    - Team workload distribution
    """
    reg_repo = RegulationRepository(db)
    req_repo = RequirementRepository(db)
    ctrl_repo = ControlRepository(db)
    risk_repo = RiskRepository(db)

    # Calculate compliance score
    ctrl_stats = ctrl_repo.get_statistics()
    total = ctrl_stats.get("total", 0)
    passing = ctrl_stats.get("pass", 0)
    partial = ctrl_stats.get("partial", 0)

    if total > 0:
        score = ((passing + partial * 0.5) / total) * 100
    else:
        score = 0

    # Determine traffic light status
    if score >= 80:
        traffic_light = "green"
    elif score >= 60:
        traffic_light = "yellow"
    else:
        traffic_light = "red"

    # Generate trend data (last 12 months - simulated for now)
    trend_data = []
    now = datetime.utcnow()
    for i in range(11, -1, -1):
        month_date = now - timedelta(days=i * 30)
        trend_score = max(0, min(100, score - (11 - i) * 2 + (5 if i > 6 else 0)))
        trend_data.append(TrendDataPoint(
            date=month_date.strftime("%Y-%m-%d"),
            score=round(trend_score, 1),
            label=month_abbr[month_date.month][:3],
        ))

    # Get top 5 risks (sorted by severity)
    risks = risk_repo.get_all()
    risk_priority = {"critical": 4, "high": 3, "medium": 2, "low": 1}
    sorted_risks = sorted(
        [r for r in risks if r.status != "mitigated"],
        key=lambda r: (
            risk_priority.get(r.inherent_risk.value if r.inherent_risk else "low", 1),
            r.impact * r.likelihood
        ),
        reverse=True
    )[:5]

    top_risks = [
        RiskSummary(
            id=r.id,
            risk_id=r.risk_id,
            title=r.title,
            risk_level=r.inherent_risk.value if r.inherent_risk else "medium",
            owner=r.owner,
            status=r.status,
            category=r.category,
            impact=r.impact,
            likelihood=r.likelihood,
        )
        for r in sorted_risks
    ]

    # Get upcoming deadlines
    controls = ctrl_repo.get_all()
    upcoming_deadlines = []
    today = datetime.utcnow().date()

    for ctrl in controls:
        if ctrl.next_review_at:
            review_date = ctrl.next_review_at.date() if hasattr(ctrl.next_review_at, 'date') else ctrl.next_review_at
            days_remaining = (review_date - today).days

            if days_remaining <= 30:
                if days_remaining < 0:
                    status = "overdue"
                elif days_remaining <= 7:
                    status = "at_risk"
                else:
                    status = "on_track"

                upcoming_deadlines.append(DeadlineItem(
                    id=ctrl.id,
                    title=f"Review: {ctrl.control_id} - {ctrl.title[:30]}",
                    deadline=review_date.isoformat(),
                    days_remaining=days_remaining,
                    type="control_review",
                    status=status,
                    owner=ctrl.owner,
                ))

    upcoming_deadlines.sort(key=lambda x: x.days_remaining)
    upcoming_deadlines = upcoming_deadlines[:10]

    # Calculate team workload (by owner)
    owner_workload = {}
    for ctrl in controls:
        owner = ctrl.owner or "Unassigned"
        if owner not in owner_workload:
            owner_workload[owner] = {"pending": 0, "in_progress": 0, "completed": 0}

        status = ctrl.status.value if ctrl.status else "planned"
        if status in ["pass"]:
            owner_workload[owner]["completed"] += 1
        elif status in ["partial"]:
            owner_workload[owner]["in_progress"] += 1
        else:
            owner_workload[owner]["pending"] += 1

    team_workload = []
    for name, stats in owner_workload.items():
        total_tasks = stats["pending"] + stats["in_progress"] + stats["completed"]
        completion_rate = (stats["completed"] / total_tasks * 100) if total_tasks > 0 else 0
        team_workload.append(TeamWorkloadItem(
            name=name,
            pending_tasks=stats["pending"],
            in_progress_tasks=stats["in_progress"],
            completed_tasks=stats["completed"],
            total_tasks=total_tasks,
            completion_rate=round(completion_rate, 1),
        ))

    team_workload.sort(key=lambda x: x.total_tasks, reverse=True)

    # Get counts
    regulations = reg_repo.get_active()
    requirements = req_repo.get_all()
    open_risks = len([r for r in risks if r.status != "mitigated"])

    return ExecutiveDashboardResponse(
        traffic_light_status=traffic_light,
        overall_score=round(score, 1),
        score_trend=trend_data,
        previous_score=trend_data[-2].score if len(trend_data) >= 2 else None,
        score_change=round(score - trend_data[-2].score, 1) if len(trend_data) >= 2 else None,
        total_regulations=len(regulations),
        total_requirements=len(requirements),
        total_controls=total,
        open_risks=open_risks,
        top_risks=top_risks,
        upcoming_deadlines=upcoming_deadlines,
        team_workload=team_workload,
        last_updated=datetime.utcnow().isoformat(),
    )


@router.get("/dashboard/trend")
async def get_compliance_trend(
    months: int = Query(12, ge=1, le=24, description="Number of months to include"),
    db: Session = Depends(get_db),
):
    """
    Get compliance score trend over time.

    Returns monthly compliance scores for trend visualization.
    """
    ctrl_repo = ControlRepository(db)
    stats = ctrl_repo.get_statistics()
    total = stats.get("total", 0)
    passing = stats.get("pass", 0)
    partial = stats.get("partial", 0)

    current_score = ((passing + partial * 0.5) / total) * 100 if total > 0 else 0

    # Generate simulated historical data
    trend_data = []
    now = datetime.utcnow()

    for i in range(months - 1, -1, -1):
        month_date = now - timedelta(days=i * 30)
        variation = ((i * 7) % 5) - 2
        trend_score = max(0, min(100, current_score - (months - 1 - i) * 1.5 + variation))

        trend_data.append({
            "date": month_date.strftime("%Y-%m-%d"),
            "score": round(trend_score, 1),
            "label": f"{month_abbr[month_date.month]} {month_date.year % 100}",
            "month": month_date.month,
            "year": month_date.year,
        })

    return {
        "current_score": round(current_score, 1),
        "trend": trend_data,
        "period_months": months,
        "generated_at": datetime.utcnow().isoformat(),
    }


# ============================================================================
# Reports
# ============================================================================

@router.get("/reports/summary")
async def get_summary_report(db: Session = Depends(get_db)):
    """Get a quick summary report for the dashboard."""
    from ..services.report_generator import ComplianceReportGenerator

    generator = ComplianceReportGenerator(db)
    return generator.generate_summary_report()


@router.get("/reports/{period}")
async def generate_period_report(
    period: str = "monthly",
    as_of_date: Optional[str] = None,
    db: Session = Depends(get_db),
):
    """
    Generate a compliance report for the specified period.

    Args:
        period: One of 'weekly', 'monthly', 'quarterly', 'yearly'
        as_of_date: Report date (YYYY-MM-DD format, defaults to today)

    Returns:
        Complete compliance report
    """
    from ..services.report_generator import ComplianceReportGenerator, ReportPeriod

    # Validate period
    try:
        report_period = ReportPeriod(period)
    except ValueError:
        raise HTTPException(
            status_code=400,
            detail=f"Invalid period '{period}'. Must be one of: weekly, monthly, quarterly, yearly"
        )

    # Parse date
    report_date = None
    if as_of_date:
        try:
            report_date = datetime.strptime(as_of_date, "%Y-%m-%d").date()
        except ValueError:
            raise HTTPException(
                status_code=400,
                detail="Invalid date format. Use YYYY-MM-DD"
            )

    generator = ComplianceReportGenerator(db)
    return generator.generate_report(report_period, report_date)
