import type { Extension, HealthcareService, PractitionerRole, Reference } from 'fhir/r4'; // Whether a service is patient-self-bookable. Byte-identical to the server contract // (docs/appointments/practitioner-services-and-self-booking-design.md ยง3). ONE extension URL on three carriers - // the carrier location determines the level: // HealthcareService.extension org DEFAULT (absent true) // PractitionerRole.healthcareService[i].extension practitioner OVERRIDE (absent inherit default) // Schedule.actor[i].extension block OVERRIDE (absent inherit practitioner) [Piece C] export const SERVICE_PATIENT_SELF_BOOKABLE_EXTENSION_URL = 'https://akashichealthrecords.com/fhir/StructureDefinition/service-patient-self-bookable'; // Tri-state form value for the per-service practitioner control (Default / Enabled / Disabled). export type SelfBookableChoice = 'default' | 'enabled' | 'disabled'; const readBoolExt = (extensions: Extension[] | undefined): boolean | undefined => { const ext = extensions?.find((e) => e.url === SERVICE_PATIENT_SELF_BOOKABLE_EXTENSION_URL); return ext ? ext.valueBoolean : undefined; }; // Org default carried on the HealthcareService. Absent true (services are self-bookable unless curated off). export const getServiceSelfBookableDefault = (service?: HealthcareService | null): boolean => readBoolExt(service?.extension) ?? true; // The explicit override (or undefined = inherit) carried on a service Reference - practitioner or block level. export const getRefSelfBookableOverride = (ref?: Reference): boolean | undefined => readBoolExt(ref?.extension); // Tri-state form value <-> stored override boolean|undefined. export const overrideToChoice = (override: boolean | undefined): SelfBookableChoice => override === undefined ? 'default' : override ? 'enabled' : 'disabled'; export const choiceToOverride = (choice: SelfBookableChoice): boolean | undefined => choice === 'default' ? undefined : choice === 'enabled'; // Rebuild a service Reference's extension array applying the chosen override, PRESERVING any other ref extensions. // override === undefined removes the self-bookable extension (inherit); true/false writes an explicit valueBoolean. export const applyRefSelfBookable = (ref: Reference, override: boolean | undefined): Reference => { const others = (ref.extension ?? []).filter((e) => e.url !== SERVICE_PATIENT_SELF_BOOKABLE_EXTENSION_URL); const next: Extension[] = override === undefined ? others : [...others, { url: SERVICE_PATIENT_SELF_BOOKABLE_EXTENSION_URL, valueBoolean: override }]; const result: Reference = { ...ref }; if (next.length) { result.extension = next; } else { delete result.extension; } return result; }; // Full resolution for a (service, practitionerRole). Block override is deferred to Piece C; the caller still // applies the block master gate (schedule-allow-patient-self-booking) on top of this. export const resolveServiceSelfBookable = ( service: HealthcareService | undefined, practitionerRole?: PractitionerRole, ): boolean => { const ref = (practitionerRole?.healthcareService ?? []).find( (r) => r.reference?.split('/').pop() === service?.id, ); const practitionerOverride = getRefSelfBookableOverride(ref); if (practitionerOverride !== undefined) { return practitionerOverride; } return getServiceSelfBookableDefault(service); };