/**
 * Serialization helpers — calendar-module.
 *
 * `serializeCalendarEvent` maps a DB row to a CalendarEventObject.
 * `taskToCalendarEvent` maps a tasks row (due_date != null) to a virtual all-day event.
 */
import type { CalendarEventObject, CalendarSource, SyncStatus } from './types'

/**
 * Minimal DB row shape consumed by serialization helpers.
 * Matches the Drizzle `calendarEvents.$inferSelect` shape but declared locally
 * so `@zync/calendar` stays free of any `@zync/db` dependency.
 */
export interface CalendarEventRow {
  id: string
  tenantId: string
  createdBy: string
  title: string
  description: string | null
  startAt: Date
  endAt: Date
  allDay: boolean
  location: string | null
  source: string
  taskId: string | null
  projectId: string | null
  customerId: string | null
  externalId: string | null
  externalCalendarId: string | null
  syncedAt: Date | null
  syncStatus: string
  createdAt: Date
  updatedAt: Date
}

// ── serializeCalendarEvent ────────────────────────────────────────────────────

/**
 * Convert a `calendar_events` DB row to the public CalendarEventObject shape.
 *
 * `readOnly` is true only for events that were authored exclusively in an external
 * provider (source ∈ {google,outlook}) AND have an external_id (i.e. the row did
 * not originate from Zync). Task-sourced events remain editable (readOnly=false).
 */
export function serializeCalendarEvent(row: CalendarEventRow): CalendarEventObject {
  const externalSources: CalendarSource[] = ['google', 'outlook']
  const readOnly = externalSources.includes(row.source as CalendarSource) && row.externalId != null

  return {
    id: row.id,
    tenantId: row.tenantId,
    createdBy: row.createdBy,
    title: row.title,
    description: row.description ?? null,
    startAt: row.startAt.toISOString(),
    endAt: row.endAt.toISOString(),
    allDay: row.allDay,
    location: row.location ?? null,
    source: row.source as CalendarSource,
    taskId: row.taskId ?? null,
    projectId: row.projectId ?? null,
    customerId: row.customerId ?? null,
    externalId: row.externalId ?? null,
    externalCalendarId: row.externalCalendarId ?? null,
    syncedAt: row.syncedAt ? row.syncedAt.toISOString() : null,
    syncStatus: row.syncStatus as SyncStatus,
    readOnly,
    createdAt: row.createdAt.toISOString(),
    updatedAt: row.updatedAt.toISOString(),
  }
}

// ── taskToCalendarEvent ───────────────────────────────────────────────────────

export interface TaskCalendarInput {
  id: string
  tenantId: string
  title: string
  dueDate: string // YYYY-MM-DD from date column
  assigneeId: string | null
  projectId: string | null
}

/**
 * Map a task with a due_date to a virtual all-day CalendarEventObject.
 * These events are synthesized (not stored in calendar_events) and are
 * never readOnly — task due dates can be rescheduled from the calendar.
 */
export function taskToCalendarEvent(task: TaskCalendarInput): CalendarEventObject {
  // All-day events: start = 00:00 UTC on the due date, end = same (convention for all-day)
  const startAt = new Date(`${task.dueDate}T00:00:00.000Z`).toISOString()
  const endAt = startAt

  return {
    id: `task:${task.id}`,
    tenantId: task.tenantId,
    createdBy: task.assigneeId ?? task.tenantId,
    title: task.title,
    description: null,
    startAt,
    endAt,
    allDay: true,
    location: null,
    source: 'task',
    taskId: task.id,
    projectId: task.projectId,
    customerId: null,
    externalId: null,
    externalCalendarId: null,
    syncedAt: null,
    syncStatus: 'local',
    readOnly: false,
    createdAt: startAt,
    updatedAt: startAt,
  }
}
