import { isAxiosError } from "axios"; import { apiClient, withAuth } from "../api/client"; import { API_ENDPOINTS } from "../config/api"; import log from "../utils/logger"; export interface FitnessGoal { id: string; userId: string; fitnessProfileId?: string; goalType: | "weight_target" | "strength_milestone" | "endurance_target" | "flexibility_goal" | "habit_building" | "custom"; title: string; description?: string; targetValue?: number; currentValue?: number; unit?: string; startDate: string; targetDate?: string; completedDate?: string; status: "active" | "completed" | "abandoned" | "paused"; progress: number; priority: "low" | "medium" | "high"; notes?: string; createdAt: string; updatedAt: string; } export interface CreateGoalData { goalType: FitnessGoal["goalType"]; title: string; description?: string; targetValue?: number; currentValue?: number; unit?: string; targetDate?: string; priority?: FitnessGoal["priority"]; notes?: string; } export class FitnessGoalsService { async getGoals( userId: string, token: string | null, status?: string, ): Promise { try { const response = await apiClient.get(API_ENDPOINTS.FITNESS_GOALS.LIST, { params: { userId, ...(status && status !== "all" ? { status } : {}), }, ...withAuth(token), }); const result = response.data; // Handle standardized API response format // API returns: { success: true, data: [...], meta: {...} } if (result.success && result.data) { return Array.isArray(result.data) ? result.data : []; } // Fallback for legacy format (direct array) return Array.isArray(result) ? result : []; } catch (error) { if (isAxiosError(error) && error.response) { throw new Error(`Failed to fetch goals: ${error.response.status}`); } log.error("Failed to fetch fitness goals", error); throw error; } } async createGoal( goalData: CreateGoalData, token: string | null, ): Promise { try { const response = await apiClient.post( API_ENDPOINTS.FITNESS_GOALS.CREATE, goalData, withAuth(token), ); const result = response.data; // Handle standardized API response format if (result.success && result.data) { return result.data; } // Fallback for legacy format return result; } catch (error) { if (isAxiosError(error)) { const message = (error.response?.data as { error?: string } | undefined)?.error || (error.response ? `Failed to create goal: ${error.response.status}` : "Failed to create goal"); throw new Error(message); } log.error("Failed to create fitness goal", error); throw error; } } async updateGoal( id: string, updates: Partial, token: string | null, ): Promise { try { const response = await apiClient.put( API_ENDPOINTS.FITNESS_GOALS.UPDATE(id), updates, withAuth(token), ); const result = response.data; // Handle standardized API response format if (result.success && result.data) { return result.data; } // Fallback for legacy format return result; } catch (error) { if (isAxiosError(error) && error.response) { throw new Error(`Failed to update goal: ${error.response.status}`); } log.error("Failed to update fitness goal", error); throw error; } } async updateProgress( id: string, currentValue: number, token: string | null, ): Promise { return this.updateGoal(id, { currentValue }, token); } async completeGoal(id: string, token: string | null): Promise { try { const response = await apiClient.post( API_ENDPOINTS.FITNESS_GOALS.COMPLETE(id), {}, withAuth(token), ); const result = response.data; // Note: Complete endpoint returns direct object (legacy format) // Handle standardized API response format (if migrated) if (result.success && result.data) { return result.data; } // Fallback for legacy format (current implementation) return result; } catch (error) { if (isAxiosError(error) && error.response) { throw new Error(`Failed to complete goal: ${error.response.status}`); } log.error("Failed to complete fitness goal", error); throw error; } } async deleteGoal(id: string, token: string | null): Promise { try { await apiClient.delete( API_ENDPOINTS.FITNESS_GOALS.DELETE(id), withAuth(token), ); // DELETE endpoint returns: { success: true, data: { deleted: true }, meta: {...} } // No need to parse the result for void return type } catch (error) { if (isAxiosError(error) && error.response) { throw new Error(`Failed to delete goal: ${error.response.status}`); } log.error("Failed to delete fitness goal", error); throw error; } } } export const fitnessGoalsService = new FitnessGoalsService();