import { randomUUIDv7 } from 'bun';

import { getDb, pgGet } from '@/shared/db';
import { touchDevice } from '@/entities/device';
import { upsertCalendar, countCalendars, listCalendarsByDevice } from '@/entities/calendar';
import { upsertEvent, listEvents, countEvents } from '@/entities/event';
import type { CalendarRecord } from '@/entities/calendar';
import type { EventRecord, EventFilter } from '@/entities/event';

export interface CalendarPayload {
  calendarIdentifier: string;
  title: string;
  calendarType: string;
  color: string;
  source: string;
}

export interface SyncCalendarsPayload {
  calendars: CalendarPayload[];
}

export interface EventPayload {
  eventIdentifier: string;
  calendarIdentifier: string;
  title: string;
  notes?: string | null;
  location?: string | null;
  url?: string | null;
  isAllDay: boolean;
  startDate: string;
  endDate: string;
  createdAt?: string | null;
  modifiedAt?: string | null;
  status: string;
  availability: string;
  isDetached: boolean;
  hasAlarms: boolean;
  hasRecurrenceRules: boolean;
  recurrenceRule?: string | null;
  organizerEmail?: string | null;
  organizerName?: string | null;
  attendeeCount: number;
}

export interface SyncEventsPayload {
  events: EventPayload[];
}

export interface ICalStats {
  totalCalendars: number;
  totalEvents: number;
}

export async function ingestCalendars(
  deviceId: string,
  payload: SyncCalendarsPayload,
): Promise<{ synced: number }> {
  try {
    const db = getDb();
    await touchDevice(db, deviceId);

    let synced = 0;
    for (const c of payload.calendars) {
      await upsertCalendar(db, {
        id: randomUUIDv7(),
        deviceId,
        externalId: c.calendarIdentifier,
        title: c.title,
        calendarType: c.calendarType,
        color: c.color,
        source: c.source,
      });
      synced++;
    }
    return { synced };
  } catch (err) {
    throw new Error(
      `ingestCalendars failed for device ${deviceId}: ${err instanceof Error ? err.message : String(err)}`,
      { cause: err },
    );
  }
}

export async function ingestEvents(
  deviceId: string,
  payload: SyncEventsPayload,
): Promise<{ synced: number }> {
  try {
    const db = getDb();
    await touchDevice(db, deviceId);

    const calendarRows = await listCalendarsByDevice(db, deviceId);
    const calendarMap = new Map(calendarRows.map((c) => [c.externalId, c.id]));

    let synced = 0;
    for (const e of payload.events) {
      const existing = await pgGet<{ id: string }>(
        db,
        'SELECT id FROM macsync.events WHERE device_id = $1 AND external_id = $2',
        [deviceId, e.eventIdentifier],
      );

      await upsertEvent(db, {
        id: existing?.id ?? randomUUIDv7(),
        deviceId,
        calendarId: calendarMap.get(e.calendarIdentifier) ?? null,
        externalId: e.eventIdentifier,
        title: e.title,
        notes: e.notes ?? null,
        location: e.location ?? null,
        url: e.url ?? null,
        isAllDay: e.isAllDay,
        startDate: e.startDate,
        endDate: e.endDate,
        status: e.status,
        availability: e.availability,
        isDetached: e.isDetached,
        hasRecurrence: e.hasRecurrenceRules,
        recurrenceRule: e.recurrenceRule ?? null,
        organizerEmail: e.organizerEmail ?? null,
        organizerName: e.organizerName ?? null,
        attendeeCount: e.attendeeCount,
        createdAt: e.createdAt ?? null,
        modifiedAt: e.modifiedAt ?? null,
      });
      synced++;
    }
    return { synced };
  } catch (err) {
    throw new Error(
      `ingestEvents failed for device ${deviceId}: ${err instanceof Error ? err.message : String(err)}`,
      { cause: err },
    );
  }
}

export async function getICalStats(): Promise<ICalStats> {
  try {
    const db = getDb();
    return {
      totalCalendars: await countCalendars(db),
      totalEvents: await countEvents(db),
    };
  } catch (err) {
    throw new Error(
      `getICalStats failed: ${err instanceof Error ? err.message : String(err)}`,
      { cause: err },
    );
  }
}

export async function listEventsByFilter(filter: EventFilter): Promise<readonly EventRecord[]> {
  try {
    return await listEvents(getDb(), filter);
  } catch (err) {
    throw new Error(
      `listEventsByFilter failed: ${err instanceof Error ? err.message : String(err)}`,
      { cause: err },
    );
  }
}

export async function listCalendarsForDevice(deviceId: string): Promise<readonly CalendarRecord[]> {
  try {
    return await listCalendarsByDevice(getDb(), deviceId);
  } catch (err) {
    throw new Error(
      `listCalendarsForDevice failed for device ${deviceId}: ${err instanceof Error ? err.message : String(err)}`,
      { cause: err },
    );
  }
}
