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

export interface CalendarStats {
  readonly totalCalendars: number;
  readonly totalEvents: number;
  readonly lastSyncAt?: string;
}

export interface CalendarSummary {
  readonly identifier: string;
  readonly title: string;
  readonly color?: string;
}

export interface CalendarEvent {
  readonly eventIdentifier: string;
  readonly calendarIdentifier: string;
  readonly title: string;
  readonly notes: string | null;
  readonly location: string | null;
  readonly startDate: string;
  readonly endDate: string;
  readonly isAllDay: boolean;
  readonly url: string | null;
}

export interface EventInput {
  readonly calendarIdentifier: string;
  readonly title: string;
  readonly notes?: string;
  readonly location?: string;
  readonly startDate: string;
  readonly endDate: string;
  readonly isAllDay?: boolean;
  readonly url?: string;
}

export type EventUpdate = Partial<EventInput>;

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 fetchCalendarStats(): Promise<CalendarStats> {
  try {
    const res = await apiGet<Envelope<CalendarStats>>('/my/calendar/stats');
    return res.data;
  } catch (err) {
    rethrow('fetchCalendarStats', err);
  }
}

export async function fetchCalendars(deviceId?: string): Promise<CalendarSummary[]> {
  try {
    const res = await apiGet<Envelope<{ calendars: CalendarSummary[] }>>(
      `/my/calendar/calendars${qs({ deviceId })}`,
    );
    return res.data.calendars;
  } catch (err) {
    rethrow('fetchCalendars', err);
  }
}

export interface EventFilter {
  readonly deviceId?: string;
  readonly startAfter?: string;
  readonly startBefore?: string;
  readonly calendarId?: string;
  readonly limit?: number;
}

export async function fetchEvents(filter: EventFilter = {}): Promise<CalendarEvent[]> {
  try {
    const res = await apiGet<Envelope<{ events: CalendarEvent[] }>>(
      `/my/calendar/events${qs({ ...filter })}`,
    );
    return res.data.events;
  } catch (err) {
    rethrow('fetchEvents', err);
  }
}

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

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

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