import type { Project, Session, Chat, Message, PendingChange, AskUserAnswer } from './types';

export class ApiError extends Error {
  constructor(
    public status: number,
    public body: unknown,
  ) {
    super(
      typeof body === 'object' && body && 'error' in body
        ? String((body as { error: unknown }).error)
        : `HTTP ${status}`,
    );
  }
}

async function request<T>(path: string, init: RequestInit = {}): Promise<T> {
  const res = await fetch(path, {
    ...init,
    headers: {
      'Content-Type': 'application/json',
      ...(init.headers ?? {}),
    },
  });
  if (res.status === 204) return undefined as T;
  const text = await res.text();
  const data = text ? JSON.parse(text) : undefined;
  if (!res.ok) throw new ApiError(res.status, data);
  return data as T;
}

export const api = {
  health: () => request<{ ok: boolean; db: boolean; tools: number }>('/api/health'),

  projects: {
    list: (params?: { status?: 'open' | 'archived' }) =>
      request<Project[]>(`/api/projects${params?.status ? `?status=${params.status}` : ''}`),
  },

  sessions: {
    listForProject: (projectId: string, status?: 'open' | 'archived') =>
      request<Session[]>(
        `/api/projects/${projectId}/sessions${status ? `?status=${status}` : ''}`,
      ),
    get: (id: string) => request<Session>(`/api/sessions/${id}`),
  },

  chats: {
    listForSession: (sessionId: string) =>
      request<Chat[]>(`/api/sessions/${sessionId}/chats`),
    create: (sessionId: string, body?: { name?: string }) =>
      request<Chat>(`/api/sessions/${sessionId}/chats`, {
        method: 'POST',
        body: JSON.stringify(body ?? {}),
      }),
    answerUserInput: (chatId: string, toolCallId: string, answers: AskUserAnswer[]) =>
      request<{ tool_message_id: string; assistant_message_id: string }>(
        `/api/chats/${chatId}/answer_user_input`,
        {
          method: 'POST',
          body: JSON.stringify({ tool_call_id: toolCallId, answers }),
        },
      ),
  },

  messages: {
    send: (sessionId: string, chatId: string, content: string) =>
      request<{ user_message_id: string; assistant_message_id: string }>(
        `/api/sessions/${sessionId}/messages`,
        {
          method: 'POST',
          body: JSON.stringify({ content, chat_id: chatId }),
        },
      ),
    stop: (sessionId: string) =>
      request<{ cancelled: boolean }>(`/api/sessions/${sessionId}/stop`, {
        method: 'POST',
      }),
  },

  pending: {
    list: (sessionId: string) =>
      request<PendingChange[]>(`/api/sessions/${sessionId}/pending`),
    applyAll: (sessionId: string) =>
      request<{ results: Array<{ id: string; success: boolean; error?: string }> }>(
        `/api/sessions/${sessionId}/pending/apply`,
        { method: 'POST' },
      ),
    applyOne: (changeId: string) =>
      request<{ success: boolean; error?: string }>(`/api/pending/${changeId}/apply`, {
        method: 'POST',
      }),
    rejectOne: (changeId: string) =>
      request<{ ok: boolean }>(`/api/pending/${changeId}/reject`, {
        method: 'POST',
      }),
    rewindOne: (changeId: string) =>
      request<{ success: boolean; error?: string }>(`/api/pending/${changeId}/rewind`, {
        method: 'POST',
      }),
  },
};
