from datetime import date, timedelta

from fastapi import APIRouter, Depends
from sqlalchemy import select, func
from sqlalchemy.ext.asyncio import AsyncSession

from backend.app.core.auth import get_current_rider
from backend.app.core.database import get_session
from backend.app.models.activity import Activity, ActivityMetrics
from backend.app.models.fitness import PowerCurve
from backend.app.models.rider import Rider
from backend.app.schemas.rider import RiderUpdate, RiderResponse, FitnessHistoryResponse
from backend.app.services.fitness import get_fitness_history

router = APIRouter()


@router.get("/profile", response_model=RiderResponse)
async def get_rider(rider: Rider = Depends(get_current_rider)):
    return rider


@router.put("/profile", response_model=RiderResponse)
async def update_rider(
    data: RiderUpdate,
    rider: Rider = Depends(get_current_rider),
    session: AsyncSession = Depends(get_session),
):
    update_data = data.model_dump(exclude_unset=True)
    ftp_changed = "ftp" in update_data and update_data["ftp"] != rider.ftp

    for key, value in update_data.items():
        setattr(rider, key, value)

    # Recalculate TSS/IF for all activities when FTP changes
    if ftp_changed and rider.ftp:
        query = (
            select(ActivityMetrics)
            .join(Activity, Activity.id == ActivityMetrics.activity_id)
            .where(Activity.rider_id == rider.id)
            .where(ActivityMetrics.normalized_power.isnot(None))
        )
        result = await session.execute(query)
        for metrics in result.scalars().all():
            np_val = metrics.normalized_power
            duration_q = await session.execute(
                select(Activity.duration).where(Activity.id == metrics.activity_id)
            )
            duration = duration_q.scalar()
            if np_val and duration:
                metrics.intensity_factor = round(np_val / rider.ftp, 2)
                metrics.tss = round(
                    (duration * np_val * (np_val / rider.ftp))
                    / (rider.ftp * 3600)
                    * 100,
                    1,
                )

    await session.commit()
    await session.refresh(rider)
    return rider


@router.get("/fitness", response_model=list[FitnessHistoryResponse])
async def get_fitness(
    days: int = 90,
    rider: Rider = Depends(get_current_rider),
    session: AsyncSession = Depends(get_session),
):
    entries = await get_fitness_history(rider.id, session, days=days)
    return entries


@router.get("/weekly-stats")
async def get_weekly_stats(
    weeks: int = 8,
    rider: Rider = Depends(get_current_rider),
    session: AsyncSession = Depends(get_session),
):
    today = date.today()
    # Start from Monday of current week
    start_of_week = today - timedelta(days=today.weekday())
    start_date = start_of_week - timedelta(weeks=weeks - 1)

    week_col = func.date_trunc('week', Activity.date).label("week")

    query = (
        select(
            week_col,
            func.count(Activity.id).label("rides"),
            func.sum(Activity.duration).label("duration"),
            func.sum(Activity.distance).label("distance"),
            func.sum(ActivityMetrics.tss).label("tss"),
        )
        .select_from(Activity)
        .outerjoin(ActivityMetrics, ActivityMetrics.activity_id == Activity.id)
        .where(Activity.rider_id == rider.id)
        .where(Activity.date >= start_date)
        .group_by(week_col)
        .order_by(week_col)
    )

    result = await session.execute(query)

    return [
        {
            "week": row.week.strftime("%Y-%m-%d") if row.week else None,
            "rides": row.rides,
            "duration": row.duration or 0,
            "distance": round(float(row.distance or 0) / 1000, 1),
            "tss": round(float(row.tss or 0), 0),
        }
        for row in result
    ]


@router.get("/personal-records")
async def get_personal_records(
    rider: Rider = Depends(get_current_rider),
    session: AsyncSession = Depends(get_session),
):
    """Best power at each standard duration across all activities."""
    query = (
        select(PowerCurve.curve_data, Activity.date, Activity.name, Activity.id)
        .join(Activity, Activity.id == PowerCurve.activity_id)
        .where(Activity.rider_id == rider.id)
    )
    result = await session.execute(query)

    # Merge all curves: keep best power + source activity for each duration
    records: dict[int, dict] = {}
    for row in result:
        curve_data = row.curve_data
        for dur_str, power in curve_data.items():
            dur = int(dur_str)
            if dur not in records or power > records[dur]["power"]:
                records[dur] = {
                    "duration": dur,
                    "power": power,
                    "activity_id": str(row.id),
                    "activity_name": row.name or "Ride",
                    "date": row.date.isoformat(),
                }

    # Sort by duration
    return sorted(records.values(), key=lambda r: r["duration"])
