/**
 * Forms service — typed client over the cms-core Forms REST endpoints.
 *
 * Every Forms admin component reads/writes through this module (never raw
 * `cmsApi` / `fetch`), so the network contract lives in one place. Read
 * fetchers re-surface `cmsApi`'s `{ error }` as a thrown error (so the
 * resource hook can show error/retry UI); mutations return `{ error? }`.
 *
 * The endpoint paths here are the contract implemented by cms-core
 * `packages/cms-core/src/api/handlers.ts` (PR 2). Domain types are re-used
 * from `@actuate-media/cms-core` so the admin can never drift from the server.
 */
import { cmsApi } from './api.js'
import type {
  FormDefinition,
  FormSchemaVersion,
  FormField,
  FormNotificationSettings,
  FormEmbedSettings,
  FormStatus,
  FormStats,
  FormsSidebarCount,
  FetchFormsParams,
  FormSubmission,
  FetchFormEntriesParams,
  EntryCounts,
} from '@actuate-media/cms-core'

export type {
  FormDefinition,
  FormSchemaVersion,
  FormField,
  FormFieldType,
  FormFieldOption,
  FieldValidationRules,
  FormNotificationSettings,
  FormEmbedSettings,
  FormStatus,
  FormStats,
  FormsSidebarCount,
  FormSubmission,
  FormSubmissionFile,
  FetchFormEntriesParams,
  EntryCounts,
  SpamStatus,
} from '@actuate-media/cms-core'

/**
 * `cmsApi` never throws — it returns `{ error, status }` on a network/HTTP
 * failure. Read (GET) fetchers must re-surface that as a thrown error so the
 * resource hook can distinguish "request failed" from "empty result".
 */
function throwIfError(res: { error?: string }): void {
  if (res.error) throw new Error(res.error)
}

/**
 * A form as returned by `GET /forms` — the typed definition plus the legacy
 * numeric aliases the list endpoint adds for backward compatibility.
 */
export interface FormListItem extends FormDefinition {
  /** `fields.length` precomputed by the server. */
  fieldCount?: number
  /** Alias of `totalEntries`. */
  submissions?: number
}

export interface FormSchemaResult {
  fields: FormField[]
  activeVersionId: string | null
  versions: FormSchemaVersion[]
}

// ─── Forms list / stats / sidebar ────────────────────────────────────────

function buildFormsQuery(params: FetchFormsParams): string {
  const qs = new URLSearchParams()
  if (params.search) qs.set('search', params.search)
  if (params.status) qs.set('status', params.status)
  if (typeof params.notifyEnabled === 'boolean') {
    qs.set('notifyEnabled', String(params.notifyEnabled))
  }
  if (params.sortBy) qs.set('sortBy', params.sortBy)
  if (params.sortDirection) qs.set('sortDirection', params.sortDirection)
  if (params.page) qs.set('page', String(params.page))
  if (params.pageSize) qs.set('pageSize', String(params.pageSize))
  const str = qs.toString()
  return str ? `?${str}` : ''
}

export async function fetchForms(params: FetchFormsParams = {}): Promise<FormListItem[]> {
  const res = await cmsApi<FormListItem[]>(`/forms${buildFormsQuery(params)}`)
  throwIfError(res)
  return res.data ?? []
}

export async function fetchFormById(id: string): Promise<FormDefinition | null> {
  const res = await cmsApi<FormDefinition>(`/forms/${encodeURIComponent(id)}`)
  throwIfError(res)
  return res.data ?? null
}

const EMPTY_STATS: FormStats = {
  totalForms: 0,
  activeForms: 0,
  totalEntries: 0,
  unreadEntries: 0,
}

export async function fetchFormStats(): Promise<FormStats> {
  const res = await cmsApi<FormStats>('/forms/stats')
  throwIfError(res)
  return res.data ?? EMPTY_STATS
}

export async function fetchFormsSidebarCounts(): Promise<FormsSidebarCount[]> {
  const res = await cmsApi<FormsSidebarCount[]>('/forms/sidebar-counts')
  throwIfError(res)
  return res.data ?? []
}

// ─── Form mutations ──────────────────────────────────────────────────────

