import { NextRequest, NextResponse } from "next/server"; import { auth } from "@clerk/nextjs/server"; import { getDatabase } from "@/lib/database"; import { randomBytes } from "crypto"; import log from "@/lib/logger"; import { fitnessGoalSchema, paginationSchema, statusFilterSchema, } from "@/lib/validation/schemas"; import { validateRequestBody, validateQueryParams, validationErrorResponse, } from "@/lib/validation/helpers"; import { successResponse, createdResponse, unauthorizedResponse, internalErrorResponse, addCorsHeaders, } from "@/lib/api/responses"; // Helper to get user ID from auth (works with both web sessions and mobile tokens) async function getAuthenticatedUserId( req: NextRequest, ): Promise { // The auth() function from Clerk should handle Bearer tokens automatically // when called within an API route that's processed by clerkMiddleware const { userId } = await auth(); return userId; } // OPTIONS - Handle preflight requests export async function OPTIONS() { return NextResponse.json({}, { headers: addCorsHeaders() }); } // GET - List user's fitness goals export async function GET(req: NextRequest) { try { const userId = await getAuthenticatedUserId(req); if (!userId) { log.error("Fitness goals GET - authentication failed", undefined, { headers: Object.fromEntries(req.headers.entries()), }); return unauthorizedResponse(undefined, addCorsHeaders()); } log.debug("Fitness goals GET - authenticated user", { userId }); const { searchParams } = new URL(req.url); const targetUserId = searchParams.get("userId") || userId; const status = searchParams.get("status"); // active, completed, all const db = await getDatabase(); // Fetch goals with optional status filter const goals = await db.getFitnessGoalsByUserId( targetUserId, status && status !== "all" ? status : undefined, ); log.debug("Fitness goals retrieved", { count: goals.length, userId: targetUserId, }); return successResponse(goals, { headers: addCorsHeaders() }); } catch (error) { log.error("Failed to get fitness goals", error); return internalErrorResponse(undefined, addCorsHeaders()); } } // POST - Create new fitness goal export async function POST(req: NextRequest) { try { const userId = await getAuthenticatedUserId(req); if (!userId) { log.error("Fitness goals POST - authentication failed"); return unauthorizedResponse(undefined, addCorsHeaders()); } // Validate request body const validation = await validateRequestBody(req, fitnessGoalSchema); if (!validation.success) { log.warn("Fitness goal creation validation failed", { errors: validation.errors, }); return validationErrorResponse(validation.errors); } const { goalType, title, description, targetValue, currentValue, unit, targetDate, priority, status, notes, } = validation.data; const db = await getDatabase(); // Create the goal const goal = await db.createFitnessGoal({ id: randomBytes(16).toString("hex"), userId, fitnessProfileId: undefined, goalType, title, description, targetValue, currentValue: currentValue || 0, unit, startDate: new Date(), targetDate: targetDate ? new Date(targetDate) : undefined, status: status || "active", progress: 0, priority: priority || "medium", notes, }); log.info("Fitness goal created", { goalId: goal.id, userId }); return createdResponse(goal, { headers: addCorsHeaders() }); } catch (error) { log.error("Failed to create fitness goal", error); return internalErrorResponse(undefined, addCorsHeaders()); } }