from flask import Flask, jsonify, request, g
from flask_cors import CORS
import json
import os
import uuid
import psycopg2
import psycopg2.extras
import cloudinary
import cloudinary.uploader
from datetime import datetime, timedelta, timezone
from functools import wraps
from urllib import error as urllib_error
from urllib import parse as urllib_parse
from urllib import request as urllib_request
from werkzeug.security import generate_password_hash, check_password_hash
import jwt
from pathlib import Path

app = Flask(__name__)

DATABASE_URL = os.environ.get("DATABASE_URL", "")
JWT_SECRET = os.environ.get("JWT_SECRET", "replace-with-a-very-secret-key-change-in-production")
JWT_ALGORITHM = "HS256"
GOOGLE_MAPS_API_KEY = os.environ.get("GOOGLE_MAPS_API_KEY") or os.environ.get("VITE_GOOGLE_MAPS_KEY", "")
DB_INITIALIZED = False

cloudinary.config(
    cloud_name=os.environ.get("CLOUDINARY_CLOUD_NAME"),
    api_key=os.environ.get("CLOUDINARY_API_KEY"),
    api_secret=os.environ.get("CLOUDINARY_API_SECRET"),
    secure=True
)

_allowed_origins = [
    "http://localhost:5173",
    "http://localhost:5174",
    "http://localhost:5175",
    "http://127.0.0.1:5173",
    "http://127.0.0.1:5174",
]
_frontend_url = (os.environ.get("FRONTEND_URL") or "").rstrip("/")
if _frontend_url:
    _allowed_origins.append(_frontend_url)

CORS(
    app,
    origins=[*_allowed_origins, r"https://.*\.vercel\.app"],
    supports_credentials=True,
)

def get_db():
    ensure_db_initialized()
    db = getattr(g, "_database", None)
    if db is None:
        db = g._database = psycopg2.connect(DATABASE_URL)
    return db

@app.teardown_appcontext
def close_connection(exception):
    db = getattr(g, "_database", None)
    if db is not None:
        db.close()

def run_query(sql, params=(), one=False):
    """Execute a SELECT and return results as dictionaries."""
    db = get_db()
    with db.cursor(cursor_factory=psycopg2.extras.RealDictCursor) as cur:
        cur.execute(sql, params)
        return cur.fetchone() if one else cur.fetchall()

def run_write(sql, params=()):
    """Execute an INSERT/UPDATE/DELETE and commit."""
    db = get_db()
    with db.cursor() as cur:
        cur.execute(sql, params)
    db.commit()

def ensure_db_initialized():
    global DB_INITIALIZED
    if DB_INITIALIZED or not DATABASE_URL:
        return
    init_db()
    DB_INITIALIZED = True

def fetch_remote_json(url, timeout=10):
    req = urllib_request.Request(url, headers={"User-Agent": "TrainRec/1.0"})
    with urllib_request.urlopen(req, timeout=timeout) as resp:
        return json.load(resp), resp.status

def init_db():
    conn = psycopg2.connect(DATABASE_URL)
    c = conn.cursor()
    c.execute("""
        CREATE TABLE IF NOT EXISTS users (
            id SERIAL PRIMARY KEY, email TEXT UNIQUE, name TEXT, nickname TEXT,
            password_hash TEXT, sex TEXT, birthdate TEXT, height_in REAL,
            weight_lb REAL, fitness_activity TEXT, profile_pic TEXT, created_at TEXT,
            confidence_level INTEGER DEFAULT 72
        )
    """)
    c.execute("ALTER TABLE users ADD COLUMN IF NOT EXISTS confidence_level INTEGER DEFAULT 72")
    c.execute("""
        CREATE TABLE IF NOT EXISTS goals (
            id SERIAL PRIMARY KEY, user_id INTEGER, goal_text TEXT, created_at TEXT
        )
    """)
    c.execute("""
        CREATE TABLE IF NOT EXISTS completed_workouts (
            id SERIAL PRIMARY KEY, user_id INTEGER, exercise_name TEXT,
            calories_burned REAL, completed_at TEXT
        )
    """)
    conn.commit()
    conn.close()

def auth_required(fn):
    @wraps(fn)
    def wrapper(*args, **kwargs):
        auth = request.headers.get("Authorization", "")
        if not auth.startswith("Bearer "): return jsonify({"error": "Unauthorized"}), 401
        try:
            token = auth.split(" ")[1]
            data = jwt.decode(token, JWT_SECRET, algorithms=[JWT_ALGORITHM])
            request.user_id = data.get("user_id")
        except: return jsonify({"error": "Invalid token"}), 401
        return fn(*args, **kwargs)
    return wrapper
