"""BAN YARO — Übungs- & Trainingsfortschritt""" from fastapi import APIRouter, Depends from pydantic import BaseModel from typing import Optional from database import db from auth import get_current_user router = APIRouter() # ------------------------------------------------------------------ # Übungs-Status # ------------------------------------------------------------------ class ProgressUpdate(BaseModel): exercise_id: str status: Optional[str] = None # null/noch-nicht/manchmal/meistens/sitzt @router.get("/progress") async def get_progress(user=Depends(get_current_user)): uid = user["id"] with db() as conn: rows = conn.execute( "SELECT exercise_id, status, updated_at FROM exercise_progress WHERE user_id=?", (uid,) ).fetchall() return [dict(r) for r in rows] @router.post("/progress") async def upsert_progress(body: ProgressUpdate, user=Depends(get_current_user)): uid = user["id"] with db() as conn: conn.execute(""" INSERT INTO exercise_progress (user_id, exercise_id, status) VALUES (?,?,?) ON CONFLICT(user_id, exercise_id) DO UPDATE SET status=excluded.status, updated_at=datetime('now') """, (uid, body.exercise_id, body.status)) return {"ok": True} # ------------------------------------------------------------------ # Trainingsplan-Checkboxen # ------------------------------------------------------------------ class PlanProgress(BaseModel): item_key: str checked: bool @router.get("/plan-progress") async def get_plan_progress(user=Depends(get_current_user)): uid = user["id"] with db() as conn: rows = conn.execute( "SELECT item_key, checked FROM training_plan_progress WHERE user_id=?", (uid,) ).fetchall() return [dict(r) for r in rows] @router.post("/plan-progress") async def upsert_plan_progress(body: PlanProgress, user=Depends(get_current_user)): uid = user["id"] with db() as conn: if body.checked: conn.execute(""" INSERT OR REPLACE INTO training_plan_progress (user_id, item_key, checked) VALUES (?,?,1) """, (uid, body.item_key)) else: conn.execute( "DELETE FROM training_plan_progress WHERE user_id=? AND item_key=?", (uid, body.item_key) ) return {"ok": True} # ------------------------------------------------------------------ # Empfehlungen (rule-based) # ------------------------------------------------------------------ GRUNDKOMMANDOS_ORDER = ['Sitz', 'Platz', 'Bleib', 'Hier / Komm', 'Fuß', 'Aus / Lass es', 'Warte'] TRICKS_FIRST = ['Pfote / Schütteln', 'Dreh', 'Auf die Decke', 'Nasenarbeit / Suchen'] @router.get("/suggestions") async def get_suggestions(user=Depends(get_current_user)): uid = user["id"] with db() as conn: rows = conn.execute( "SELECT exercise_id, status FROM exercise_progress WHERE user_id=?", (uid,) ).fetchall() progress = {r["exercise_id"]: r["status"] for r in rows} def key(name): return f"grundkommandos_{name.replace(' ', '_').replace('/', '')}" def tkey(name): return f"tricks_{name.replace(' ', '_').replace('/', '')}" suggestions = [] # Noch-nicht Übungen — direkte Hilfe stuck = [n for n in GRUNDKOMMANDOS_ORDER if progress.get(key(n)) == 'noch-nicht'] if stuck: suggestions.append({ "type": "help", "icon": "warning", "title": f'\u201e{stuck[0]}\u201c klappt noch nicht', "text": "Mach einen Schritt zurück: Kürzere Einheiten, mehr Leckerlis, weniger Ablenkung. Schau dir die Trainingsgrundlagen an.", "action_tab": "grundkommandos", "action_name": stuck[0], }) # Manchmal-Übungen — intensivieren almost = [n for n in GRUNDKOMMANDOS_ORDER if progress.get(key(n)) == 'manchmal'] if almost: suggestions.append({ "type": "boost", "icon": "fire", "title": f'Fast da: \u201e{almost[0]}\u201c', "text": "Du bist auf dem richtigen Weg! Übe täglich 3–5 Minuten — dann sitzt es bald.", "action_tab": "grundkommandos", "action_name": almost[0], }) # Nächste ungestartete Grundkommando grundk_mastered = [n for n in GRUNDKOMMANDOS_ORDER if progress.get(key(n)) == 'sitzt'] next_up = next((n for n in GRUNDKOMMANDOS_ORDER if progress.get(key(n)) in (None, 'noch-nicht') and n not in stuck), None) if len(grundk_mastered) == len(GRUNDKOMMANDOS_ORDER): # Alle Grundkommandos gemeistert → Tricks empfehlen next_trick = next((n for n in TRICKS_FIRST if progress.get(tkey(n)) is None), None) if next_trick: suggestions.append({ "type": "next", "icon": "star", "title": "Alle Grundkommandos sitzen! 🎉", "text": f'Zeit für Tricks! Starte mit \u201e{next_trick}\u201c \u2014 Spaß garantiert.', "action_tab": "tricks", "action_name": next_trick, }) elif next_up and not almost: suggestions.append({ "type": "next", "icon": "arrow-right", "title": f"Bereit für den nächsten Schritt?", "text": f'Starte jetzt mit \u201e{next_up}\u201c. {"Du hast bereits " + str(len(grundk_mastered)) + " Grundkommandos gemeistert!" if grundk_mastered else "Es ist die perfekte Basis für alles Weitere."}', "action_tab": "grundkommandos", "action_name": next_up, }) elif not progress: # Noch gar kein Fortschritt suggestions.append({ "type": "start", "icon": "flag", "title": "Womit fangen wir an?", "text": "\u201eSitz\u201c ist das erste Kommando für jeden Hund \u2014 einfach, schnell erlernt und die Basis für alles.", "action_tab": "grundkommandos", "action_name": "Sitz", }) return suggestions[:2] # max 2 Empfehlungen