import { clientFetch } from '@/lib/api/client';
import { unwrap, type ApiEnvelope, type Paginated } from '@/lib/api/types';
import type { PageParams } from '@/lib/api/types';
import { RECORD_HISTORY_PAGE_SIZE } from '../constants';
import type {
  CreateVisitNoteRequest,
  FamilyCareRecord,
  PatientRecordsApi,
  RecordAccess,
  TaskResult,
  UpdateFamilyRecordRequest,
  VisitNote,
  WriteVisitNoteResult,
} from '../types';

const API = '/api/v1';

/** Wire `CareRecordDto` — the nurse-authored note (`body` decrypted after the access check). */
interface CareRecordWire {
  id: number;
  patientId: number;
  bookingId: number | null;
  nurseProfileId: number;
  nurseName: string | null;
  body: string;
  recordedAt: string;
}

function toVisitNote(w: CareRecordWire): VisitNote {
  return {
    id: w.id,
    bookingId: w.bookingId,
    nurseProfileId: w.nurseProfileId,
    nurseDisplayName: w.nurseName,
    body: w.body,
    // The wire body carries only free text; the structured checklist is composed into it on write (see below).
    taskResults: [],
    recordedAt: w.recordedAt,
  };
}

/**
 * Folds the nurse's ticked task checklist into the free-text note body, because the wire
 * `WriteCareRecordBody` has only `{ bookingId?, body }` — there is no structured task field (REQ-027 would
 * add one). The mock keeps `taskResults` structured; the real path serialises them as a leading summary line.
 */
export function composeVisitNoteBody(body: string, taskResults: TaskResult[] | undefined): string {
  const trimmed = body.trim();
  if (!taskResults || taskResults.length === 0) return trimmed;
  const summary = taskResults.map((t) => `${t.done ? '✓' : '✗'} ${t.label}`).join(' · ');
  return trimmed ? `${summary}\n\n${trimmed}` : summary;
}

/**
 * Real HTTP implementation of the `PatientRecordsApi` seam (b14 contract). Two methods map **published**
 * b14 routes:
 *  - `getPatientHistory` → `GET patients/{id}/care_records` (the patient-scoped, newest-first note history;
 *    a `403` from the envelope surfaces as an `ApiError` the E2 screen renders as access-denied).
 *  - `createVisitNote`   → `POST patients/{id}/care_records` (a nurse appends one encrypted note).
 *
 * The family-record + access methods target contract gaps the frontend filed (**REQ-027**) — no wire
 * endpoint exists — which is why the domain stays mock-primary (see `constants.ts`).
 *
 * NOT the primary implementation this phase (`USE_PATIENT_RECORDS_MOCK = true`).
 */
export const patientRecordsClientApi: PatientRecordsApi = {
  // REQ-027: proposed owner/nurse-scoped read of the family-owned record (no wire endpoint yet).
  getFamilyRecord: async (patientId: number): Promise<FamilyCareRecord> =>
    unwrap(await clientFetch<ApiEnvelope<FamilyCareRecord>>(`${API}/patients/${patientId}/care_record`)),

  // REQ-027: proposed access check. On the real path the 403 on the history read is the true access signal.
  getRecordAccess: async (patientId: number): Promise<RecordAccess> =>
    unwrap(await clientFetch<ApiEnvelope<RecordAccess>>(`${API}/patients/${patientId}/record_access`)),

  getPatientHistory: async (patientId: number, params: PageParams): Promise<Paginated<VisitNote>> => {
    const query = new URLSearchParams();
    query.set('page', String(params.page ?? 1));
    query.set('pageSize', String(params.pageSize ?? RECORD_HISTORY_PAGE_SIZE));
    const page = unwrap(
      await clientFetch<ApiEnvelope<Paginated<CareRecordWire>>>(
        `${API}/patients/${patientId}/care_records?${query.toString()}`,
      ),
    );
    return { ...page, items: page.items.map(toVisitNote) };
  },

  // REQ-027: proposed customer edit of the family record.
  updateFamilyRecord: async (patientId: number, body: UpdateFamilyRecordRequest): Promise<FamilyCareRecord> =>
    unwrap(
      await clientFetch<ApiEnvelope<FamilyCareRecord>>(`${API}/patients/${patientId}/care_record`, {
        method: 'PUT',
        body: JSON.stringify(body),
      }),
    ),

  createVisitNote: async (patientId: number, body: CreateVisitNoteRequest): Promise<WriteVisitNoteResult> =>
    unwrap(
      await clientFetch<ApiEnvelope<WriteVisitNoteResult>>(`${API}/patients/${patientId}/care_records`, {
        method: 'POST',
        body: JSON.stringify({
          bookingId: body.bookingId ?? null,
          body: composeVisitNoteBody(body.body, body.taskResults),
        }),
      }),
    ),
};