#Guarantees the data directory exists for storing pose session data. 
#Each session will be saved as a JSON file with a unique name based on the timestamp and a random UUID to avoid collisions.
#This is where Abdiel's section will read from to display past workout sessions and their associated pose data.
BASE_DIR = Path(__file__).resolve().parent
POSE_DATA_DIR = BASE_DIR / 'data' / 'pose_sessions'
POSE_DATA_DIR.mkdir(parents=True, exist_ok=True)

# ---------------------------------------------------------
# EXERCISE LIBRARY DATA
# This is the "Source of Truth" for Abdiel's section.
# ---------------------------------------------------------
EXERCISES = [
    # --- UPPER BODY ---
    {"id": "pushups", "name": "Push-ups", "category": "Upper Body", "difficulty": "Beginner", "type": "reps", "target": 15, "icon": "fitness_center", "description": "Standard chest press movement.", "steps": ["Hands wide", "Lower chest", "Push up"]},
    {"id": "diamond_pushups", "name": "Diamond Push-ups", "category": "Upper Body", "difficulty": "Advanced", "type": "reps", "target": 10, "icon": "handyman", "description": "Tricep-focused push-ups.", "steps": ["Hands in diamond shape", "Keep elbows in"]},
    {"id": "pike_pushups", "name": "Pike Push-ups", "category": "Upper Body", "difficulty": "Intermediate", "type": "reps", "target": 10, "icon": "architecture", "description": "Shoulder-focused push-up.", "steps": ["Hips high in V-shape", "Lower head to floor"]},
    {"id": "tricep_dips", "name": "Tricep Dips", "category": "Upper Body", "difficulty": "Beginner", "type": "reps", "target": 12, "icon": "chair", "description": "Using a chair or bench for triceps.", "steps": ["Hands on edge", "Lower hips", "Push up"]},
    {"id": "bicep_curls", "name": "Bicep Curls", "category": "Upper Body", "difficulty": "Beginner", "type": "reps", "target": 12, "icon": "fitness_center", "description": "Classic elbow flexion for bicep isolation.", "steps": ["Stand tall, arms at sides", "Curl both arms to shoulder height", "Squeeze at the top", "Lower with control"]},
    {"id": "supermans", "name": "Supermans", "category": "Upper Body", "difficulty": "Beginner", "type": "reps", "target": 15, "icon": "flight", "description": "Strengthens the lower back and shoulders.", "steps": ["Lie face down", "Lift arms and legs", "Hold and lower"]},
    {"id": "inchworms", "name": "Inchworms", "category": "Upper Body", "difficulty": "Intermediate", "type": "reps", "target": 8, "icon": "bug_report", "description": "Full body stretch and shoulder stability.", "steps": ["Walk hands out to plank", "Walk hands back to feet"]},

    # --- LOWER BODY ---
    {"id": "squats", "name": "Bodyweight Squats", "category": "Lower Body", "difficulty": "Beginner", "type": "reps", "target": 20, "icon": "accessibility_new", "description": "Essential leg movement.", "steps": ["Feet shoulder-width", "Sit back", "Chest up"]},
    {"id": "jump_squats", "name": "Jump Squats", "category": "Lower Body", "difficulty": "Advanced", "type": "reps", "target": 12, "icon": "bolt", "description": "Explosive leg power.", "steps": ["Squat down", "Jump explosively", "Land softly"]},
    {"id": "lunges", "name": "Walking Lunges", "category": "Lower Body", "difficulty": "Intermediate", "type": "reps", "target": 20, "icon": "directions_walk", "description": "Unilateral leg training.", "steps": ["Step forward", "Drop back knee", "Switch legs"]},
    {"id": "glute_bridge", "name": "Glute Bridges", "category": "Lower Body", "difficulty": "Beginner", "type": "reps", "target": 15, "icon": "airline_seat_flat", "description": "Isolating the glutes.", "steps": ["Lie on back", "Lift hips", "Squeeze"]},
    {"id": "calf_raises", "name": "Calf Raises", "category": "Lower Body", "difficulty": "Beginner", "type": "reps", "target": 25, "icon": "height", "description": "Lower leg definition.", "steps": ["Stand on toes", "Lower slowly"]},
    {"id": "side_lunges", "name": "Side Lunges", "category": "Lower Body", "difficulty": "Intermediate", "type": "reps", "target": 12, "description": "Lateral leg movement.", "steps": ["Step wide to side", "Keep one leg straight"]},

    # --- CORE ---
    {"id": "plank", "name": "Forearm Plank", "category": "Core", "difficulty": "Beginner", "type": "seconds", "target": 60, "icon": "timer", "description": "Static core stability.", "steps": ["Hold forearm position", "Keep back flat"]},
    {"id": "mountain_climbers", "name": "Mountain Climbers", "category": "Core", "difficulty": "Intermediate", "type": "seconds", "target": 40, "icon": "terrain", "description": "Rapid knee-to-chest movement.", "steps": ["High plank", "Run knees in"]},
    {"id": "russian_twists", "name": "Russian Twists", "category": "Core", "difficulty": "Intermediate", "type": "reps", "target": 30, "icon": "sync", "description": "Oblique rotational strength.", "steps": ["Sit with knees bent", "Twist torso side to side"]},
    {"id": "leg_raises", "name": "Leg Raises", "category": "Core", "difficulty": "Intermediate", "type": "reps", "target": 15, "icon": "vertical_align_top", "description": "Lower ab isolation.", "steps": ["Lie on back", "Lift legs to 90 degrees", "Lower slowly"]},
    {"id": "bicycle_crunches", "name": "Bicycle Crunches", "category": "Core", "difficulty": "Advanced", "type": "reps", "target": 20, "icon": "pedal_bike", "description": "Dynamic core rotation.", "steps": ["Opposite elbow to knee", "Keep legs moving"]},
    {"id": "plank_jacks", "name": "Plank Jacks", "category": "Core", "difficulty": "Intermediate", "type": "seconds", "target": 30, "icon": "unfold_more", "description": "Cardio-core hybrid.", "steps": ["Plank position", "Jump feet wide and in"]},

    # --- CARDIO ---
    {"id": "burpees", "name": "Standard Burpees", "category": "Cardio", "difficulty": "Advanced", "type": "reps", "target": 10, "icon": "rocket_launch", "description": "Full body explosive movement.", "steps": ["Squat", "Plank", "Jump"]},
    {"id": "jumping_jacks", "name": "Jumping Jacks", "category": "Cardio", "difficulty": "Beginner", "type": "reps", "target": 50, "icon": "celebration", "description": "Classic cardio warm-up.", "steps": ["Jump wide", "Hands up"]},
    {"id": "high_knees", "name": "High Knees", "category": "Cardio", "difficulty": "Intermediate", "type": "seconds", "target": 30, "icon": "directions_run", "description": "Running in place with lift.", "steps": ["Drive knees high", "Pump arms"]}
]