export interface CreateFormPayload {
  name: string
  slug?: string
  description?: string
  status?: FormStatus
  template?: string
  fields?: FormField[]
}

export async function createForm(
  payload: CreateFormPayload,
): Promise<{ data?: FormDefinition; error?: string }> {
  const res = await cmsApi<FormDefinition>('/forms', {
    method: 'POST',
    body: JSON.stringify(payload),
  })
  return { data: res.data, error: res.error }
}

export async function updateForm(
  id: string,
  payload: Partial<Pick<FormDefinition, 'name' | 'slug' | 'description' | 'status'>>,
): Promise<{ data?: FormDefinition; error?: string }> {
  const res = await cmsApi<FormDefinition>(`/forms/${encodeURIComponent(id)}`, {
    method: 'PATCH',
    body: JSON.stringify(payload),
  })
  return { data: res.data, error: res.error }
}

export async function duplicateForm(
  id: string,
): Promise<{ data?: FormDefinition; error?: string }> {
  const res = await cmsApi<FormDefinition>(`/forms/${encodeURIComponent(id)}/duplicate`, {
    method: 'POST',
  })
  return { data: res.data, error: res.error }
}

/** Move a form to the archived state (hidden from embed pickers, no new submissions). */
export async function archiveForm(id: string): Promise<{ error?: string }> {
  return updateForm(id, { status: 'archived' })
}

/** Restore an archived form back to draft. */
export async function restoreForm(id: string): Promise<{ error?: string }> {
  return updateForm(id, { status: 'draft' })
}

export async function deleteForm(
  id: string,
  opts: { force?: boolean } = {},
): Promise<{ error?: string }> {
  const qs = opts.force ? '?force=true' : ''
  const res = await cmsApi(`/forms/${encodeURIComponent(id)}${qs}`, { method: 'DELETE' })
  return { error: res.error }
}

// ─── Schema ──────────────────────────────────────────────────────────────

export async function fetchFormSchema(id: string): Promise<FormSchemaResult> {
  const res = await cmsApi<FormSchemaResult>(`/forms/${encodeURIComponent(id)}/schema`)
  throwIfError(res)
  return res.data ?? { fields: [], activeVersionId: null, versions: [] }
}

export async function saveFormSchema(
  id: string,
  fields: FormField[],
  notes?: string,
): Promise<{ data?: { form: FormDefinition; version: FormSchemaVersion }; error?: string }> {
  const res = await cmsApi<{ form: FormDefinition; version: FormSchemaVersion }>(
    `/forms/${encodeURIComponent(id)}/schema`,
    { method: 'PUT', body: JSON.stringify({ fields, notes }) },
  )
  return { data: res.data, error: res.error }
}

// ─── Notifications ─────────────────────────────────────────────────────────

export async function fetchNotificationSettings(id: string): Promise<FormNotificationSettings> {
  const res = await cmsApi<FormNotificationSettings>(
    `/forms/${encodeURIComponent(id)}/notifications`,
  )
  throwIfError(res)
  return res.data ?? { enabled: false, recipients: [] }
}

export async function updateNotificationSettings(
  id: string,
  payload: Partial<FormNotificationSettings>,
): Promise<{ data?: FormNotificationSettings; error?: string }> {
  const res = await cmsApi<FormNotificationSettings>(
    `/forms/${encodeURIComponent(id)}/notifications`,
    { method: 'PUT', body: JSON.stringify(payload) },
  )
  return { data: res.data, error: res.error }
}

/** Lightweight notify on/off toggle used by the forms-list switch. */
export async function setNotifyEnabled(
  id: string,
  enabled: boolean,
): Promise<{ data?: { notifyEnabled: boolean }; error?: string }> {
  const res = await cmsApi<{ notifyEnabled: boolean }>(`/forms/${encodeURIComponent(id)}/notify`, {
    method: 'PUT',
    body: JSON.stringify({ enabled }),
  })
  return { data: res.data, error: res.error }
}

// ─── Embed ───────────────────────────────────────────────────────────────

export async function fetchEmbedSettings(id: string): Promise<FormEmbedSettings> {
  const res = await cmsApi<FormEmbedSettings>(`/forms/${encodeURIComponent(id)}/embed`)
  throwIfError(res)
  return res.data ?? {}
}

