import { clientFetch } from '@/lib/api/client';
import { unwrap, type ApiEnvelope, type Paginated, type PageParams } from '@/lib/api/types';
import { NOTIFICATIONS_PAGE_SIZE } from '../constants';
import { parseNotificationData } from '../parse';
import type { AppNotification, NotificationsApi } from '../types';

const API = '/api/v1';

/** Wire `NotificationDto` (camelCase; `dataJson` is a JSON string parsed into the typed union). */
interface NotificationWire {
  id: number;
  type: string;
  title: string;
  body: string | null;
  dataJson: string | null;
  isRead: boolean;
  readAt: string | null;
  createdAt: string;
}

function mapNotification(w: NotificationWire): AppNotification {
  return {
    id: w.id,
    type: w.type,
    title: w.title,
    body: w.body,
    isRead: w.isRead,
    createdAt: w.createdAt,
    data: parseNotificationData(w.type, w.dataJson),
  };
}

/**
 * Real HTTP implementation of the `NotificationsApi` seam (b1 contract, `notifications` controller). All four
 * methods map published routes:
 *  - `listNotifications` → `GET notifications/get_notifications` (unread-first, paginated).
 *  - `getUnreadCount`    → `GET notifications/get_unread_count` (`{ count }`).
 *  - `markRead`          → `POST notifications/mark_notification_read` (`{ notificationId }`).
 *  - `markAllRead`       → `POST notifications/mark_all_read`.
 *
 * NOT the primary implementation this phase (`USE_NOTIFICATIONS_MOCK = true`) — nothing dispatches
 * notifications client-side yet (see `constants.ts`). Pagination follows the repo convention (`pageSize`,
 * REQ-010).
 */
export const notificationsClientApi: NotificationsApi = {
  listNotifications: async (params: PageParams): Promise<Paginated<AppNotification>> => {
    const query = new URLSearchParams();
    query.set('page', String(params.page ?? 1));
    query.set('pageSize', String(params.pageSize ?? NOTIFICATIONS_PAGE_SIZE));
    const wire = unwrap(
      await clientFetch<ApiEnvelope<Paginated<NotificationWire>>>(
        `${API}/notifications/get_notifications?${query.toString()}`,
      ),
    );
    return { ...wire, items: wire.items.map(mapNotification) };
  },

  getUnreadCount: async (): Promise<number> => {
    const wire = unwrap(await clientFetch<ApiEnvelope<{ count: number }>>(`${API}/notifications/get_unread_count`));
    return wire.count;
  },

  markRead: async (notificationId: number): Promise<void> => {
    await clientFetch<ApiEnvelope<boolean>>(`${API}/notifications/mark_notification_read`, {
      method: 'POST',
      body: JSON.stringify({ notificationId }),
    });
  },

  markAllRead: async (): Promise<void> => {
    await clientFetch<ApiEnvelope<boolean>>(`${API}/notifications/mark_all_read`, { method: 'POST' });
  },
};