# ---------------------------------------------------------
# API ROUTES
# ---------------------------------------------------------

@app.route("/api/nearby-gyms", methods=["GET"])
def nearby_gyms():
    if not GOOGLE_MAPS_API_KEY:
        return jsonify({"error": "Gym lookup is not configured on the server."}), 500

    lat_raw = request.args.get("lat")
    lon_raw = request.args.get("lon")
    radius_raw = request.args.get("radius", "8000")

    try:
        lat = float(lat_raw)
        lon = float(lon_raw)
        radius = max(1, min(int(radius_raw), 50000))
    except (TypeError, ValueError):
        return jsonify({"error": "Valid lat, lon, and radius values are required."}), 400

    google_url = (
        "https://maps.googleapis.com/maps/api/place/nearbysearch/json?"
        + urllib_parse.urlencode(
            {
                "location": f"{lat},{lon}",
                "radius": radius,
                "type": "gym",
                "key": GOOGLE_MAPS_API_KEY,
            }
        )
    )

    try:
        data, _status_code = fetch_remote_json(google_url, timeout=15)
    except urllib_error.HTTPError as exc:
        details = exc.read().decode("utf-8", errors="replace")[:300]
        return jsonify({"error": "Google Places request failed.", "details": details}), 502
    except urllib_error.URLError:
        return jsonify({"error": "Unable to reach Google Places."}), 502

    google_status = data.get("status")
    if google_status not in {"OK", "ZERO_RESULTS"}:
        return jsonify({
            "error": data.get("error_message") or "Google Places request was rejected.",
            "googleStatus": google_status,
        }), 502

    results = []
    for place in data.get("results", []):
        geometry = place.get("geometry", {}).get("location", {})
        if "lat" not in geometry or "lng" not in geometry:
            continue
        results.append(
            {
                "id": place.get("place_id"),
                "name": place.get("name"),
                "lat": geometry.get("lat"),
                "lon": geometry.get("lng"),
                "address": place.get("vicinity"),
                "city": None,
                "phone": None,
                "website": None,
                "photoRef": (place.get("photos") or [{}])[0].get("photo_reference"),
            }
        )

    return jsonify({"results": results}), 200