export async function updateEmbedSettings(
  id: string,
  payload: Partial<FormEmbedSettings>,
): Promise<{ data?: FormEmbedSettings; error?: string }> {
  const res = await cmsApi<FormEmbedSettings>(`/forms/${encodeURIComponent(id)}/embed`, {
    method: 'PUT',
    body: JSON.stringify(payload),
  })
  return { data: res.data, error: res.error }
}

// ─── Entries (submissions) ─────────────────────────────────────────────────

/** A page of submissions as returned by `GET /forms/entries`. */
export interface EntriesPage {
  entries: FormSubmission[]
  total: number
  page: number
  pageSize: number
}

/** Patch shape accepted by the entry mutation endpoints. */
export interface EntryPatch {
  unread?: boolean
  starred?: boolean
  archived?: boolean
}

function buildEntriesQuery(params: FetchFormEntriesParams): string {
  const qs = new URLSearchParams()
  if (params.search) qs.set('search', params.search)
  if (params.formId) qs.set('formId', params.formId)
  if (typeof params.unread === 'boolean') qs.set('unread', String(params.unread))
  if (typeof params.starred === 'boolean') qs.set('starred', String(params.starred))
  if (typeof params.archived === 'boolean') qs.set('archived', String(params.archived))
  if (params.spamStatus) qs.set('spamStatus', params.spamStatus)
  if (params.dateFrom) qs.set('dateFrom', params.dateFrom)
  if (params.dateTo) qs.set('dateTo', params.dateTo)
  if (params.thisWeek) qs.set('thisWeek', 'true')
  if (params.sortBy) qs.set('sortBy', params.sortBy)
  if (params.sortDirection) qs.set('sortDirection', params.sortDirection)
  if (params.page) qs.set('page', String(params.page))
  if (params.pageSize) qs.set('pageSize', String(params.pageSize))
  const str = qs.toString()
  return str ? `?${str}` : ''
}

const EMPTY_PAGE: EntriesPage = { entries: [], total: 0, page: 1, pageSize: 25 }

export async function fetchEntries(params: FetchFormEntriesParams = {}): Promise<EntriesPage> {
  const res = await cmsApi<EntriesPage>(`/forms/entries${buildEntriesQuery(params)}`)
  throwIfError(res)
  return res.data ?? EMPTY_PAGE
}

const EMPTY_COUNTS: EntryCounts = { total: 0, unread: 0, starred: 0, thisWeek: 0, byForm: {} }

export async function fetchEntryCounts(params: FetchFormEntriesParams = {}): Promise<EntryCounts> {
  const res = await cmsApi<EntryCounts>(`/forms/entries/counts${buildEntriesQuery(params)}`)
  throwIfError(res)
  return res.data ?? EMPTY_COUNTS
}

/** A single entry rendered against the schema version it was captured with. */
export interface EntryDetail {
  entry: FormSubmission
  fields: FormField[]
}

export async function fetchEntry(id: string): Promise<EntryDetail | null> {
  const res = await cmsApi<EntryDetail>(`/forms/entries/${encodeURIComponent(id)}`)
  throwIfError(res)
  return res.data ?? null
}

export async function updateEntry(
  id: string,
  patch: EntryPatch,
): Promise<{ data?: FormSubmission; error?: string }> {
  const res = await cmsApi<FormSubmission>(`/forms/entries/${encodeURIComponent(id)}`, {
    method: 'PATCH',
    body: JSON.stringify(patch),
  })
  return { data: res.data, error: res.error }
}

export async function deleteEntry(id: string): Promise<{ error?: string }> {
  const res = await cmsApi(`/forms/entries/${encodeURIComponent(id)}`, { method: 'DELETE' })
  return { error: res.error }
}

export async function bulkUpdateEntries(
  ids: string[],
  patch: EntryPatch,
): Promise<{ data?: { updated: number }; error?: string }> {
  const res = await cmsApi<{ updated: number }>('/forms/entries/bulk', {
    method: 'POST',
    body: JSON.stringify({ ids, patch }),
  })
  return { data: res.data, error: res.error }
}
