// api.ts から分割（挙動不変）: 通知 V2（Web Push）。
import { BASE } from './client';

// ── Notifications V2 (Web Push) ───────────────────────────────────────

export type NotifyEventType = 'running' | 'succeeded' | 'failed' | 'waiting_human';

export interface NotificationPrefsDTO {
  userId: string;
  enabled: boolean;
  events: Record<NotifyEventType, boolean>;
  includeDetails: boolean;
  v1Migrated: boolean;
  updatedAt: string;
}

export interface NotificationPrefsInput {
  enabled?: boolean;
  events?: Partial<Record<NotifyEventType, boolean>>;
  includeDetails?: boolean;
}

export interface PushSubscriptionPublic {
  id: string;
  endpointHost: string;
  userAgent: string | null;
  createdAt: string;
  lastSuccessAt: string | null;
  lastFailureAt: string | null;
  failureCount: number;
}

export interface VapidPublicKeyDTO {
  publicKey: string;
  keyId: string;
}

async function notificationsJsonOrThrow<T>(res: Response, fallback: string): Promise<T> {
  const data = await res.json().catch(() => ({} as Record<string, unknown>));
  if (!res.ok) throw new Error((data as { error?: string }).error ?? fallback);
  return data as T;
}

export async function fetchVapidPublicKey(): Promise<VapidPublicKeyDTO> {
  const res = await fetch(`${BASE}/notifications/vapid-public-key`);
  return notificationsJsonOrThrow(res, 'failed to fetch VAPID key');
}

export async function listPushSubscriptions(): Promise<PushSubscriptionPublic[]> {
  const res = await fetch(`${BASE}/notifications/subscriptions`);
  const data = await notificationsJsonOrThrow<{ subscriptions: PushSubscriptionPublic[] }>(
    res, 'failed to list subscriptions',
  );
  return data.subscriptions;
}

export async function postPushSubscription(input: {
  endpoint: string;
  p256dh: string;
  auth: string;
  userAgent?: string;
}): Promise<{ id: string }> {
  const res = await fetch(`${BASE}/notifications/subscriptions`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(input),
  });
  return notificationsJsonOrThrow(res, 'failed to register subscription');
}

export async function deletePushSubscription(id: string): Promise<void> {
  const res = await fetch(`${BASE}/notifications/subscriptions/${id}`, { method: 'DELETE' });
  await notificationsJsonOrThrow(res, 'failed to delete subscription');
}

export async function fetchNotificationPrefs(): Promise<NotificationPrefsDTO> {
  const res = await fetch(`${BASE}/notifications/preferences`);
  return notificationsJsonOrThrow(res, 'failed to fetch preferences');
}

export async function updateNotificationPrefs(
  input: NotificationPrefsInput,
): Promise<NotificationPrefsDTO> {
  const res = await fetch(`${BASE}/notifications/preferences`, {
    method: 'PUT',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(input),
  });
  return notificationsJsonOrThrow(res, 'failed to update preferences');
}

export async function migrateLocalStoragePrefs(
  input: NotificationPrefsInput,
): Promise<{ ok: boolean; prefs: NotificationPrefsDTO } | { alreadyMigrated: true }> {
  const res = await fetch(`${BASE}/notifications/preferences/migrate-from-localstorage`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(input),
  });
  if (res.status === 409) return { alreadyMigrated: true };
  return notificationsJsonOrThrow(res, 'failed to migrate preferences');
}

export async function postTestNotification(): Promise<{ ok: boolean }> {
  const res = await fetch(`${BASE}/notifications/test`, { method: 'POST' });
  return notificationsJsonOrThrow(res, 'failed to send test notification');
}