@app.route("/register", methods=["POST"])
def register():
    payload = request.get_json()
    email = payload.get("email", "").lower().strip()
    if not email:
        return jsonify({"error": "Email is required"}), 400
    pw_hash = generate_password_hash(payload["password"])
    try:
        run_write("""
            INSERT INTO users (email, name, nickname, password_hash, sex, birthdate, height_in, weight_lb, fitness_activity, created_at)
            VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
        """, (
            email, payload.get("name"), payload.get("nickname"), pw_hash,
            payload.get("sex"), payload.get("birthdate"), payload.get("height_in"),
            payload.get("weight_lb"), payload.get("fitness_activity"),
            datetime.now(timezone.utc).isoformat()
        ))
        user = run_query("SELECT id FROM users WHERE email = %s", (email,), one=True)
        token = jwt.encode({
            'user_id': user['id'],
            'exp': datetime.now(timezone.utc) + timedelta(hours=24)
        }, JWT_SECRET, algorithm=JWT_ALGORITHM)
        return jsonify({"message": "Account Created", "token": token}), 201
    except psycopg2.errors.UniqueViolation:
        get_db().rollback()
        return jsonify({"error": "User already exists"}), 400
    except Exception as e:
        print(f"ERROR: {e}")
        return jsonify({"error": str(e)}), 500
    
@app.route("/login", methods=["POST"])
def login():
    payload = request.get_json() or {}
    email = payload.get("email", "").lower()
    password = payload.get("password", "")
    user = run_query("SELECT id, password_hash FROM users WHERE email = %s", (email,), one=True)
    if user and check_password_hash(user["password_hash"], password):
        token = jwt.encode(
            {
                "user_id": user["id"],
                "exp": datetime.now(timezone.utc) + timedelta(hours=24),
                "iat": datetime.now(timezone.utc)
            },
            JWT_SECRET,
            algorithm=JWT_ALGORITHM
        )
        return jsonify({"message": "Logged in successfully", "token": token}), 200
    return jsonify({"error": "Invalid email or password"}), 401

@app.route("/reset_password", methods=["POST"])
def reset_password():
    data = request.get_json()
    email = data.get("email")
    new_pw = data.get("new_password")
    if not email or not new_pw:
        return jsonify({"error": "Email and new password are required"}), 400
    user = run_query("SELECT id FROM users WHERE email = %s", (email,), one=True)
    if not user:
        return jsonify({"error": "No account found with that email"}), 404
    run_write("UPDATE users SET password_hash = %s WHERE email = %s",
              (generate_password_hash(new_pw), email))
    return jsonify({"message": "Password updated successfully"}), 200

@app.route("/me/update_profile", methods=["POST"])
@auth_required
def update_profile():
    payload = request.get_json()
    for key in ["weight_lb", "height_in", "nickname", "fitness_activity"]:
        if key in payload:
            run_write(f"UPDATE users SET {key} = %s WHERE id = %s", (payload[key], request.user_id))
    return jsonify({"message": "Profile updated"})

@app.route("/me/add_goal", methods=["POST"])
@auth_required
def add_goal():
    data = request.get_json()
    content = data.get("text")
    if not content:
        return jsonify({"error": "Content is empty"}), 400
    run_write("INSERT INTO goals (user_id, goal_text, created_at) VALUES (%s, %s, %s)",
              (request.user_id, content, datetime.now().isoformat()))
    return jsonify({"message": "Added"}), 201

@app.route("/me/delete_goal/<int:goal_id>", methods=["DELETE"])
@auth_required
def delete_goal(goal_id):
    run_write("DELETE FROM goals WHERE id = %s AND user_id = %s", (goal_id, request.user_id))
    return jsonify({"message": "Deleted"}), 200

