const API_URL = '';

function getToken(): string | null {
  if (typeof window === 'undefined') return null;
  return localStorage.getItem('token');
}

function setToken(token: string): void {
  localStorage.setItem('token', token);
}

function clearToken(): void {
  localStorage.removeItem('token');
}

async function request<T>(
  endpoint: string,
  options: RequestInit = {}
): Promise<T> {
  const token = getToken();
  const headers: HeadersInit = {
    'Content-Type': 'application/json',
    'X-Timezone-Offset': String(new Date().getTimezoneOffset()),
    ...(token ? { Authorization: `Bearer ${token}` } : {}),
    ...options.headers,
  };

  const response = await fetch(`${API_URL}${endpoint}`, {
    ...options,
    headers,
  });

  if (!response.ok) {
    const body = await response.text();
    let errorMsg = 'Request failed';
    try {
      const error = JSON.parse(body);
      errorMsg = error.error || error.message || body;
    } catch {
      errorMsg = body || errorMsg;
    }
    throw new Error(errorMsg);
  }

  return response.json();
}

export const api = {
  // Auth
  auth: {
    login: async (username: string, password: string) => {
      const result = await request<{ token: string }>('/api/login', {
        method: 'POST',
        body: JSON.stringify({ username, password }),
      });
      setToken(result.token);
      return result;
    },

    register: async (username: string, password: string) => {
      return request<{ success: boolean }>('/api/register', {
        method: 'POST',
        body: JSON.stringify({ username, password }),
      });
    },

    logout: () => {
      clearToken();
    },

    getToken,
  },

  // User
  user: {
    get: async (userId: string) => {
      return request<{ id: string; username: string; created_at: string }>(
        `/api/user/${userId}`,
        { method: 'GET' }
      );
    },

    getUUID: async (username: string) => {
      return request<{ id: string }>(`/api/getUserUUID/${username}`, {
        method: 'GET',
      });
    },

    update: async (userId: string, data: Record<string, unknown>) => {
      return request<{ success: boolean }>(`/api/user/${userId}`, {
        method: 'PUT',
        body: JSON.stringify(data),
      });
    },
  },

  // Routines
  routines: {
    list: async () => {
      return request<Array<{
        id: string;
        user_uuid: string;
        name: string;
        description?: string;
        icon?: string;
        created_at: string;
      }>>('/api/routines', { method: 'GET' });
    },

    get: async (routineId: string) => {
      return request<{
        routine: {
          id: string;
          user_uuid: string;
          name: string;
          description?: string;
          icon?: string;
        };
        steps: Array<{
          id: string;
          routine_id: string;
          name: string;
          instructions?: string;
          step_type: string;
          duration_minutes?: number;
          media_url?: string;
          position: number;
        }>;
      }>(`/api/routines/${routineId}`, { method: 'GET' });
    },

    create: async (data: { name: string; description?: string; icon?: string }) => {
      return request<{ id: string }>('/api/routines', {
        method: 'POST',
        body: JSON.stringify(data),
      });
    },

    update: async (routineId: string, data: Record<string, unknown>) => {
      return request<{ id: string }>(`/api/routines/${routineId}`, {
        method: 'PUT',
        body: JSON.stringify(data),
      });
    },

    delete: async (routineId: string) => {
      return request<{ deleted: boolean }>(`/api/routines/${routineId}`, {
        method: 'DELETE',
      });
    },

    // Steps
    getSteps: async (routineId: string) => {
      return request<Array<{
        id: string;
        routine_id: string;
        name: string;
        instructions?: string;
        step_type: string;
        duration_minutes?: number;
        media_url?: string;
        position: number;
      }>>(`/api/routines/${routineId}/steps`, { method: 'GET' });
    },

    addStep: async (
      routineId: string,
      data: { name: string; duration_minutes?: number; position?: number }
    ) => {
      return request<{ id: string }>(`/api/routines/${routineId}/steps`, {
        method: 'POST',
        body: JSON.stringify(data),
      });
    },

    updateStep: async (
      routineId: string,
      stepId: string,
      data: Record<string, unknown>
    ) => {
      return request<{ id: string }>(`/api/routines/${routineId}/steps/${stepId}`, {
        method: 'PUT',
        body: JSON.stringify(data),
      });
    },

    deleteStep: async (routineId: string, stepId: string) => {
      return request<{ deleted: boolean }>(
        `/api/routines/${routineId}/steps/${stepId}`,
        { method: 'DELETE' }
      );
    },

    reorderSteps: async (routineId: string, stepIds: string[]) => {
      return request<Array<{ id: string }>>(
        `/api/routines/${routineId}/steps/reorder`,
        {
          method: 'PUT',
          body: JSON.stringify({ step_ids: stepIds }),
        }
      );
    },

    // Step extended
    updateStepInstructions: async (
      routineId: string,
      stepId: string,
      instructions: string
    ) => {
      return request<{ id: string }>(
        `/api/routines/${routineId}/steps/${stepId}/instructions`,
        {
          method: 'PUT',
          body: JSON.stringify({ instructions }),
        }
      );
    },

    updateStepType: async (
      routineId: string,
      stepId: string,
      stepType: string
    ) => {
      return request<{ id: string }>(
        `/api/routines/${routineId}/steps/${stepId}/type`,
        {
          method: 'PUT',
          body: JSON.stringify({ step_type: stepType }),
        }
      );
    },

    updateStepMedia: async (
      routineId: string,
      stepId: string,
      mediaUrl: string
    ) => {
      return request<{ id: string }>(
        `/api/routines/${routineId}/steps/${stepId}/media`,
        {
          method: 'PUT',
          body: JSON.stringify({ media_url: mediaUrl }),
        }
      );
    },

    // Scheduling
    getSchedule: async (routineId: string) => {
      return request<{
        id: string;
        routine_id: string;
        days: string[];
        time: string;
        remind: boolean;
      }>(`/api/routines/${routineId}/schedule`, { method: 'GET' });
    },

    setSchedule: async (
      routineId: string,
      data: { days: string[]; time: string; remind?: boolean }
    ) => {
      return request<{ id: string }>(`/api/routines/${routineId}/schedule`, {
        method: 'PUT',
        body: JSON.stringify(data),
      });
    },

    deleteSchedule: async (routineId: string) => {
      return request<{ deleted: boolean }>(
        `/api/routines/${routineId}/schedule`,
        { method: 'DELETE' }
      );
    },

    listAllSchedules: async () => {
      return request<Array<{
        routine_id: string;
        routine_name: string;
        routine_icon: string;
        days: string[];
        time: string;
        remind: boolean;
        total_duration_minutes: number;
      }>>('/api/routines/schedules', { method: 'GET' });
    },

    // History
    getHistory: async (routineId: string, days = 7) => {
      return request<Array<{
        id: string;
        routine_id: string;
        status: string;
        created_at: string;
        completed_at?: string;
      }>>(`/api/routines/${routineId}/history?days=${days}`, {
        method: 'GET',
      });
    },

    // Stats
    getStats: async (routineId: string, days = 30) => {
      return request<{
        routine_id: string;
        routine_name: string;
        period_days: number;
        total_sessions: number;
        completed: number;
        aborted: number;
        completion_rate_percent: number;
        avg_duration_minutes: number;
        total_time_minutes: number;
      }>(`/api/routines/${routineId}/stats?days=${days}`, { method: 'GET' });
    },

    getStreak: async (routineId: string) => {
      return request<{
        routine_id: string;
        routine_name: string;
        current_streak: number;
        longest_streak: number;
        last_completed_date?: string;
      }>(`/api/routines/${routineId}/streak`, { method: 'GET' });
    },

    // Tags
    getTags: async (routineId: string) => {
      return request<Array<{ id: string; name: string; color: string }>>(
        `/api/routines/${routineId}/tags`,
        { method: 'GET' }
      );
    },

    addTags: async (routineId: string, tagIds: string[]) => {
      return request<Array<{ id: string; name: string; color: string }>>(
        `/api/routines/${routineId}/tags`,
        {
          method: 'POST',
          body: JSON.stringify({ tag_ids: tagIds }),
        }
      );
    },

    removeTag: async (routineId: string, tagId: string) => {
      return request<{ removed: boolean }>(
        `/api/routines/${routineId}/tags/${tagId}`,
        { method: 'DELETE' }
      );
    },
  },

  // Sessions
  sessions: {
    start: async (routineId: string) => {
      return request<{
        session: { id: string; status: string };
        current_step: {
          id: string;
          name: string;
          instructions?: string;
          step_type: string;
          duration_minutes?: number;
          position: number;
        };
      }>(`/api/routines/${routineId}/start`, { method: 'POST' });
    },

    getActive: async () => {
      return request<{
        session: {
          id: string;
          routine_id: string;
          status: string;
          current_step_index: number;
        };
        routine: { id: string; name: string; icon?: string };
        current_step: {
          id: string;
          name: string;
          instructions?: string;
          step_type: string;
          duration_minutes?: number;
          position: number;
        } | null;
      }>('/api/sessions/active', { method: 'GET' });
    },

    completeStep: async (sessionId: string, stepId: string) => {
      return request<{
        session: { status: string; current_step_index?: number };
        next_step: {
          id: string;
          name: string;
          instructions?: string;
          step_type: string;
          duration_minutes?: number;
          position: number;
        } | null;
        celebration?: {
          streak_current: number;
          streak_longest: number;
          session_duration_minutes: number;
          total_completions: number;
          steps_completed: number;
          steps_skipped: number;
        };
      }>(`/api/sessions/${sessionId}/complete-step`, {
        method: 'POST',
        body: JSON.stringify({ step_id: stepId }),
      });
    },

    skipStep: async (sessionId: string, stepId: string) => {
      return request<{
        session: { status: string; current_step_index?: number };
        next_step: {
          id: string;
          name: string;
          instructions?: string;
          step_type: string;
          duration_minutes?: number;
          position: number;
        } | null;
        celebration?: {
          streak_current: number;
          streak_longest: number;
          session_duration_minutes: number;
          total_completions: number;
          steps_completed: number;
          steps_skipped: number;
        };
      }>(`/api/sessions/${sessionId}/skip-step`, {
        method: 'POST',
        body: JSON.stringify({ step_id: stepId }),
      });
    },

    pause: async (sessionId: string) => {
      return request<{ status: string }>(`/api/sessions/${sessionId}/pause`, {
        method: 'POST',
      });
    },

    resume: async (sessionId: string) => {
      return request<{ status: string }>(`/api/sessions/${sessionId}/resume`, {
        method: 'POST',
      });
    },

    cancel: async (sessionId: string) => {
      return request<{ status: string }>(`/api/sessions/${sessionId}/cancel`, {
        method: 'POST',
      });
    },

    abort: async (sessionId: string, reason?: string) => {
      return request<{ status: string; reason: string }>(
        `/api/sessions/${sessionId}/abort`,
        {
          method: 'POST',
          body: JSON.stringify({ reason }),
        }
      );
    },

    addNote: async (
      sessionId: string,
      stepIndex: number | undefined,
      note: string
    ) => {
      return request<{ id: string }>(`/api/sessions/${sessionId}/note`, {
        method: 'POST',
        body: JSON.stringify({ step_index: stepIndex, note }),
      });
    },

    setDuration: async (sessionId: string, durationMinutes: number) => {
      return request<{ id: string }>(`/api/sessions/${sessionId}/duration`, {
        method: 'PUT',
        body: JSON.stringify({ actual_duration_minutes: durationMinutes }),
      });
    },

    getDetails: async (sessionId: string) => {
      return request<{
        session: {
          id: string;
          routine_id: string;
          status: string;
          current_step_index: number;
        };
        routine: { id: string; name: string };
        steps: Array<{ id: string; name: string; position: number }>;
        notes: Array<{ id: string; step_index?: number; note: string }>;
      }>(`/api/sessions/${sessionId}`, { method: 'GET' });
    },
  },

  // Templates
  templates: {
    list: async () => {
      return request<Array<{
        id: string;
        name: string;
        description?: string;
        icon?: string;
        step_count: number;
      }>>('/api/templates', { method: 'GET' });
    },

    get: async (templateId: string) => {
      return request<{
        template: {
          id: string;
          name: string;
          description?: string;
          icon?: string;
        };
        steps: Array<{
          id: string;
          name: string;
          instructions?: string;
          step_type: string;
          duration_minutes?: number;
          position: number;
        }>;
      }>(`/api/templates/${templateId}`, { method: 'GET' });
    },

    clone: async (templateId: string) => {
      return request<{ id: string }>(`/api/templates/${templateId}/clone`, {
        method: 'POST',
      });
    },
  },

  // Tags
  tags: {
    list: async () => {
      return request<Array<{ id: string; name: string; color: string }>>(
        '/api/tags',
        { method: 'GET' }
      );
    },

    create: async (data: { name: string; color?: string }) => {
      return request<{ id: string }>('/api/tags', {
        method: 'POST',
        body: JSON.stringify(data),
      });
    },

    delete: async (tagId: string) => {
      return request<{ deleted: boolean }>(`/api/tags/${tagId}`, {
        method: 'DELETE',
      });
    },
  },

  // Stats
  stats: {
    getWeeklySummary: async () => {
      return request<{
        total_completed: number;
        total_time_minutes: number;
        routines_started: number;
        routines: Array<{
          routine_id: string;
          name: string;
          completed_this_week: number;
        }>;
      }>('/api/routines/weekly-summary', { method: 'GET' });
    },

    getStreaks: async () => {
      return request<Array<{
        routine_id: string;
        routine_name: string;
        current_streak: number;
        longest_streak: number;
        last_completed_date?: string;
      }>>('/api/routines/streaks', { method: 'GET' });
    },
  },

  // Victories
  victories: {
    get: async (days = 30) => {
      return request<Array<{
        type: string;
        message: string;
        date?: string;
      }>>(`/api/victories?days=${days}`, { method: 'GET' });
    },
  },

  // Rewards
  rewards: {
    getRandom: async (context = 'completion') => {
      return request<{
        reward: {
          id: string;
          category: string;
          content: string;
          emoji?: string;
          rarity: string;
        } | null;
      }>(`/api/rewards/random?context=${context}`, { method: 'GET' });
    },

    getHistory: async () => {
      return request<Array<{
        earned_at: string;
        context?: string;
        category: string;
        content: string;
        emoji?: string;
        rarity?: string;
      }>>('/api/rewards/history', { method: 'GET' });
    },
  },

  // Preferences
  preferences: {
    get: async () => {
      return request<{
        sound_enabled: boolean;
        haptic_enabled: boolean;
        show_launch_screen: boolean;
        celebration_style: string;
      }>('/api/preferences', { method: 'GET' });
    },

    update: async (data: {
      sound_enabled?: boolean;
      haptic_enabled?: boolean;
      show_launch_screen?: boolean;
      celebration_style?: string;
      timezone_offset?: number;
    }) => {
      return request<Record<string, unknown>>('/api/preferences', {
        method: 'PUT',
        body: JSON.stringify(data),
      });
    },
  },

  // Notifications
  notifications: {
    getVapidPublicKey: async () => {
      return request<{ public_key: string }>('/api/notifications/vapid-public-key', {
        method: 'GET',
      });
    },

    subscribe: async (subscription: PushSubscriptionJSON) => {
      return request<{ subscribed: boolean }>('/api/notifications/subscribe', {
        method: 'POST',
        body: JSON.stringify(subscription),
      });
    },

    unsubscribe: async (endpoint: string) => {
      return request<{ unsubscribed: boolean }>('/api/notifications/subscribe', {
        method: 'DELETE',
        body: JSON.stringify({ endpoint }),
      });
    },

    getSettings: async () => {
      return request<{
        discord_user_id: string;
        discord_enabled: boolean;
        ntfy_topic: string;
        ntfy_enabled: boolean;
        web_push_enabled: boolean;
      }>('/api/notifications/settings', { method: 'GET' });
    },

    updateSettings: async (data: {
      discord_user_id?: string;
      discord_enabled?: boolean;
      ntfy_topic?: string;
      ntfy_enabled?: boolean;
    }) => {
      return request<{ updated: boolean }>('/api/notifications/settings', {
        method: 'PUT',
        body: JSON.stringify(data),
      });
    },
  },

  // Medications
  medications: {
    list: async () => {
      return request<Array<{
        id: string;
        name: string;
        dosage: string;
        unit: string;
        frequency: string;
        times: string[];
        notes?: string;
        active: boolean;
        quantity_remaining?: number;
        refill_date?: string;
      }>>('/api/medications', { method: 'GET' });
    },

    get: async (medId: string) => {
      return request<{
        id: string;
        name: string;
        dosage: string;
        unit: string;
        frequency: string;
        times: string[];
        notes?: string;
        active: boolean;
        quantity_remaining?: number;
        refill_date?: string;
      }>(`/api/medications/${medId}`, { method: 'GET' });
    },

    create: async (data: {
      name: string;
      dosage: string;
      unit: string;
      frequency: string;
      times?: string[];
      days_of_week?: string[];
      interval_days?: number;
      start_date?: string;
      notes?: string;
    }) => {
      return request<{ id: string }>('/api/medications', {
        method: 'POST',
        body: JSON.stringify(data),
      });
    },

    update: async (medId: string, data: Record<string, unknown>) => {
      return request<{ id: string }>(`/api/medications/${medId}`, {
        method: 'PUT',
        body: JSON.stringify(data),
      });
    },

    delete: async (medId: string) => {
      return request<{ deleted: boolean }>(`/api/medications/${medId}`, {
        method: 'DELETE',
      });
    },

    take: async (medId: string, scheduledTime?: string, notes?: string) => {
      return request<{ id: string }>(`/api/medications/${medId}/take`, {
        method: 'POST',
        body: JSON.stringify({ scheduled_time: scheduledTime, notes }),
      });
    },

    skip: async (medId: string, scheduledTime?: string, reason?: string) => {
      return request<{ id: string }>(`/api/medications/${medId}/skip`, {
        method: 'POST',
        body: JSON.stringify({ scheduled_time: scheduledTime, reason }),
      });
    },

    snooze: async (medId: string, minutes = 15) => {
      return request<{ snoozed_until_minutes: number }>(
        `/api/medications/${medId}/snooze`,
        {
          method: 'POST',
          body: JSON.stringify({ minutes }),
        }
      );
    },

    getLog: async (medId: string, days = 30) => {
      return request<Array<{
        id: string;
        medication_id: string;
        action: string;
        scheduled_time?: string;
        notes?: string;
        created_at: string;
      }>>(`/api/medications/${medId}/log?days=${days}`, { method: 'GET' });
    },

    getToday: async () => {
      return request<Array<{
        medication: {
          id: string;
          name: string;
          dosage: string;
          unit: string;
        };
        scheduled_times: string[];
        taken_times: string[];
        skipped_times?: string[];
        is_prn?: boolean;
        is_next_day?: boolean;
        is_previous_day?: boolean;
      }>>('/api/medications/today', { method: 'GET' });
    },

    getAdherence: async (days = 30) => {
      return request<Array<{
        medication_id: string;
        name: string;
        taken: number;
        skipped: number;
        adherence_percent: number;
      }>>(`/api/medications/adherence?days=${days}`, { method: 'GET' });
    },

    getRefillsDue: async (daysAhead = 7) => {
      return request<Array<{
        id: string;
        name: string;
        dosage: string;
        quantity_remaining?: number;
        refill_date?: string;
      }>>(`/api/medications/refills-due?days_ahead=${daysAhead}`, {
        method: 'GET',
      });
    },

    setRefill: async (
      medId: string,
      data: {
        quantity_remaining?: number;
        refill_date?: string;
        pharmacy_notes?: string;
      }
    ) => {
      return request<{ id: string }>(`/api/medications/${medId}/refill`, {
        method: 'PUT',
        body: JSON.stringify(data),
      });
    },
  },
};

export default api;
