export interface Webhook {
  id: string;
  restaurantId: string;
  endpointUrl: string;
  events: string[];
  secret: string;
  status: 'active' | 'inactive';
  successRate?: number;
  totalDeliveries?: number;
  pendingAttempts: number;
  exhaustedAttempts: number;
  createdAt: string;
  updatedAt?: string;
}

export interface WebhookListResponse {
  webhooks: Webhook[];
}

function normalize(row: Record<string, unknown>): Webhook {
  const rawEvents = (row.events ?? []) as string[] | string;
  const events = typeof rawEvents === 'string'
    ? (() => { try { return JSON.parse(rawEvents); } catch { return []; } })()
    : rawEvents;
  return {
    id: row.id as string,
    restaurantId: (row.restaurantId ?? row.restaurant_id) as string,
    endpointUrl: (row.endpointUrl ?? row.endpoint_url) as string,
    events: Array.isArray(events) ? events : [],
    secret: row.secret as string,
    status: row.status as 'active' | 'inactive',
    successRate: row.successRate != null ? Number(row.successRate) : row.success_rate != null ? Number(row.success_rate) : undefined,
    totalDeliveries: row.totalDeliveries != null ? Number(row.totalDeliveries) : row.total_deliveries != null ? Number(row.total_deliveries) : undefined,
    pendingAttempts: Number(row.pendingAttempts ?? row.pending_attempts ?? 0),
    exhaustedAttempts: Number(row.exhaustedAttempts ?? row.exhausted_attempts ?? 0),
    createdAt: (row.createdAt ?? row.created_at) as string,
    updatedAt: (row.updatedAt ?? row.updated_at) as string | undefined,
  };
}

async function apiFetch<T>(url: string, options?: RequestInit): Promise<T> {
  const res = await fetch(url, { credentials: 'include', ...options });
  const json = (await res.json().catch(() => ({}))) as Record<string, unknown>;
  if (!res.ok) throw new Error((json.error as string) || `Request failed: ${res.status}`);
  return json as T;
}

export async function listWebhooks(): Promise<WebhookListResponse> {
  const data = await apiFetch<{ webhooks: Record<string, unknown>[] }>('/api/webhooks');
  return { webhooks: data.webhooks.map(normalize) };
}

export async function getWebhook(id: string): Promise<{ webhook: Webhook }> {
  const data = await apiFetch<{ webhook: Record<string, unknown> }>(`/api/webhooks/${id}`);
  return { webhook: normalize(data.webhook) };
}

export async function createWebhook(body: Record<string, unknown>): Promise<{ webhook: Webhook }> {
  const data = await apiFetch<{ webhook: Record<string, unknown> }>('/api/webhooks', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(body),
  });
  return { webhook: normalize(data.webhook) };
}

export async function updateWebhook(id: string, body: Record<string, unknown>): Promise<{ webhook: Webhook }> {
  const data = await apiFetch<{ webhook: Record<string, unknown> }>(`/api/webhooks/${id}`, {
    method: 'PATCH',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(body),
  });
  return { webhook: normalize(data.webhook) };
}

export async function deleteWebhook(id: string): Promise<{ success: boolean }> {
  return apiFetch<{ success: boolean }>(`/api/webhooks/${id}`, { method: 'DELETE' });
}

export interface DeliveryLog {
  id: string;
  webhookId: string;
  restaurantId: string;
  event: string;
  status: 'success' | 'failed' | 'pending';
  responseCode: number | null;
  responseBody: string | null;
  durationMs: number | null;
  errorMessage: string | null;
  triggeredAt: string;
  endpointUrl: string;
}

function normalizeLog(row: Record<string, unknown>): DeliveryLog {
  return {
    id: row.id as string,
    webhookId: (row.webhookId ?? row.webhook_id) as string,
    restaurantId: (row.restaurantId ?? row.restaurant_id) as string,
    event: row.event as string,
    status: row.status as 'success' | 'failed' | 'pending',
    responseCode: (row.responseCode ?? row.response_code) as number | null,
    responseBody: (row.responseBody ?? row.response_body ?? null) as string | null,
    durationMs: (row.durationMs ?? row.duration_ms) as number | null,
    errorMessage: (row.errorMessage ?? row.error_message) as string | null,
    triggeredAt: (row.triggeredAt ?? row.triggered_at) as string,
    endpointUrl: (row.endpointUrl ?? row.endpoint_url) as string,
  };
}

export async function listDeliveryLogs(webhookId?: string): Promise<{ logs: DeliveryLog[] }> {
  const qs = webhookId ? `?webhook_id=${encodeURIComponent(webhookId)}` : '';
  const data = await apiFetch<{ logs: Record<string, unknown>[] }>(`/api/webhooks/delivery-logs${qs}`);
  return { logs: data.logs.map(normalizeLog) };
}

export type DeliveryAttemptStatus = 'pending' | 'processing' | 'succeeded' | 'exhausted';

export interface DeliveryAttempt {
  id: string;
  webhookId: string;
  restaurantId: string;
  event: string;
  endpointUrl: string;
  status: DeliveryAttemptStatus;
  attemptCount: number;
  maxAttempts: number;
  lastResponseCode: number | null;
  lastErrorMessage: string | null;
  nextRetryAt: string | null;
  lastAttemptedAt: string | null;
  createdAt: string;
  updatedAt: string;
}

function normalizeAttempt(row: Record<string, unknown>): DeliveryAttempt {
  return {
    id: row.id as string,
    webhookId: (row.webhookId ?? row.webhook_id) as string,
    restaurantId: (row.restaurantId ?? row.restaurant_id) as string,
    event: row.event as string,
    endpointUrl: (row.endpointUrl ?? row.endpoint_url) as string,
    status: row.status as DeliveryAttemptStatus,
    attemptCount: (row.attemptCount ?? row.attempt_count) as number,
    maxAttempts: (row.maxAttempts ?? row.max_attempts) as number,
    lastResponseCode: (row.lastResponseCode ?? row.last_response_code ?? null) as number | null,
    lastErrorMessage: (row.lastErrorMessage ?? row.last_error_message ?? null) as string | null,
    nextRetryAt: (row.nextRetryAt ?? row.next_retry_at ?? null) as string | null,
    lastAttemptedAt: (row.lastAttemptedAt ?? row.last_attempted_at ?? null) as string | null,
    createdAt: (row.createdAt ?? row.created_at) as string,
    updatedAt: (row.updatedAt ?? row.updated_at) as string,
  };
}

export async function listDeliveryAttempts(webhookId?: string): Promise<{ attempts: DeliveryAttempt[] }> {
  const qs = webhookId ? `?webhook_id=${encodeURIComponent(webhookId)}` : '';
  const data = await apiFetch<{ attempts: Record<string, unknown>[] }>(`/api/webhooks/delivery-attempts${qs}`);
  return { attempts: data.attempts.map(normalizeAttempt) };
}

export async function resendDeliveryAttempt(id: string): Promise<{ attempt: DeliveryAttempt }> {
  const data = await apiFetch<{ attempt: Record<string, unknown> }>(
    `/api/webhooks/delivery-attempts/${id}/resend`,
    { method: 'POST' }
  );
  return { attempt: normalizeAttempt(data.attempt) };
}