@app.route("/me/full_profile", methods=["GET"])
@auth_required
def get_full_profile():
    user = run_query(
        "SELECT name, email, nickname, sex, birthdate, height_in, weight_lb, fitness_activity, profile_pic, confidence_level FROM users WHERE id = %s",
        (request.user_id,), one=True
    )
    goals_rows = run_query(
        "SELECT id, goal_text FROM goals WHERE user_id = %s ORDER BY created_at DESC",
        (request.user_id,)
    )
    total_cal = run_query(
        "SELECT SUM(calories_burned) as total FROM completed_workouts WHERE user_id = %s",
        (request.user_id,), one=True
    )
    history = run_query(
        "SELECT exercise_name, completed_at FROM completed_workouts WHERE user_id = %s ORDER BY completed_at DESC LIMIT 5",
        (request.user_id,)
    )
    if user:
        res = dict(user)
        res["confidence_level"] = max(0, min(int(res.get("confidence_level") or 72), 100))
        res["goals"] = [{"id": row["id"], "text": row["goal_text"]} for row in goals_rows]
        res["total_calories"] = total_cal["total"] or 0
        res["history"] = [dict(row) for row in history]
        return jsonify(res)
    return jsonify({"error": "User not found"}), 404

@app.route("/me/confidence", methods=["POST"])
@auth_required
def save_confidence_level():
    payload = request.get_json() or {}
    raw_level = payload.get("confidence_level")

    try:
        confidence_level = int(raw_level)
    except (TypeError, ValueError):
        return jsonify({"error": "Confidence level must be a number"}), 400

    confidence_level = max(0, min(confidence_level, 100))
    run_write(
        "UPDATE users SET confidence_level = %s WHERE id = %s",
        (confidence_level, request.user_id)
    )
    return jsonify({"message": "Confidence saved", "confidence_level": confidence_level}), 200

@app.route("/api/workouts/complete", methods=["POST"])
@auth_required
def complete_workout():
    payload = request.get_json()
    run_write("""
        INSERT INTO completed_workouts (user_id, exercise_name, calories_burned, completed_at)
        VALUES (%s, %s, %s, %s)""",
        (request.user_id, payload["exercise_name"], payload["calories_burned"],
         datetime.now(timezone.utc).isoformat()))
    return jsonify({"message": "Workout saved!"})

@app.route('/profile', methods=['GET'])
@app.route('/me', methods=['GET'])
@auth_required
def get_profile():
    user_row = run_query("SELECT * FROM users WHERE id = %s", (request.user_id,), one=True)
    if user_row:
        user_data = dict(user_row)
        user_data.pop('password_hash', None)
        return jsonify(user_data), 200
    return jsonify({"error": "User not found in database"}), 404
    
@app.route("/me/upload_icon", methods=["POST"])
@auth_required
def upload_icon():
    if 'file' not in request.files:
        return jsonify({"error": "No file part"}), 400
    file = request.files['file']
    if file.filename == '':
        return jsonify({"error": "No selected file"}), 400
    result = cloudinary.uploader.upload(
        file,
        folder="trainrec/avatars",
        public_id=f"user_{request.user_id}",
        overwrite=True,
        resource_type="image"
    )
    url = result.get("secure_url")
    run_write("UPDATE users SET profile_pic = %s WHERE id = %s", (url, request.user_id))
    return jsonify({"message": "Icon updated", "profile_pic": url}), 200

@app.route("/me/remove_icon", methods=["DELETE"])
@auth_required
def remove_icon():
    try:
        cloudinary.uploader.destroy(f"trainrec/avatars/user_{request.user_id}")
    except Exception:
        pass
    run_write("UPDATE users SET profile_pic = NULL WHERE id = %s", (request.user_id,))
    return jsonify({"message": "Profile picture removed"}), 200

@app.route("/dashboard", methods=["GET"])
def dashboard():
    db = get_db()
    user = db.execute("SELECT * FROM users WHERE id = ?", (request.user_id,)).fetchone()
    
    # Auto-age for dashboard
    birth = datetime.fromisoformat(user["birthdate"])
    age = datetime.utcnow().year - birth.year
    
    return jsonify({
        "display_name": user["nickname"] or user["name"],
        "age": age,
        "stats": {
            "weight": f"{user['weight_lb']} lbs",
            "height": f"{user['height_in']} inches",
            "activity": user["fitness_activity"]
        }
    })
#--------------------------------------------------------------------------------
# Temporary storage for active sessions
active_sessions = {}

