from datetime import datetime, timezone

from sqlalchemy import func, select
from sqlalchemy.orm import Session

from app.db.models import Exercise, TrainingPlan, TrainingRecord
from app.schemas.models import TrainingPlanCreateRequest, TrainingRecordCreateRequest
from app.services.videos import verify_child_owner

DEFAULT_EXERCISES = [
    {"id": 1, "name": "肩胛稳定训练", "durationMinutes": 5},
    {"id": 2, "name": "颈后肌群拉伸", "sets": 3},
]


def plan_to_dict(plan: TrainingPlan) -> dict:
    detail = plan.plan_detail or {}
    records_count = detail.get("completedDays", 0)
    current_day = min(plan.cycle_days, records_count + 1)
    return {
        "id": plan.id,
        "status": plan.status,
        "detail": {
            **detail,
            "goal": plan.goal,
            "cycleDays": plan.cycle_days,
            "currentDay": current_day,
            "childId": plan.child_id,
            "reportId": plan.report_id,
        },
        "startedAt": plan.started_at.isoformat() if plan.started_at else None,
        "endedAt": plan.ended_at.isoformat() if plan.ended_at else None,
    }


def build_plan_detail(body: TrainingPlanCreateRequest) -> dict:
    exercises = DEFAULT_EXERCISES
    if body.exercise_ids:
        exercises = [{"id": eid, "name": f"动作 #{eid}"} for eid in body.exercise_ids]
    return {
        "goal": body.goal,
        "cycleDays": body.cycle_days,
        "currentDay": 1,
        "completedDays": 0,
        "exercises": exercises,
        "constraints": body.constraints or {},
    }


def get_plan_for_user(db: Session, user_id: int, plan_id: int) -> TrainingPlan | None:
    plan = db.get(TrainingPlan, plan_id)
    if not plan or plan.status == "cancelled":
        return None
    if not verify_child_owner(db, user_id, plan.child_id):
        return None
    return plan


def get_active_plan_for_child(db: Session, user_id: int, child_id: int) -> TrainingPlan | None:
    if not verify_child_owner(db, user_id, child_id):
        return None
    return db.scalar(
        select(TrainingPlan)
        .where(TrainingPlan.child_id == child_id, TrainingPlan.status == "active")
        .order_by(TrainingPlan.id.desc())
    )


def list_plans_for_child(db: Session, user_id: int, child_id: int) -> list[TrainingPlan] | None:
    if not verify_child_owner(db, user_id, child_id):
        return None
    return list(
        db.scalars(
            select(TrainingPlan)
            .where(TrainingPlan.child_id == child_id, TrainingPlan.status != "cancelled")
            .order_by(TrainingPlan.id.desc())
            .limit(10)
        ).all()
    )


def create_plan(db: Session, user_id: int, body: TrainingPlanCreateRequest) -> TrainingPlan | None:
    if not verify_child_owner(db, user_id, body.child_id):
        return None
    now = datetime.now(timezone.utc)
    plan = TrainingPlan(
        child_id=body.child_id,
        report_id=body.report_id,
        goal=body.goal,
        cycle_days=body.cycle_days,
        status="active",
        plan_detail=build_plan_detail(body),
        started_at=now,
    )
    db.add(plan)
    db.commit()
    db.refresh(plan)
    return plan


def create_record(
    db: Session, user_id: int, plan_id: int, body: TrainingRecordCreateRequest
) -> TrainingRecord | None:
    plan = get_plan_for_user(db, user_id, plan_id)
    if not plan:
        return None

    feedback = {"media": body.media} if body.media else None
    record = TrainingRecord(
        plan_id=plan_id,
        child_id=plan.child_id,
        exercise_id=body.exercise_id,
        completed=body.completed,
        score=body.score,
        duration_seconds=body.duration_seconds,
        feedback=feedback,
        note=body.note,
    )
    db.add(record)

    detail = dict(plan.plan_detail or {})
    detail["completedDays"] = detail.get("completedDays", 0) + (1 if body.completed else 0)
    detail["lastScore"] = body.score
    detail["lastRecordId"] = None
    plan.plan_detail = detail

    db.commit()
    db.refresh(record)
    detail["lastRecordId"] = record.id
    plan.plan_detail = detail
    db.commit()
    return record


def ensure_default_exercises(db: Session) -> None:
    existing = db.scalar(select(func.count()).select_from(Exercise))
    if existing:
        return
    for item in DEFAULT_EXERCISES:
        db.add(
            Exercise(
                name=item["name"],
                category="posture",
                target_issue="头前伸/高低肩",
                duration_seconds=(item.get("durationMinutes", 3) * 60),
            )
        )
    db.commit()
