import { clientFetch } from '@/lib/api/client';
import { unwrap, type ApiEnvelope, type Paginated } from '@/lib/api/types';
import { BOOKINGS_PAGE_SIZE } from '../constants';
import type {
  BookingDetailDto,
  BookingListItemDto,
  BookingListParams,
  BookingSessionListItemDto,
  BookingsApi,
  CareInstructionsDto,
  CheckInVisitInput,
  CheckOutVisitInput,
  TodaySessionsParams,
  VisitVerificationDto,
} from '../types';

const BOOKINGS = '/api/v1/bookings';
const SESSIONS = '/api/v1/booking_sessions';

/**
 * Real HTTP implementation of the `BookingsApi` seam (b9 contract `dev/contracts/domains/bookings-evv.md`,
 * swagger `dev/contracts/openapi/swagger.v1.json`). Routes are action-style + snake_case; ids come from
 * the **route**; bodies/fields are camelCase and `clientFetch` returns the raw envelope, so we `unwrap()`.
 *
 * NOT the primary implementation this phase (`USE_BOOKINGS_MOCK = true`): a booking only exists after the
 * (mock-primary) request flow converts + is paid (b10), so `bookings/list` has nothing to return yet.
 * The server infers the viewer from auth + tenancy (nurse view masks `addressSnapshotJson`; the
 * care-instructions read 404s for anyone but the assigned nurse/admin), so the `viewerRole` args a mock
 * needs are ignored here. The EVV commands send only the coordinates — the server timestamps the
 * authoritative `checkInAt`, so the client's `capturedAt` is not sent. One config flip selects this.
 */
export const bookingsClientApi: BookingsApi = {
  getBookingDetail: async (id: number) =>
    unwrap(await clientFetch<ApiEnvelope<BookingDetailDto>>(`${BOOKINGS}/get/${id}`)),

  listBookings: async (params: BookingListParams): Promise<Paginated<BookingListItemDto>> => {
    const query = new URLSearchParams();
    query.set('role', params.role);
    if (params.status) query.set('status', params.status);
    query.set('page', String(params.page ?? 1));
    query.set('pageSize', String(params.pageSize ?? BOOKINGS_PAGE_SIZE));
    return unwrap(await clientFetch<ApiEnvelope<Paginated<BookingListItemDto>>>(`${BOOKINGS}/list?${query.toString()}`));
  },

  listTodaySessions: async (params: TodaySessionsParams): Promise<Paginated<BookingSessionListItemDto>> => {
    const query = new URLSearchParams();
    if (params.date) query.set('date', params.date);
    query.set('page', String(params.page ?? 1));
    query.set('pageSize', String(params.pageSize ?? BOOKINGS_PAGE_SIZE));
    return unwrap(
      await clientFetch<ApiEnvelope<Paginated<BookingSessionListItemDto>>>(`${SESSIONS}/today?${query.toString()}`),
    );
  },

  getSessionEvv: async (sessionId: number) =>
    unwrap(await clientFetch<ApiEnvelope<VisitVerificationDto>>(`${SESSIONS}/evv/${sessionId}`)),

  getCareInstructions: async (bookingId: number) =>
    unwrap(await clientFetch<ApiEnvelope<CareInstructionsDto>>(`${BOOKINGS}/care_instructions/${bookingId}`)),

  checkInVisit: async (input: CheckInVisitInput) =>
    unwrap(
      await clientFetch<ApiEnvelope<VisitVerificationDto>>(`${SESSIONS}/check_in/${input.bookingSessionId}`, {
        method: 'POST',
        body: JSON.stringify({ latitude: input.latitude, longitude: input.longitude }),
      }),
    ),

  checkOutVisit: async (input: CheckOutVisitInput) =>
    unwrap(
      await clientFetch<ApiEnvelope<VisitVerificationDto>>(`${SESSIONS}/check_out/${input.bookingSessionId}`, {
        method: 'POST',
        body: JSON.stringify({ latitude: input.latitude, longitude: input.longitude }),
      }),
    ),
};