def utc_now_iso() -> str:
    return datetime.now(timezone.utc).isoformat()


def session_dir(session_id: str) -> Path:
    path = POSE_DATA_DIR / session_id
    path.mkdir(parents=True, exist_ok=True)
    return path

@app.route('/api/session/start', methods=['POST'])
def start_session():
    data = request.json or {}
    exercise_id = data.get('exerciseId')
    
    # Generate a unique ID for this specific workout
    session_id = str(uuid.uuid4())
    
    active_sessions[session_id] = {
        'exercise_id': exercise_id,
        'start_time': utc_now_iso(), #actual start time of the session in ISO format
        'status': 'active'
    }
    
    return jsonify({'sessionId': session_id, 'status': 'success'})

@app.route('/api/pose/session/start', methods=['POST'])
def start_pose_session():
    data = request.json or {}
    session_id = str(uuid.uuid4())
    record = {
        'sessionId': session_id,
        'exerciseId': data.get('exerciseId'),
        'exerciseName': data.get('exerciseName'),
        'cameraLabel': data.get('cameraLabel'),
        'deviceId': data.get('deviceId'),
        'facingMode': data.get('facingMode'),
        'startedAt': utc_now_iso(),
        'status': 'active',
        'framesReceived': 0,
    }

    active_sessions[session_id] = record
    directory = session_dir(session_id)
    (directory / 'metadata.json').write_text(json.dumps(record, indent=2))
    (directory / 'landmarks.json').touch(exist_ok=True)  # Create an empty file for landmarks

    return jsonify({'sessionId': session_id, 'status': 'started'})

@app.route('/api/pose/session/<session_id>/landmarks', methods=['POST'])
def append_landmarks(session_id):
    session = active_sessions.get(session_id)
    if not session:
        return jsonify({'error': 'Session not found'}), 404
    
    data = request.json or {}
    frames = data.get('frames', [])
    directory = session_dir(session_id)
    jsonl_path = directory / 'landmarks.jsonl'

    with jsonl_path.open('a', encoding='utf-8') as output:
        for frame in frames:
            output.write(json.dumps(frame) + '\n')
    
    session['framesReceived'] = session.get('framesReceived', 0) + len(frames)
    metadata_path = directory / 'metadata.json'
    metadata_path.write_text(json.dumps(session, indent=2))

    return jsonify({'status': 'saved', 'framesSaved': len(frames), 'totalFrames': session['framesReceived']})

@app.route('/api/pose/session/<session_id>/stop', methods=['POST'])
def stop_pose_session(session_id):
    session = active_sessions.get(session_id)
    if not session:
        return jsonify({'error': 'Session not found'}), 404
    
    data = request.json or {}
    session['status'] = 'completed'
    session['endedAt'] = utc_now_iso()
    session['savedFramesClient'] = data.get('savedFrames', 0)
    session['repCount'] = data.get('repCount', 0)

    directory = session_dir(session_id)
    (directory / 'metadata.json').write_text(json.dumps(session, indent=2))
    return jsonify({'status': 'completed', 'sessionId': session_id})

@app.route('/api/pose/sessions', methods=['GET'])
def get_pose_sessions():
    sessions = []
    for entry in sorted(POSE_DATA_DIR.iterdir(), reverse=True):
        metadata = entry / 'metadata.json'
        if metadata.exists():
            sessions.append(json.loads(metadata.read_text(encoding='utf-8')))
    return jsonify(sessions)

@app.route('/api/exercises', methods=['GET'])
def get_exercises():
    #Returns the full list of exercises for the library UI.
    return jsonify(EXERCISES)

@app.route('/api/exercises/filter', methods=['GET'])
def filter_exercises():
    #Allows filtering by category or difficulty via URL parameters.
    category = request.args.get('category')
    difficulty = request.args.get('difficulty')
    
    results = EXERCISES
    if category:
        results = [e for e in results if e['category'] == category]
    if difficulty:
        results = [e for e in results if e['difficulty'] == difficulty]
        
    return jsonify(results)


@app.route("/api/health", methods=["GET"])
def health_check():
    #Simple route to verify the backend is running.
    return jsonify({'status': 'online', 'version': '3.0.0'})

if __name__ == '__main__':
    init_db()
    app.run(
        debug=os.environ.get("FLASK_DEBUG", "false").lower() == "true",
        port=int(os.environ.get("PORT", 5000))
    )