import { apiGet, apiPost, apiPut, apiDelete } from './client';

export interface NoteStats {
  readonly totalNotes: number;
  readonly totalFolders: number;
  readonly lastSyncAt?: string;
}

export interface Note {
  readonly noteIdentifier: string;
  readonly folder: string | null;
  readonly name: string;
  readonly body: string;
  readonly modificationDate: string | null;
}

export interface NoteInput {
  readonly folder?: string;
  readonly name: string;
  readonly body: string;
}

export type NoteUpdate = Partial<NoteInput>;

export interface MutationResult {
  readonly sendQueueId: string;
}

interface Envelope<T> {
  readonly success: boolean;
  readonly data: T;
}

function qs(params: Record<string, string | number | boolean | undefined>): string {
  const sp = new URLSearchParams();
  for (const [k, v] of Object.entries(params)) {
    if (v !== undefined && v !== '') sp.set(k, String(v));
  }
  const s = sp.toString();
  return s ? `?${s}` : '';
}

function rethrow(label: string, err: unknown): never {
  if (err instanceof Error) throw err;
  throw new Error(`${label} failed`);
}

export async function fetchNoteStats(): Promise<NoteStats> {
  try {
    const res = await apiGet<Envelope<NoteStats>>('/my/notes/stats');
    return res.data;
  } catch (err) {
    rethrow('fetchNoteStats', err);
  }
}

export interface NoteFilter {
  readonly folder?: string;
  readonly limit?: number;
}

export async function fetchNotes(filter: NoteFilter = {}): Promise<Note[]> {
  try {
    const res = await apiGet<Envelope<{ notes: Note[] }>>(`/my/notes${qs({ ...filter })}`);
    return res.data.notes;
  } catch (err) {
    rethrow('fetchNotes', err);
  }
}

export async function createNote(input: NoteInput, deviceId: string): Promise<MutationResult> {
  try {
    const res = await apiPost<Envelope<MutationResult>>(`/my/notes${qs({ deviceId })}`, input);
    return res.data;
  } catch (err) {
    rethrow('createNote', err);
  }
}

export async function updateNote(
  noteIdentifier: string,
  patch: NoteUpdate,
  deviceId: string,
): Promise<MutationResult> {
  try {
    const res = await apiPut<Envelope<MutationResult>>(
      `/my/notes/${encodeURIComponent(noteIdentifier)}${qs({ deviceId })}`,
      patch,
    );
    return res.data;
  } catch (err) {
    rethrow('updateNote', err);
  }
}

export async function deleteNote(
  noteIdentifier: string,
  deviceId: string,
): Promise<MutationResult> {
  try {
    const res = await apiDelete<Envelope<MutationResult>>(
      `/my/notes/${encodeURIComponent(noteIdentifier)}${qs({ deviceId })}`,
    );
    return res.data;
  } catch (err) {
    rethrow('deleteNote', err);
  }
}
