import type { CheckInStatus, Tier } from "../api/types";
import { firstName } from "./format";
type TieredFinding = { id: string; tier: string };
/** Findings that cannot wait for a check-in: Urgent review (CHK-6). */
export const urgentFindings = <T extends TieredFinding>(findings: T[]) =>
findings.filter((f) => f.tier === "get_help_now");
/** The clinician's "I will speak to Mariam today", kept for the day it was given. */
export type CallConfirmation = { patientId: string; confirmedAt: string };
const localDate = (d: Date, offsetMinutes: number) =>
new Date(d.getTime() + offsetMinutes * 60_000).toISOString().slice(0, 10);
/** A confirmation counts only on the clinic's day it was given. */
export function confirmationValid(
confirmation: CallConfirmation | null,
patientId: string,
now: Date,
clinicOffset: number,
): boolean {
if (!confirmation || confirmation.patientId !== patientId) return false;
return localDate(new Date(confirmation.confirmedAt), clinicOffset) === localDate(now, clinicOffset);
}
export type UrgentGate =
| { mode: "none"; canAskYasmar: true }
| { mode: "call_first"; canAskYasmar: boolean; confirmLine: string; callLine: string };
/**
* YCI-1a, urgent first: with an Urgent review finding, Context leads with "Call Mariam";
* Ask Yasmar to check in opens only after "I will speak to Mariam today".
*/
export function urgentGate(input: {
findings: TieredFinding[];
patientId: string;
patientName: string;
confirmation: CallConfirmation | null;
now: Date;
clinicOffset: number;
}): UrgentGate {
if (!urgentFindings(input.findings).length) return { mode: "none", canAskYasmar: true };
const first = firstName(input.patientName);
return {
mode: "call_first",
canAskYasmar: confirmationValid(input.confirmation, input.patientId, input.now, input.clinicOffset),
confirmLine: `I will speak to ${first} today`,
callLine: `Call ${first}`,
};
}
const finished: CheckInStatus[] = ["completed", "declined", "identity_not_confirmed", "cancelled"];
/**
* YCI-1a: a check-in linked to an Urgent review or Review today finding that has not
* finished by the end of clinic hours raises "Mariam not reached. Call today."
*/
export function notReachedAlert(input: {
status: CheckInStatus;
linkedTiers: (Tier | string)[];
patientName: string;
clinicCloseAt: Date | null;
now: Date;
}): string | null {
const pressing = input.linkedTiers.some((t) => t === "get_help_now" || t === "today");
if (!pressing || finished.includes(input.status)) return null;
const late = input.status === "not_reached" || (input.clinicCloseAt !== null && input.now >= input.clinicCloseAt);
return late ? `${firstName(input.patientName)} not reached. Call today.` : null;
}