'use client';

import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { useLocale, useTranslations } from 'next-intl';
import { useRouter } from '@/i18n/navigation';
import { Button } from '@/components/ui/shared/Button';
import { PatientSearchCombobox } from '@/components/ui/patient/PatientSearchCombobox';
import {
  TreatmentLabCasesPanel,
  type TreatmentLabCasesScope,
} from '@/components/ui/treatment/TreatmentLabCasesPanel';
import { TreatmentRailSection } from '@/components/ui/treatment/TreatmentRailSection';
import { AppointmentsStrip } from '@/components/ui/treatment/AppointmentsStrip';
import { NewTreatmentPatientPicker } from '@/components/ui/treatment/NewTreatmentPatientPicker';
import { FdiToothChart } from '@/components/ui/treatment/FdiToothChart';
import { ProsthesisAssignChart } from '@/components/ui/treatment/ProsthesisAssignChart';
import { LabCasesDispatchPanel } from '@/components/ui/treatment/LabCasesDispatchPanel';
import { LabDispatchAttentionPanel } from '@/components/ui/treatment/LabDispatchAttentionPanel';
import { PastTreatmentsPanel } from '@/components/ui/treatment/PastTreatmentsPanel';
import { TreatmentDetailsEditor } from '@/components/ui/treatment/TreatmentDetailsEditor';
import { TreatmentPreviewCard } from '@/components/ui/treatment/TreatmentPreviewCard';
import { treatmentTypeLabelFromCatalog, treatmentTypeColor } from '@/components/shared/treatmentTypeDisplay';
import {
  addCalendarDays,
  compareLocalDayStart,
  isSameLocalCalendarDay,
  startOfLocalDay,
} from '@/components/appointments/appointmentTime';
import { appointmentsApi } from '@/lib/api/appointments';
import { treatmentCatalogApi } from '@/lib/api/treatment-catalog';
import { prosthesisCatalogApi } from '@/lib/api/prosthesis-catalog';
import { voiceApi } from '@/lib/api/voice';
import { useVoiceCapture } from '@/lib/voice/useVoiceCapture';
import { VoiceReviewSheet } from '@/components/ui/treatment/VoiceReviewSheet';
import type {
  VoiceApplySelection,
  VoiceAvailability,
  VoiceExtractionResult,
} from '@/types/voice';
import { treatmentsApi } from '@/lib/api/treatments';
import { notificationsApi } from '@/lib/api/notifications';
import { pickAutoAppointment } from '@/components/shared/treatmentSelection';
import { unscheduledStripColorCode, type DayStripItem } from '@/components/treatment/dayStrip';
import {
  areDetailsPersistable,
  defaultTreatmentTypeForAppointment,
  isDetailTypeSelected,
  isEmptyDraftDetail,
  areUnscheduledDetailsStripDeletable,
} from '@/components/treatment/treatmentDetailRules';
import {
  applyShiftRange,
  connectedTeethSet,
  deriveTeethFromGroups,
  groupsFromFlatTeeth,
  linkAdjacentTeeth,
  linkedEdgesFromGroups,
  pruneToothProsthesisForGroups,
  toothEdgeKey,
  toggleToothInGroups,
  unlinkAdjacentTeeth,
} from '@/components/treatment/toothSelectionGroups';
import { hasArchJobs, pruneDetailTeethToJobs } from '@/components/treatment/prosthesisTree';
import type { LabDispatchAttentionItem } from '@/components/treatment/labDispatchAttention';
import { collectLabDispatchAttention } from '@/components/treatment/labDispatchAttention';
import {
  loadRecentLabIds,
  MAX_RECENT_LABS,
  rememberRecentLab,
} from '@/components/treatment/labDispatchDefaults';
import { canEditTreatment, canViewTreatment, canAccessDashboardRoute } from '@/components/shared/permissions';
import { scrollWithinMainScrollContainer } from '@/components/shared/scrollWithinMain';
import { useMarkTabReadOnVisit, useTabBadgeCounts } from '@/lib/hooks/useTabBadgeCounts';
import { tabBadgesChangedEventName } from '@/lib/tabBadgeUtils';
import { notifyTabBadgesChanged } from '@/lib/tabBadgeUtils';
import { APP_DATE, formatAppDate, formatAppTimeRange } from '@/lib/i18n/format';
import { useAuth } from '@/lib/hooks/useAuth';
import { getUserFacingError } from '@/components/shared/formatApiError';
import { useToast } from '@/lib/hooks/useToast';
import { usePatientSearchQuery } from '@/lib/hooks/usePatientSearchQuery';
import type { Organization } from '@/types/organization';
import type { Patient } from '@/types/patient';
import type { AppointmentRecord } from '@/types/appointment';
import type { ProsthesisCatalogEntry, TreatmentCatalogEntry } from '@/types/treatment-catalog';
import type {
  FdiToothId,
  LabCaseDraft,
  LinkedOrganizationOption,
  PastLabCase,
  PastTreatment,
  PastTreatmentCase,
  PastTreatmentDetail,
  TreatmentAppointment,
  TreatmentDetailDraft,
} from '@/types/treatment';
import type { PatientLabCaseSummary } from '@/types/lab-case-activity';

type WorkspaceMode = 'live' | 'historical';

function isTreatmentDayHistorical(treatmentAt: string, todayStart: Date): boolean {
  return compareLocalDayStart(new Date(treatmentAt), todayStart) < 0;
}

function withoutEmptyLabCaseDrafts(drafts: LabCaseDraft[]): LabCaseDraft[] {
  return drafts.filter((lc) => lc.sentAt || Boolean(lc.detailClientId));
}

/** Prefer the unsent draft this chart writes to; fall back to a sent case for locked details. */
function labCaseDraftForDetail(
  drafts: LabCaseDraft[],
  detailClientId: string,
): LabCaseDraft | undefined {
  const rows = drafts.filter((lc) => lc.detailClientId === detailClientId);
  return rows.find((lc) => !lc.sentAt) ?? rows[0];
}

function pruneLabDependentDetailsToJobs(
  details: TreatmentDetailDraft[],
  drafts: LabCaseDraft[],
  labDependentCodes: Set<string>,
): TreatmentDetailDraft[] {
  if (labDependentCodes.size === 0) return details;
  return details.map((detail) => {
    if (!labDependentCodes.has(detail.treatmentType)) return detail;
    const jobs = labCaseDraftForDetail(drafts, detail.clientId)?.toothProsthesis ?? [];
    return pruneDetailTeethToJobs(detail, jobs);
  });
}

function labCaseDraftsToPast(
  labCaseDrafts: LabCaseDraft[],
  details: TreatmentDetailDraft[],
): PastLabCase[] {
  return labCaseDrafts.map((lc) => {
    const linkedDetail = lc.detailClientId
      ? details.find((d) => d.clientId === lc.detailClientId)
      : undefined;

    return {
      id: lc.id ?? lc.clientId,
      clientId: lc.clientId,
      destinationOrganizationId: lc.destinationOrganizationId,
      sentAt: lc.sentAt ?? null,
      treatmentDetailId: linkedDetail?.id ?? null,
      detail: linkedDetail
        ? {
            id: linkedDetail.id ?? linkedDetail.clientId,
            clientId: linkedDetail.clientId,
            treatmentType: linkedDetail.treatmentType,
            teeth: linkedDetail.teeth,
            toothSelectionGroups: linkedDetail.toothSelectionGroups,
          }
        : null,
      sends: lc.sends ?? [],
      toothProsthesis: lc.toothProsthesis,
    };
  });
}

function enrichDetailsWithLabSendState(
  details: TreatmentDetailDraft[],
  labCaseDrafts: LabCaseDraft[],
): TreatmentDetailDraft[] {
  return details.map((detail) => {
    const sentLabCase = labCaseDrafts.find(
      (lc) => lc.sentAt && lc.detailClientId === detail.clientId,
    );
    if (!sentLabCase) return detail;
    return {
      ...detail,
      labCaseId: sentLabCase.id ?? detail.labCaseId,
      sentAt: sentLabCase.sentAt ?? detail.sentAt,
      sends: sentLabCase.sends ?? detail.sends,
      sendToOrganizationIds: sentLabCase.destinationOrganizationId
        ? [sentLabCase.destinationOrganizationId]
        : detail.sendToOrganizationIds,
    };
  });
}

function buildWorkspaceSnapshot(
  ctx: { id: string; patientId: string; treatmentAt: string; appointmentId: string | null },
  details: TreatmentDetailDraft[],
  labCaseDrafts: LabCaseDraft[],
  title: string,
  id?: string,
): PastTreatment {
  const detailsForPreview = enrichDetailsWithLabSendState(details, labCaseDrafts);
  return {
    ...detailsToPreviewTreatment(detailsForPreview, {
      id: id ?? `preview-${ctx.id}`,
      title,
      patientId: ctx.patientId,
      treatmentAt: ctx.treatmentAt,
    }),
    appointmentId: ctx.appointmentId,
    labCases: labCaseDraftsToPast(labCaseDrafts, details),
  };
}

function newDetail(defaultTreatmentType?: string): TreatmentDetailDraft {
  return {
    clientId:
      typeof crypto !== 'undefined' && 'randomUUID' in crypto
        ? crypto.randomUUID()
        : `detail-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`,
    treatmentType: defaultTreatmentType ?? '',
    teeth: [],
    toothSelectionGroups: [],
    comment: '',
    attachmentMetas: [],
    sendToOrganizationIds: [],
    sentAt: null,
  };
}

function newLabCaseDraft(): LabCaseDraft {
  return {
    clientId:
      typeof crypto !== 'undefined' && 'randomUUID' in crypto
        ? crypto.randomUUID()
        : `lab-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`,
    destinationOrganizationId: null,
    detailClientId: null,
    toothProsthesis: [],
    attachmentIds: [],
    sentAt: null,
    sends: [],
  };
}

function mapAppointment(record: AppointmentRecord): TreatmentAppointment {
  return {
    id: record.id,
    patientId: record.patientId,
    patientFirstName: record.patient.firstName,
    patientLastName: record.patient.lastName,
    patientMobile: record.patient.mobile,
    providerUserId: record.providerUserId,
    startAt: record.startAt,
    endAt: record.endAt,
    purpose: record.purpose,
  };
}

function mapDetailFromApi(d: PastTreatmentCase): TreatmentDetailDraft {
  const teeth = d.teeth;
  const toothSelectionGroups = groupsFromFlatTeeth(teeth, d.toothSelectionGroups ?? null);
  return {
    clientId: d.clientId,
    id: d.id,
    treatmentType: d.treatmentType,
    teeth,
    toothSelectionGroups,
    comment: d.notes ?? '',
    attachmentMetas: d.attachmentMetas ?? [],
    labCaseId: d.labCaseId ?? null,
    taskProgress: d.taskProgress ?? null,
    sendToOrganizationIds: d.destinationOrganizationId ? [d.destinationOrganizationId] : [],
    sends: d.sends ?? [],
    sentAt: d.sentAt ?? null,
  };
}

function draftToPastDetail(d: TreatmentDetailDraft): PastTreatmentDetail {
  return {
    id: d.id ?? d.clientId,
    clientId: d.clientId,
    treatmentType: d.treatmentType,
    teeth: d.teeth,
    toothSelectionGroups: d.toothSelectionGroups,
    notes: d.comment,
    attachmentMetas: d.attachmentMetas,
    labCaseId: d.labCaseId ?? null,
    taskProgress: d.taskProgress ?? null,
    sends: d.sends ?? [],
    sentAt: d.sentAt ?? null,
  };
}

function mapLabCaseDraftFromApi(lc: PastLabCase): LabCaseDraft {
  return {
    clientId: lc.clientId,
    id: lc.id,
    destinationOrganizationId: lc.destinationOrganizationId,
    detailClientId: lc.detail?.clientId ?? null,
    toothProsthesis: (lc.toothProsthesis ?? []).map((tp) => ({
      detailClientId: lc.detail?.clientId ?? tp.treatmentDetailId ?? '',
      tooth: tp.tooth,
      prosthesisTypeCode: tp.prosthesisTypeCode,
      selectionGroupId: tp.selectionGroupId ?? '',
    })),
    attachmentIds: (lc.attachments ?? []).map((a) => a.id),
    sentAt: lc.sentAt ?? null,
    sends: lc.sends ?? [],
    dueDate: lc.dueDate ?? null,
    taskProgress: lc.taskProgress ?? null,
    shareUrl: lc.shareUrl ?? null,
  };
}

function serializeDetails(details: TreatmentDetailDraft[]) {
  return JSON.stringify(
    details.map((d) => ({
      clientId: d.clientId,
      id: d.id,
      treatmentType: d.treatmentType,
      teeth: d.teeth,
      toothSelectionGroups: d.toothSelectionGroups,
      comment: d.comment,
      attachmentMetas: d.attachmentMetas,
    })),
  );
}

function isDetailsDirty(
  details: TreatmentDetailDraft[],
  savedSnapshot: string | null,
): boolean {
  if (savedSnapshot === null) {
    return details.some((d) => !isEmptyDraftDetail(d)) || details.length > 1;
  }
  return serializeDetails(details) !== savedSnapshot;
}

/** Apply server ids/attachments onto local rows without replacing newer local edits. */
function mergeServerIdsIntoDetails(
  local: TreatmentDetailDraft[],
  fromServer: TreatmentDetailDraft[],
): TreatmentDetailDraft[] {
  const byClientId = new Map(fromServer.map((d) => [d.clientId, d]));
  return local.map((d) => {
    const s = byClientId.get(d.clientId);
    if (!s) return d;
    return {
      ...d,
      id: s.id ?? d.id,
      labCaseId: s.labCaseId ?? d.labCaseId,
      taskProgress: s.taskProgress ?? d.taskProgress,
      attachmentMetas:
        d.attachmentMetas.length > 0 ? d.attachmentMetas : s.attachmentMetas,
    };
  });
}

const PREVIEW_TREATMENT_ID = 'current-draft';

function isPreviewTreatment(treatment: PastTreatment): boolean {
  return treatment.id === PREVIEW_TREATMENT_ID;
}

function serializeLabCases(drafts: LabCaseDraft[]): string {
  return JSON.stringify(
    [...drafts]
      .sort((a, b) => a.clientId.localeCompare(b.clientId))
      .map((lc) => ({
        clientId: lc.clientId,
        id: lc.id ?? null,
        destinationOrganizationId: lc.destinationOrganizationId ?? null,
        detailClientId: lc.detailClientId,
        dueDate: lc.dueDate ?? null,
        attachmentIds: [...lc.attachmentIds].sort(),
        toothProsthesis: [...lc.toothProsthesis]
          .map((tp) => ({
            detailClientId: tp.detailClientId,
            tooth: tp.tooth,
            prosthesisTypeCode: tp.prosthesisTypeCode,
            selectionGroupId: tp.selectionGroupId ?? '',
          }))
          .sort(
            (a, b) =>
              a.tooth.localeCompare(b.tooth) ||
              a.prosthesisTypeCode.localeCompare(b.prosthesisTypeCode),
          ),
      })),
  );
}

function isLabCasesDirty(drafts: LabCaseDraft[], savedSnapshot: string | null): boolean {
  if (savedSnapshot === null) {
    return drafts.some(
      (lc) =>
        lc.toothProsthesis.length > 0 ||
        Boolean(lc.destinationOrganizationId) ||
        Boolean(lc.dueDate) ||
        lc.attachmentIds.length > 0,
    );
  }
  return serializeLabCases(drafts) !== savedSnapshot;
}

function mergeServerIdsIntoLabCases(
  local: LabCaseDraft[],
  fromServer: LabCaseDraft[],
): LabCaseDraft[] {
  const byClientId = new Map(fromServer.map((lc) => [lc.clientId, lc]));
  return local.map((lc) => {
    const s = byClientId.get(lc.clientId);
    if (!s) return lc;
    return { ...lc, id: s.id ?? lc.id, shareUrl: s.shareUrl ?? lc.shareUrl };
  });
}

function detailsToPreviewTreatment(
  details: TreatmentDetailDraft[],
  meta: { title: string; patientId: string; treatmentAt: string; id?: string },
): PastTreatment {
  return {
    id: meta.id ?? PREVIEW_TREATMENT_ID,
    patientId: meta.patientId,
    title: meta.title,
    treatmentAt: meta.treatmentAt,
    details: details.map((d, idx) => ({
      id: d.id ?? d.clientId ?? `draft-${idx + 1}`,
      clientId: d.clientId,
      treatmentType: d.treatmentType,
      teeth: d.teeth,
      toothSelectionGroups: d.toothSelectionGroups,
      notes: d.comment || null,
      attachmentMetas: d.attachmentMetas,
      labCaseId: d.labCaseId ?? null,
      taskProgress: d.taskProgress ?? null,
      destinationOrganizationId: d.sendToOrganizationIds[0] ?? null,
      sends: d.sends ?? [],
      sentAt: d.sentAt ?? null,
    })),
    labCases: [],
    documents: [],
  };
}

interface TreatmentWorkspaceProps {
  userId: string;
  currentOrganization: Organization | null;
  initialAppointmentId?: string | null;
  initialLabCaseId?: string | null;
}

function WholePlanToggle({
  pressed,
  label,
  onToggle,
}: {
  pressed: boolean;
  label: string;
  onToggle: () => void;
}) {
  return (
    <Button
      type="button"
      variant={pressed ? 'secondary' : 'outline'}
      size="sm"
      className="h-8"
      aria-pressed={pressed}
      onClick={onToggle}
    >
      {label}
    </Button>
  );
}

export function TreatmentWorkspace({
  userId,
  currentOrganization,
  initialAppointmentId = null,
  initialLabCaseId = null,
}: TreatmentWorkspaceProps) {
  const locale = useLocale();
  const t = useTranslations('treatment');
  const tErrors = useTranslations('errors');
  const tPatients = useTranslations('patients');
  const router = useRouter();
  const { user } = useAuth();
  const { showError, showSuccess, messages: toastMessages } = useToast();
  const canView = canViewTreatment(currentOrganization);
  const canEdit = canEditTreatment(currentOrganization);
  useMarkTabReadOnVisit();
  const tabBadgeCounts = useTabBadgeCounts();
  const initialLabCasesScopeSetRef = useRef(false);

  const [stripHidden, setStripHidden] = useState(false);
  const todayStart = useMemo(() => startOfLocalDay(new Date()), []);

  const [selectedDay, setSelectedDay] = useState(() => startOfLocalDay(new Date()));
  const [appointments, setAppointments] = useState<TreatmentAppointment[]>([]);
  const [standaloneTreatments, setStandaloneTreatments] = useState<PastTreatment[]>([]);
  const [apptsLoading, setApptsLoading] = useState(false);
  const [selectionLocked, setSelectionLocked] = useState(false);
  const [selectedAppointmentId, setSelectedAppointmentId] = useState<string | null>(null);
  const [selectedStandaloneId, setSelectedStandaloneId] = useState<string | null>(null);

  const [history, setHistory] = useState<PastTreatment[]>([]);
  const [historyLoading, setHistoryLoading] = useState(false);
  const [historyPatientId, setHistoryPatientId] = useState<string | null>(null);
  const [patientLabCases, setPatientLabCases] = useState<PatientLabCaseSummary[]>([]);
  const [patientLabCasesLoading, setPatientLabCasesLoading] = useState(false);
  const [unreadLabCases, setUnreadLabCases] = useState<PatientLabCaseSummary[]>([]);
  const [unreadLabCasesLoading, setUnreadLabCasesLoading] = useState(false);
  const [labCasesScope, setLabCasesScope] = useState<TreatmentLabCasesScope>('patient');
  const [selectedRailLabCaseId, setSelectedRailLabCaseId] = useState<string | null>(null);
  const [searchedPatient, setSearchedPatient] = useState<
    (Pick<Patient, 'id' | 'firstName' | 'lastName'> & {
      mobile?: string | null;
      email?: string | null;
    }) | null
  >(null);
  const [patientSearchBusy, setPatientSearchBusy] = useState(false);
  const [newTreatmentPickerOpen, setNewTreatmentPickerOpen] = useState(false);
  const [creatingStandalone, setCreatingStandalone] = useState(false);

  const {
    search: patientSearch,
    setSearch: setPatientSearch,
    patients: patientSearchResults,
    loading: patientSearchLoading,
  } = usePatientSearchQuery(canView);

  const [orgs, setOrgs] = useState<LinkedOrganizationOption[]>([]);
  const [labDependentCodes, setLabDependentCodes] = useState<Set<string>>(new Set());
  const [treatmentCatalog, setTreatmentCatalog] = useState<TreatmentCatalogEntry[]>([]);
  const [prosthesisCatalog, setProsthesisCatalog] = useState<ProsthesisCatalogEntry[]>([]);
  const treatmentDropdownCatalog = useMemo(
    () => treatmentCatalog.filter((entry) => entry.availableInTreatment),
    [treatmentCatalog],
  );

  const [details, setDetails] = useState<TreatmentDetailDraft[]>(() => [newDetail()]);
  const [labCaseDrafts, setLabCaseDrafts] = useState<LabCaseDraft[]>([]);
  const [activeDetailId, setActiveDetailId] = useState<string>(() => details[0].clientId);
  const [activeLabCaseId, setActiveLabCaseId] = useState<string | null>(null);
  const [savedSnapshot, setSavedSnapshot] = useState<string | null>(null);
  const [savedLabCasesSnapshot, setSavedLabCasesSnapshot] = useState<string | null>(null);
  const [saveStatus, setSaveStatus] = useState<'idle' | 'dirty' | 'saving' | 'saved' | 'error'>('idle');
  const [selectedPreviewId, setSelectedPreviewId] = useState<string | null>(null);
  const [workspaceMode, setWorkspaceMode] = useState<WorkspaceMode>('live');

  const selectionLockedRef = useRef(selectionLocked);
  selectionLockedRef.current = selectionLocked;

  const detailsRef = useRef(details);
  detailsRef.current = details;
  const savedSnapshotRef = useRef(savedSnapshot);
  savedSnapshotRef.current = savedSnapshot;
  const savedLabCasesSnapshotRef = useRef(savedLabCasesSnapshot);
  savedLabCasesSnapshotRef.current = savedLabCasesSnapshot;
  const autosaveTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
  const saveInFlightRef = useRef(false);
  const saveQueuedRef = useRef(false);
  const draftHydratingRef = useRef(false);
  const workspaceModeRef = useRef(workspaceMode);
  workspaceModeRef.current = workspaceMode;
  const labCaseDraftsRef = useRef(labCaseDrafts);
  labCaseDraftsRef.current = labCaseDrafts;
  const skipNextGetDraftRef = useRef(false);
  const pendingAppointmentIdRef = useRef<string | null>(initialAppointmentId);
  const pendingLabCaseIdRef = useRef<string | null>(initialLabCaseId);
  const labPanelRef = useRef<HTMLDivElement>(null);
  const [labWorkspaceView, setLabWorkspaceView] = useState<'chart' | 'dispatch'>('chart');
  const historyRequestRef = useRef(0);
  /** When set, switching the active detail scrolls to the lab dispatch panel. */
  const pendingScrollToLabRef = useRef(false);

  useEffect(() => {
    pendingAppointmentIdRef.current = initialAppointmentId;
    if (initialAppointmentId) {
      setSelectedDay(startOfLocalDay(new Date()));
      setSelectionLocked(false);
    }
  }, [initialAppointmentId]);

  useEffect(() => {
    pendingLabCaseIdRef.current = initialLabCaseId;
  }, [initialLabCaseId]);

  const [sendBusyId, setSendBusyId] = useState<string | null>(null);
  const [uploadBusyDetailId, setUploadBusyDetailId] = useState<string | null>(null);
  const [organizationSearch, setOrganizationSearch] = useState('');
  const [recentOrganizationIds, setRecentOrganizationIds] = useState<string[]>([]);
  const [showWholeTreatmentPlan, setShowWholeTreatmentPlan] = useState(false);


  const [voiceAvailability, setVoiceAvailability] = useState<VoiceAvailability | null>(null);
  const [voiceResult, setVoiceResult] = useState<VoiceExtractionResult | null>(null);


  const isDetailLocked = useCallback(
    (detail: TreatmentDetailDraft) =>
      labCaseDrafts.some((lc) => lc.sentAt && lc.detailClientId === detail.clientId),
    [labCaseDrafts],
  );

  const activeSentLabCaseId = useMemo(() => {
    const match = labCaseDrafts.find(
      (lc) => lc.detailClientId === activeDetailId && lc.sentAt && lc.id,
    );
    return match?.id ?? null;
  }, [labCaseDrafts, activeDetailId]);

  const isDirty = useMemo(
    () =>
      isDetailsDirty(details, savedSnapshot) ||
      isLabCasesDirty(labCaseDrafts, savedLabCasesSnapshot),
    [details, savedSnapshot, labCaseDrafts, savedLabCasesSnapshot],
  );

  const AUTOSAVE_DEBOUNCE_MS = 600;

  const selectedAppointment = useMemo(
    () => appointments.find((a) => a.id === selectedAppointmentId) ?? null,
    [appointments, selectedAppointmentId],
  );


  const voice = useVoiceCapture({
    // The locale the clinician is actually reading and speaking in. Sent explicitly so
    // the server's ASR hint, catalog labels and week start match what the microphone was
    // offered for — req.user.language can drift from the URL locale.
    locale,
    maxMs: voiceAvailability?.maxRecordingMs ?? null,
    onExtracted: setVoiceResult,
    onError: (error) => showError(getUserFacingError(error, tErrors, t('voiceFailed'))),
  });

  /** Absence is the unavailable state — the Add button then renders unsplit. */
  const voiceForEditor =
    voiceAvailability?.enabled && voiceAvailability.locales.includes(locale) ? voice : undefined;

  const selectedStandalone = useMemo(
    () => standaloneTreatments.find((t) => t.id === selectedStandaloneId) ?? null,
    [standaloneTreatments, selectedStandaloneId],
  );

  const liveTreatmentId = selectedStandalone?.id ?? null;
  const hasLiveContext = Boolean(selectedAppointment || selectedStandalone);

  const walkInLabel = t('walkIn');

  const activePatient = useMemo(() => {
    if (selectedAppointment) {
      return {
        id: selectedAppointment.patientId,
        firstName: selectedAppointment.patientFirstName,
        lastName: selectedAppointment.patientLastName,
        mobile: selectedAppointment.patientMobile ?? null,
        email: null,
        purpose: selectedAppointment.purpose,
        isWalkIn: false,
      };
    }
    if (selectedStandalone) {
      const isWalkIn = Boolean(selectedStandalone.patient?.isWalkIn);
      return {
        id: selectedStandalone.patientId,
        firstName: isWalkIn ? walkInLabel : (selectedStandalone.patient?.firstName ?? ''),
        lastName: isWalkIn ? '' : (selectedStandalone.patient?.lastName ?? ''),
        mobile: isWalkIn ? null : (selectedStandalone.patient?.mobile ?? null),
        email: isWalkIn ? null : (selectedStandalone.patient?.email ?? null),
        purpose: selectedStandalone.details[0]?.treatmentType,
        isWalkIn,
      };
    }
    if (searchedPatient) {
      return {
        id: searchedPatient.id,
        firstName: searchedPatient.firstName,
        lastName: searchedPatient.lastName,
        mobile: searchedPatient.mobile ?? null,
        email: searchedPatient.email ?? null,
        purpose: undefined,
        isWalkIn: false,
      };
    }
    return null;
  }, [selectedAppointment, selectedStandalone, searchedPatient, walkInLabel]);

  const activePatientId = activePatient?.id ?? null;
  const activePatientName = activePatient
    ? `${activePatient.firstName} ${activePatient.lastName}`.trim()
    : null;
  const namedActivePatient =
    activePatient && !activePatient.isWalkIn && activePatient.id
      ? {
          id: activePatient.id,
          displayName: activePatientName ?? '',
          mobile: activePatient.mobile ?? null,
          email: activePatient.email ?? null,
        }
      : null;
  const searchedWithoutLiveVisit = Boolean(searchedPatient) && !hasLiveContext;
  const showSearchedPatientLoading =
    searchedWithoutLiveVisit && (patientSearchBusy || historyLoading);
  const showNoTreatmentFound =
    searchedWithoutLiveVisit &&
    !patientSearchBusy &&
    !historyLoading &&
    history.length === 0;

  const unreadUpdatesCount = unreadLabCases.length;
  const otherPatientsUnreadCount = useMemo(
    () => unreadLabCases.filter((item) => item.patientId !== activePatientId).length,
    [unreadLabCases, activePatientId],
  );
  const displayedLabCases = labCasesScope === 'updates' ? unreadLabCases : patientLabCases;
  const labCasesListLoading =
    labCasesScope === 'updates'
      ? unreadLabCasesLoading && unreadLabCases.length === 0
      : patientLabCasesLoading && patientLabCases.length === 0;
  const showLabShipmentsSection = Boolean(activePatient) || unreadUpdatesCount > 0;
  const labShipmentsSubtitle =
    labCasesScope === 'updates'
      ? t('labShipmentsUpdatesScope')
      : activePatientName
        ? t('labShipmentsPatientScope', { patientName: activePatientName })
        : t('labShipmentsSubtitle');

  useEffect(() => {
    if (selectedStandalone && searchedPatient?.id === selectedStandalone.patientId) {
      setSearchedPatient(null);
    }
  }, [selectedAppointment, selectedStandalone, searchedPatient?.id]);

  const isViewingPastDay = useMemo(
    () => compareLocalDayStart(selectedDay, todayStart) < 0,
    [selectedDay, todayStart],
  );

  const canEditTreatmentForDay =
    canEdit &&
    hasLiveContext &&
    !isViewingPastDay &&
    workspaceMode === 'live';

  const historyPanelItems = history;

  const activeDetail = useMemo(
    () => details.find((d) => d.clientId === activeDetailId) ?? details[0] ?? null,
    [details, activeDetailId],
  );

  const showLabDispatch = useMemo(
    () => Boolean(activeDetail && labDependentCodes.has(activeDetail.treatmentType)),
    [activeDetail, labDependentCodes],
  );

  useEffect(() => {
    if (labDependentCodes.size === 0) return;
    setDetails((prev) => {
      const next = pruneLabDependentDetailsToJobs(
        prev,
        labCaseDraftsRef.current,
        labDependentCodes,
      );
      if (serializeDetails(next) === serializeDetails(prev)) return prev;
      detailsRef.current = next;
      return next;
    });
  }, [labDependentCodes]);

  const activeTypeSelected = Boolean(activeDetail && isDetailTypeSelected(activeDetail));
  const activeLocked = Boolean(activeDetail && isDetailLocked(activeDetail));
  const activeHasArchJobs = hasArchJobs(
    labCaseDraftForDetail(labCaseDrafts, activeDetailId)?.toothProsthesis ?? [],
    activeDetailId,
  );

  useEffect(() => {
    if (!selectedStandaloneId || draftHydratingRef.current) return;
    const nextDetails = details.map(draftToPastDetail);
    setStandaloneTreatments((prev) => {
      const current = prev.find((row) => row.id === selectedStandaloneId);
      if (!current) return prev;
      const prevColor = unscheduledStripColorCode(current.details);
      const nextColor = unscheduledStripColorCode(nextDetails);
      if (
        prevColor === nextColor &&
        areUnscheduledDetailsStripDeletable(current.details) ===
          areUnscheduledDetailsStripDeletable(nextDetails)
      ) {
        return prev;
      }
      return prev.map((row) =>
        row.id === selectedStandaloneId ? { ...row, details: nextDetails } : row,
      );
    });
  }, [selectedStandaloneId, details]);

  const dayStripItems = useMemo<DayStripItem[]>(() => {
    const timed: DayStripItem[] = appointments.map((a) => ({
      kind: 'appointment',
      id: a.id,
      patientId: a.patientId,
      patientFirstName: a.patientFirstName,
      patientLastName: a.patientLastName,
      patientIsWalkIn: false,
      colorCode: a.purpose,
      timeLabel: formatAppTimeRange(a.startAt, a.endAt, locale),
      subtitle: treatmentTypeLabelFromCatalog(a.purpose, treatmentCatalog),
    }));
    const unscheduled: DayStripItem[] = standaloneTreatments.map((tr) => {
      const isWalkIn = Boolean(tr.patient?.isWalkIn);
      const sourceDetails = tr.id === selectedStandaloneId && !draftHydratingRef.current
        ? details
        : tr.details;
      const colorCode = unscheduledStripColorCode(sourceDetails);
      return {
        kind: 'unscheduled' as const,
        id: tr.id,
        patientId: tr.patientId,
        patientFirstName: isWalkIn ? t('walkIn') : (tr.patient?.firstName ?? ''),
        patientLastName: isWalkIn ? '' : (tr.patient?.lastName ?? ''),
        patientIsWalkIn: isWalkIn,
        colorCode,
        timeLabel: null,
        subtitle: t('noAppointment'),
        canDelete: areUnscheduledDetailsStripDeletable(sourceDetails),
      };
    });
    return [...timed, ...unscheduled];
  }, [
    appointments,
    standaloneTreatments,
    selectedStandaloneId,
    details,
    locale,
    treatmentCatalog,
    t,
  ]);

  const selectedStripItemId = selectedAppointmentId ?? selectedStandaloneId;

  const currentDraftPreview = useMemo<PastTreatment | null>(() => {
    if (selectedAppointment) {
      return buildWorkspaceSnapshot(
        {
          id: selectedAppointment.id,
          patientId: selectedAppointment.patientId,
          treatmentAt: selectedAppointment.startAt,
          appointmentId: selectedAppointment.id,
        },
        details,
        labCaseDrafts,
        t('treatmentPlanTitle', {
          patientName: `${selectedAppointment.patientFirstName} ${selectedAppointment.patientLastName}`,
        }),
        'current-draft',
      );
    }
    if (selectedStandalone) {
      const name = selectedStandalone.patient?.isWalkIn
        ? t('walkIn')
        : `${selectedStandalone.patient?.firstName ?? ''} ${selectedStandalone.patient?.lastName ?? ''}`.trim();
      return buildWorkspaceSnapshot(
        {
          id: selectedStandalone.id,
          patientId: selectedStandalone.patientId,
          treatmentAt: selectedStandalone.treatmentAt,
          appointmentId: null,
        },
        details,
        labCaseDrafts,
        t('treatmentPlanTitle', { patientName: name || t('walkIn') }),
        selectedStandalone.id,
      );
    }
    return null;
  }, [details, labCaseDrafts, selectedAppointment, selectedStandalone, t]);

  const previewTreatment = useMemo(() => {
    if (!selectedPreviewId) return currentDraftPreview;
    const fromHistory =
      history.find((item) => item.id === selectedPreviewId) ??
      historyPanelItems.find((item) => item.id === selectedPreviewId);
    if (
      workspaceMode === 'live' &&
      currentDraftPreview?.appointmentId &&
      (selectedPreviewId === currentDraftPreview.id ||
        fromHistory?.appointmentId === currentDraftPreview.appointmentId)
    ) {
      return currentDraftPreview;
    }
    return fromHistory ?? currentDraftPreview;
  }, [selectedPreviewId, history, historyPanelItems, currentDraftPreview, workspaceMode]);

  const isBrowsing = selectedPreviewId !== null;

  const labAttentionItems = useMemo(
    () =>
      collectLabDispatchAttention(
        labDependentCodes,
        currentDraftPreview,
        history,
        selectedAppointmentId,
      ),
    [labDependentCodes, currentDraftPreview, history, selectedAppointmentId],
  );

  const hydrateFromTreatment = useCallback((
    treatment: PastTreatment,
    options?: { seedBlankIfEmpty?: boolean },
  ) => {
    const mappedLabCases = withoutEmptyLabCaseDrafts(
      (treatment.labCases ?? []).map(mapLabCaseDraftFromApi),
    );
    const mapped = pruneLabDependentDetailsToJobs(
      treatment.details.map(mapDetailFromApi),
      mappedLabCases,
      labDependentCodes,
    );
    const nextDetails =
      mapped.length > 0
        ? mapped
        : options?.seedBlankIfEmpty
          ? [newDetail()]
          : [];
    setDetails(nextDetails);
    setActiveDetailId((prev) => {
      const stillExists = nextDetails.some((d) => d.clientId === prev);
      return stillExists ? prev : (nextDetails[0]?.clientId ?? '');
    });
    setSavedSnapshot(serializeDetails(nextDetails));
    const labSnap = serializeLabCases(mappedLabCases);
    labCaseDraftsRef.current = mappedLabCases;
    savedLabCasesSnapshotRef.current = labSnap;
    setLabCaseDrafts(mappedLabCases);
    setSavedLabCasesSnapshot(labSnap);
    setActiveLabCaseId(mappedLabCases[0]?.clientId ?? null);
    setOrganizationSearch('');
    setSaveStatus('idle');
  }, [labDependentCodes]);

  const selectedTeethSet = useMemo(() => new Set(activeDetail?.teeth ?? []), [activeDetail?.teeth]);
  const connectedSelectedTeeth = useMemo(
    () => connectedTeethSet(activeDetail?.toothSelectionGroups ?? []),
    [activeDetail?.toothSelectionGroups],
  );
  const linkedToothEdges = useMemo(
    () => linkedEdgesFromGroups(activeDetail?.toothSelectionGroups ?? []),
    [activeDetail?.toothSelectionGroups],
  );
  const rangeAnchorRef = useRef<FdiToothId | null>(null);

  const wholePlanTeethSet = useMemo(() => {
    const set = new Set<FdiToothId>();
    for (const detail of details) {
      for (const tooth of detail.teeth) set.add(tooth);
    }
    return set;
  }, [details]);

  const wholePlanToothColors = useMemo(() => {
    const colors: Partial<Record<FdiToothId, string>> = {};
    for (let i = 0; i < details.length; i++) {
      const detail = details[i];
      const catalogIndex = treatmentCatalog.findIndex((e) => e.code === detail.treatmentType);
      const color = treatmentTypeColor(detail.treatmentType, catalogIndex >= 0 ? catalogIndex : i);
      for (const tooth of detail.teeth) {
        if (!(tooth in colors)) colors[tooth] = color;
      }
    }
    return colors;
  }, [details, treatmentCatalog]);

  const wholePlanLinkedEdges = useMemo(() => {
    const edges = new Set<string>();
    for (const detail of details) {
      for (const key of linkedEdgesFromGroups(detail.toothSelectionGroups ?? [])) {
        edges.add(key);
      }
    }
    return edges;
  }, [details]);

  const chartSelectedTeeth = showWholeTreatmentPlan ? wholePlanTeethSet : selectedTeethSet;
  const chartToothColors = showWholeTreatmentPlan ? wholePlanToothColors : undefined;
  const chartLinkedEdges = showWholeTreatmentPlan ? wholePlanLinkedEdges : linkedToothEdges;
  const prosthesisAssignActive =
    !showWholeTreatmentPlan &&
    Boolean(activeDetail && labDependentCodes.has(activeDetail.treatmentType)) &&
    prosthesisCatalog.length > 0;

  // Reset whole-plan overview when switching details.
  useEffect(() => {
    setShowWholeTreatmentPlan(false);
    rangeAnchorRef.current = null;
    setOrganizationSearch('');
    if (pendingScrollToLabRef.current) {
      pendingScrollToLabRef.current = false;
      setLabWorkspaceView('dispatch');
      requestAnimationFrame(() => {
        scrollWithinMainScrollContainer(labPanelRef.current);
      });
    } else {
      setLabWorkspaceView('chart');
    }
  }, [activeDetailId]);

  useEffect(() => {
    if (!showLabDispatch) setLabWorkspaceView('chart');
  }, [showLabDispatch]);

  // Sync active lab shipment when the selected treatment detail changes.
  useEffect(() => {
    const match = labCaseDraftForDetail(labCaseDrafts, activeDetailId);
    setActiveLabCaseId(match?.clientId ?? null);
  }, [activeDetailId, labCaseDrafts]);

  useEffect(() => {
    let cancelled = false;
    setApptsLoading(true);
    void (async () => {
      try {
        const dayStart = startOfLocalDay(selectedDay);
        const dayEnd = addCalendarDays(dayStart, 1);
        const [apptsResponse, standaloneResponse] = await Promise.all([
          appointmentsApi.list({
            from: dayStart.toISOString(),
            to: dayEnd.toISOString(),
          }),
          treatmentsApi.listDayStandalone({
            from: dayStart.toISOString(),
            to: dayEnd.toISOString(),
          }),
        ]);
        if (cancelled) return;
        const list = apptsResponse.data
          .filter((a) => a.providerUserId === userId)
          .map(mapAppointment);
        setAppointments(list);
        setStandaloneTreatments(standaloneResponse.data);
        if (!selectionLockedRef.current) {
          const pendingId = pendingAppointmentIdRef.current;
          if (pendingId && list.some((appointment) => appointment.id === pendingId)) {
            setSelectedAppointmentId(pendingId);
            setSelectedStandaloneId(null);
            setSelectionLocked(true);
            pendingAppointmentIdRef.current = null;
            router.replace('/treatment', { scroll: false });
          } else {
            pendingAppointmentIdRef.current = null;
            const autoAppt = pickAutoAppointment(list, selectedDay);
            if (autoAppt) {
              setSelectedAppointmentId(autoAppt);
              setSelectedStandaloneId(null);
            } else if (standaloneResponse.data[0]) {
              setSelectedAppointmentId(null);
              setSelectedStandaloneId(standaloneResponse.data[0].id);
            } else {
              setSelectedAppointmentId(null);
              setSelectedStandaloneId(null);
            }
          }
        }
      } catch (error: unknown) {
        if (!cancelled) {
          showError(getUserFacingError(error, tErrors, t('errorLoadAppointments')));
        }
      } finally {
        if (!cancelled) setApptsLoading(false);
      }
    })();
    return () => {
      cancelled = true;
    };
  }, [userId, selectedDay, showError, t, router]);

  useEffect(() => {
    const today = startOfLocalDay(new Date());
    if (!isSameLocalCalendarDay(selectedDay, today) || selectionLocked) return;

    const id = window.setInterval(() => {
      setSelectedAppointmentId((prev) => {
        const next = pickAutoAppointment(appointments, selectedDay);
        return next ?? prev;
      });
    }, 60_000);

    return () => window.clearInterval(id);
  }, [selectedDay, appointments, selectionLocked]);

  useEffect(() => {
    let cancelled = false;
    void (async () => {
      try {
        const [orgsResponse, catalogResponse, prosthesisResponse, voiceResponse] =
          await Promise.all([
            treatmentsApi.listLinkedOrganizations(),
            treatmentCatalogApi.list(),
            prosthesisCatalogApi.list(),
            // Voice availability comes from the API, not a NEXT_PUBLIC_* var: those are
            // baked in at build time, so enabling a locale would need a frontend rebuild.
            // A failure here must not take the whole treatment tab down with it.
            voiceApi.availability().catch(() => null),
          ]);
        if (cancelled) return;
        setVoiceAvailability(voiceResponse?.data ?? null);
        setOrgs(orgsResponse.data);
        setTreatmentCatalog(catalogResponse.data);
        setProsthesisCatalog(prosthesisResponse.data);
        setLabDependentCodes(
          new Set(catalogResponse.data.filter((entry) => entry.labDependent).map((entry) => entry.code)),
        );
        const recentIds = loadRecentLabIds(currentOrganization?.id).filter((id) =>
          orgsResponse.data.some((o) => o.id === id && o.active),
        );
        if (recentIds.length > 0) {
          setRecentOrganizationIds(recentIds);
        }
      } catch (error: unknown) {
        if (!cancelled) {
          showError(getUserFacingError(error, tErrors, t('errorLoadOrgs')));
        }
      }
    })();
    return () => {
      cancelled = true;
    };
  }, [showError, t, currentOrganization?.id]);

  useEffect(() => {
    if (!activePatientId) {
      setHistoryPatientId(null);
      setHistory([]);
      setHistoryLoading(false);
      setPatientLabCases([]);
      setPatientLabCasesLoading(false);
      setSelectedRailLabCaseId(null);
      return;
    }
    setHistoryPatientId((prev) => {
      if (prev !== activePatientId) {
        setHistory([]);
        setHistoryLoading(true);
      }
      return activePatientId;
    });
  }, [activePatientId]);

  const refreshPatientLabCases = useCallback(
    async (patientId: string, options?: { silent?: boolean }) => {
      const silent = options?.silent ?? false;
      if (!silent) setPatientLabCasesLoading(true);
      try {
        const response = await treatmentsApi.listPatientLabCases(patientId);
        setPatientLabCases(response.data ?? []);
      } catch {
        if (!silent) setPatientLabCases([]);
      } finally {
        if (!silent) setPatientLabCasesLoading(false);
      }
    },
    [],
  );

  const refreshUnreadLabCases = useCallback(async (options?: { silent?: boolean }) => {
    const silent = options?.silent ?? false;
    if (!silent) setUnreadLabCasesLoading(true);
    try {
      const response = await treatmentsApi.listUnreadLabCases();
      setUnreadLabCases(response.data ?? []);
    } catch {
      if (!silent) setUnreadLabCases([]);
    } finally {
      if (!silent) setUnreadLabCasesLoading(false);
    }
  }, []);

  const handleLabCaseMarkedRead = useCallback((labCaseId: string) => {
    setPatientLabCases((prev) =>
      prev.map((item) => (item.labCaseId === labCaseId ? { ...item, hasUnread: false } : item)),
    );
    setUnreadLabCases((prev) => prev.filter((item) => item.labCaseId !== labCaseId));
  }, []);

  const activeLabCaseSummary = useMemo(() => {
    if (activeSentLabCaseId) {
      return patientLabCases.find((item) => item.labCaseId === activeSentLabCaseId) ?? null;
    }
    return patientLabCases.find((item) => item.detailClientId === activeDetailId) ?? null;
  }, [patientLabCases, activeSentLabCaseId, activeDetailId]);

  const handleLabCaseSummaryChange = useCallback((summary: PatientLabCaseSummary) => {
    setPatientLabCases((prev) =>
      prev.map((item) => (item.labCaseId === summary.labCaseId ? summary : item)),
    );
  }, []);

  useEffect(() => {
    void refreshUnreadLabCases();
  }, [refreshUnreadLabCases]);

  useEffect(() => {
    if (initialLabCasesScopeSetRef.current) return;
    if ((tabBadgeCounts.treatment ?? 0) > 0) {
      setLabCasesScope('updates');
      initialLabCasesScopeSetRef.current = true;
      return;
    }
    if (activePatientId) {
      setLabCasesScope('patient');
      initialLabCasesScopeSetRef.current = true;
    }
  }, [tabBadgeCounts.treatment, activePatientId]);

  useEffect(() => {
    if (unreadLabCases.length === 0 && labCasesScope === 'updates' && activePatientId) {
      setLabCasesScope('patient');
    }
    if (unreadLabCases.length > 0 && !activePatientId && labCasesScope === 'patient') {
      setLabCasesScope('updates');
    }
  }, [unreadLabCases.length, labCasesScope, activePatientId]);

  useEffect(() => {
    if (!historyPatientId) return;
    const requestId = ++historyRequestRef.current;
    setHistoryLoading(true);
    void (async () => {
      try {
        const response = await treatmentsApi.listPatientHistory(historyPatientId, 50);
        if (requestId !== historyRequestRef.current) return;
        setHistory(response.data);
        void refreshPatientLabCases(historyPatientId);
      } catch (error: unknown) {
        if (requestId !== historyRequestRef.current) return;
        showError(getUserFacingError(error, tErrors, t('errorLoadHistory')));
      } finally {
        if (requestId === historyRequestRef.current) {
          setHistoryLoading(false);
        }
      }
    })();
  }, [historyPatientId, refreshPatientLabCases, showError, t, tErrors]);

  useEffect(() => {
    const onBadgesChanged = () => {
      if (historyPatientId) void refreshPatientLabCases(historyPatientId, { silent: true });
      void refreshUnreadLabCases({ silent: true });
    };
    window.addEventListener(tabBadgesChangedEventName(), onBadgesChanged);
    return () => window.removeEventListener(tabBadgesChangedEventName(), onBadgesChanged);
  }, [historyPatientId, refreshPatientLabCases, refreshUnreadLabCases]);

  useEffect(() => {
    const appointmentId = selectedAppointment?.id;
    const treatmentId = selectedStandalone?.id;
    if ((!appointmentId && !treatmentId) || workspaceMode !== 'live') return;

    if (skipNextGetDraftRef.current) {
      skipNextGetDraftRef.current = false;
      return;
    }

    let cancelled = false;
    draftHydratingRef.current = true;
    if (autosaveTimerRef.current) {
      clearTimeout(autosaveTimerRef.current);
      autosaveTimerRef.current = null;
    }

    void (async () => {
      try {
        const response = appointmentId
          ? await treatmentsApi.getDraft(appointmentId)
          : await treatmentsApi.getDraftByTreatment(treatmentId!);
        if (cancelled) return;

        const mappedLabCases = withoutEmptyLabCaseDrafts(
          (response.data?.labCases ?? []).map(mapLabCaseDraftFromApi),
        );

        if (response.data?.details?.length) {
          const mapped = pruneLabDependentDetailsToJobs(
            response.data.details.map(mapDetailFromApi),
            mappedLabCases,
            labDependentCodes,
          );
          setDetails(mapped);
          setActiveDetailId((prev) => {
            const stillExists = mapped.some((d) => d.clientId === prev);
            return stillExists ? prev : mapped[0].clientId;
          });
          setSavedSnapshot(serializeDetails(mapped));
        } else if (response.data) {
          setDetails([]);
          setActiveDetailId('');
          setSavedSnapshot(serializeDetails([]));
        } else {
          const first = newDetail(
            defaultTreatmentTypeForAppointment(selectedAppointment?.purpose, treatmentCatalog),
          );
          setDetails([first]);
          setActiveDetailId(first.clientId);
          setSavedSnapshot(serializeDetails([first]));
        }

        const labSnap = serializeLabCases(mappedLabCases);
        labCaseDraftsRef.current = mappedLabCases;
        savedLabCasesSnapshotRef.current = labSnap;
        setLabCaseDrafts(mappedLabCases);
        setSavedLabCasesSnapshot(labSnap);
        setActiveLabCaseId(mappedLabCases[0]?.clientId ?? null);
        setOrganizationSearch('');
        setSaveStatus('idle');
      } catch (error: unknown) {
        if (!cancelled) {
          showError(getUserFacingError(error, tErrors, t('errorLoadDraft')));
        }
      } finally {
        if (!cancelled) {
          draftHydratingRef.current = false;
        }
      }
    })();
    return () => {
      cancelled = true;
      draftHydratingRef.current = false;
    };
  }, [
    selectedAppointment?.id,
    selectedAppointment?.purpose,
    selectedStandalone?.id,
    workspaceMode,
    treatmentCatalog,
    labDependentCodes,
    showError,
    t,
    tErrors,
  ]);

  const persistDraft = useCallback(
    async (options?: { force?: boolean }) => {
      if (!selectedAppointment && !selectedStandalone) throw new Error('No visit selected');

      const patientName = selectedAppointment
        ? `${selectedAppointment.patientFirstName} ${selectedAppointment.patientLastName}`
        : selectedStandalone?.patient?.isWalkIn
          ? t('walkIn')
          : `${selectedStandalone?.patient?.firstName ?? ''} ${selectedStandalone?.patient?.lastName ?? ''}`.trim();
      const patientId = selectedAppointment?.patientId ?? selectedStandalone!.patientId;
      const treatmentAt = selectedAppointment?.startAt ?? selectedStandalone!.treatmentAt;

      const currentDetails = pruneLabDependentDetailsToJobs(
        detailsRef.current,
        labCaseDraftsRef.current,
        labDependentCodes,
      );
      if (serializeDetails(currentDetails) !== serializeDetails(detailsRef.current)) {
        detailsRef.current = currentDetails;
        setDetails(currentDetails);
      }
      const dirty = isDetailsDirty(currentDetails, savedSnapshotRef.current);

      if (!options?.force && !dirty) {
        return detailsToPreviewTreatment(currentDetails, {
          title: t('treatmentPlanTitle', { patientName }),
          patientId,
          treatmentAt,
        });
      }

      if (!areDetailsPersistable(currentDetails)) {
        return detailsToPreviewTreatment(currentDetails, {
          title: t('treatmentPlanTitle', { patientName }),
          patientId,
          treatmentAt,
        });
      }

      const payload = {
        details: currentDetails.map(
          ({ clientId, id, treatmentType, teeth, toothSelectionGroups, comment, attachmentMetas }) => ({
            clientId,
            id,
            treatmentType,
            teeth,
            toothSelectionGroups,
            comment,
            attachmentIds: attachmentMetas.map((a) => a.id),
          }),
        ),
      };
      const response = selectedAppointment
        ? await treatmentsApi.saveDraft(selectedAppointment.id, payload)
        : await treatmentsApi.saveDraftByTreatment(selectedStandalone!.id, payload);
      const mapped = response.data.details.map(mapDetailFromApi);
      const sentSnapshot = serializeDetails(currentDetails);
      const localNow = detailsRef.current;

      // If the user changed details while this save was in flight (e.g. removed a
      // detail), do not clobber local state with the stale response.
      if (serializeDetails(localNow) === sentSnapshot) {
        detailsRef.current = mapped;
        setDetails(mapped);
        setActiveDetailId((prev) => {
          const stillExists = mapped.some((d) => d.clientId === prev);
          return stillExists ? prev : (mapped[0]?.clientId ?? '');
        });
        const snap = serializeDetails(mapped);
        savedSnapshotRef.current = snap;
        setSavedSnapshot(snap);
      } else {
        const merged = mergeServerIdsIntoDetails(localNow, mapped);
        detailsRef.current = merged;
        setDetails(merged);
        setActiveDetailId((prev) => {
          const stillExists = merged.some((d) => d.clientId === prev);
          return stillExists ? prev : (merged[0]?.clientId ?? '');
        });
        // Keep dirty so the queued autosave persists the newer local state.
      }
      return response.data;
    },
    [labDependentCodes, selectedAppointment, selectedStandalone, t],
  );

  const persistLabCases = useCallback(
    async (savedTreatment: PastTreatment, draftsOverride?: LabCaseDraft[]) => {
      if (!selectedAppointment && !selectedStandalone) throw new Error('No visit selected');
      if (isPreviewTreatment(savedTreatment)) {
        return savedTreatment;
      }

      const drafts = draftsOverride ?? labCaseDraftsRef.current;
      const detailIdByClientId = new Map(
        savedTreatment.details.map((d) => [d.clientId, d.id]),
      );

      const payload = drafts
        .map((lc) => {
          if (!lc.detailClientId) return null;
          const treatmentDetailId = detailIdByClientId.get(lc.detailClientId);
          if (!treatmentDetailId) return null;

          return {
            clientId: lc.clientId,
            id: lc.id,
            destinationOrganizationId: lc.destinationOrganizationId ?? undefined,
            treatmentDetailId,
            toothProsthesis: lc.toothProsthesis
              .map((tp) => {
                const detailId = detailIdByClientId.get(tp.detailClientId);
                if (!detailId) return null;
                return {
                  treatmentDetailId: detailId,
                  tooth: tp.tooth,
                  prosthesisTypeCode: tp.prosthesisTypeCode,
                  selectionGroupId: tp.selectionGroupId ?? '',
                };
              })
              .filter(
                (
                  row,
                ): row is {
                  treatmentDetailId: string;
                  tooth: string;
                  prosthesisTypeCode: string;
                  selectionGroupId: string;
                } => row !== null,
              ),
            attachmentIds: lc.attachmentIds,
            dueDate: lc.dueDate ?? null,
          };
        })
        .filter((row): row is NonNullable<typeof row> => row !== null);

      const localJobCount = drafts.reduce((n, lc) => n + lc.toothProsthesis.length, 0);
      const payloadJobCount = payload.reduce((n, lc) => n + lc.toothProsthesis.length, 0);
      if (payloadJobCount < localJobCount) {
        throw new Error('Lab case jobs could not be mapped to saved details');
      }

      const applySavedDrafts = (mapped: LabCaseDraft[]) => {
        const sent = serializeLabCases(drafts);
        const localNow = labCaseDraftsRef.current;
        if (serializeLabCases(localNow) === sent) {
          const snap = serializeLabCases(mapped);
          labCaseDraftsRef.current = mapped;
          savedLabCasesSnapshotRef.current = snap;
          setLabCaseDrafts(mapped);
          setSavedLabCasesSnapshot(snap);
          setActiveLabCaseId((prev) => {
            if (prev && mapped.some((lc) => lc.clientId === prev)) return prev;
            return mapped[0]?.clientId ?? null;
          });
          return;
        }
        const merged = mergeServerIdsIntoLabCases(localNow, mapped);
        labCaseDraftsRef.current = merged;
        setLabCaseDrafts(merged);
      };

      const emptySnap = serializeLabCases([]);
      if (payload.length === 0) {
        if (drafts.length > 0) {
          throw new Error('Lab case drafts could not be mapped to saved details');
        }
        if (
          !savedLabCasesSnapshotRef.current ||
          savedLabCasesSnapshotRef.current === emptySnap
        ) {
          savedLabCasesSnapshotRef.current = emptySnap;
          setSavedLabCasesSnapshot(emptySnap);
          return savedTreatment;
        }
      }

      const response = selectedAppointment
        ? await treatmentsApi.saveLabCases(selectedAppointment.id, {
            labCases: payload,
          })
        : await treatmentsApi.saveLabCasesByTreatment(selectedStandalone!.id, {
            labCases: payload,
          });
      const mapped = withoutEmptyLabCaseDrafts(response.data.labCases.map(mapLabCaseDraftFromApi));
      applySavedDrafts(mapped);
      return response.data;
    },
    [selectedAppointment, selectedStandalone],
  );

  const refreshHistory = useCallback(async (patientId: string, options?: { silentLabCases?: boolean }) => {
    const requestId = ++historyRequestRef.current;
    try {
      const response = await treatmentsApi.listPatientHistory(patientId, 50);
      if (requestId !== historyRequestRef.current) return;
      setHistory(response.data);
      void refreshPatientLabCases(patientId, { silent: options?.silentLabCases ?? false });
    } catch (error: unknown) {
      if (requestId !== historyRequestRef.current) return;
      showError(getUserFacingError(error, tErrors, t('errorLoadHistory')));
    }
  }, [refreshPatientLabCases, showError, t, tErrors]);

  const runDraftSave = useCallback(async () => {
    if (!hasLiveContext || saveInFlightRef.current) {
      if (saveInFlightRef.current) saveQueuedRef.current = true;
      return;
    }

    const detailsDirty = isDetailsDirty(detailsRef.current, savedSnapshotRef.current);
    const labDirty = isLabCasesDirty(
      labCaseDraftsRef.current,
      savedLabCasesSnapshotRef.current,
    );
    if (!detailsDirty && !labDirty) {
      return;
    }
    if (!areDetailsPersistable(detailsRef.current)) {
      return;
    }

    saveInFlightRef.current = true;
    setSaveStatus('saving');
    const draftsAtSave = labCaseDraftsRef.current;
    try {
      const saved = await persistDraft({ force: labDirty && !detailsDirty });
      if (isPreviewTreatment(saved)) {
        setSaveStatus('dirty');
        return;
      }
      await persistLabCases(saved, draftsAtSave);
      setSaveStatus('saved');
      if (historyPatientId) {
        await refreshHistory(historyPatientId);
      }
    } catch (error: unknown) {
      setSaveStatus('error');
      showError(getUserFacingError(error, tErrors, t('errorSaveDraft')));
      throw error;
    } finally {
      saveInFlightRef.current = false;
      if (saveQueuedRef.current) {
        saveQueuedRef.current = false;
        if (
          isDetailsDirty(detailsRef.current, savedSnapshotRef.current) ||
          isLabCasesDirty(labCaseDraftsRef.current, savedLabCasesSnapshotRef.current)
        ) {
          void runDraftSave();
        }
      }
    }
  }, [hasLiveContext, persistDraft, persistLabCases, showError, t, historyPatientId, refreshHistory]);

  const flushDraftSave = useCallback(async (): Promise<boolean> => {
    if (autosaveTimerRef.current) {
      clearTimeout(autosaveTimerRef.current);
      autosaveTimerRef.current = null;
    }

    if (workspaceModeRef.current !== 'live' || !hasLiveContext || !canEditTreatmentForDay) {
      return true;
    }

    while (saveInFlightRef.current) {
      await new Promise((resolve) => setTimeout(resolve, 50));
    }

    if (
      !isDetailsDirty(detailsRef.current, savedSnapshotRef.current) &&
      !isLabCasesDirty(labCaseDraftsRef.current, savedLabCasesSnapshotRef.current)
    ) {
      return true;
    }

    try {
      await runDraftSave();
      return true;
    } catch {
      return window.confirm(t('confirmDiscard'));
    }
  }, [hasLiveContext, canEditTreatmentForDay, runDraftSave, t]);

  useEffect(() => {
    if (draftHydratingRef.current || !canEditTreatmentForDay || !hasLiveContext) {
      return;
    }

    if (!isDirty) {
      return;
    }

    setSaveStatus('dirty');

    if (autosaveTimerRef.current) clearTimeout(autosaveTimerRef.current);
    autosaveTimerRef.current = setTimeout(() => {
      autosaveTimerRef.current = null;
      void runDraftSave();
    }, AUTOSAVE_DEBOUNCE_MS);

    return () => {
      if (autosaveTimerRef.current) {
        clearTimeout(autosaveTimerRef.current);
        autosaveTimerRef.current = null;
      }
    };
  }, [details, isDirty, canEditTreatmentForDay, hasLiveContext, runDraftSave]);

  const resetToLiveContext = useCallback(() => {
    setWorkspaceMode('live');
    setSelectedPreviewId(null);
  }, []);

  const onPickAppointment = useCallback(
    (id: string) => {
      void (async () => {
        const ok = await flushDraftSave();
        if (!ok) return;
        draftHydratingRef.current = true;
        resetToLiveContext();
        setSearchedPatient(null);
        setSelectionLocked(true);
        setSelectedAppointmentId(id);
        setSelectedStandaloneId(null);
      })();
    },
    [flushDraftSave, resetToLiveContext],
  );

  const onPickStripItem = useCallback(
    (item: DayStripItem) => {
      void (async () => {
        const ok = await flushDraftSave();
        if (!ok) return;
        draftHydratingRef.current = true;
        resetToLiveContext();
        setSearchedPatient(null);
        setSelectionLocked(true);
        if (item.kind === 'appointment') {
          setSelectedAppointmentId(item.id);
          setSelectedStandaloneId(null);
        } else {
          setSelectedAppointmentId(null);
          setSelectedStandaloneId(item.id);
        }
      })();
    },
    [flushDraftSave, resetToLiveContext],
  );

  const createStandaloneTreatment = useCallback(
    async (opts: { patientId?: string; walkIn?: boolean }) => {
      if (creatingStandalone) return;
      const ok = await flushDraftSave();
      if (!ok) return;
      setCreatingStandalone(true);
      try {
        const created = await treatmentsApi.createStandalone({
          ...opts,
          treatmentAt: selectedDay.toISOString(),
        });
        resetToLiveContext();
        setSearchedPatient(null);
        setNewTreatmentPickerOpen(false);
        setSelectionLocked(true);
        setSelectedAppointmentId(null);
        setSelectedStandaloneId(created.data.id);
        setStandaloneTreatments((prev) =>
          prev.some((row) => row.id === created.data.id) ? prev : [...prev, created.data],
        );
        skipNextGetDraftRef.current = true;
        draftHydratingRef.current = true;
        hydrateFromTreatment(created.data, { seedBlankIfEmpty: true });
        draftHydratingRef.current = false;
        if (created.data.patientId && !created.data.patient?.isWalkIn) {
          await refreshHistory(created.data.patientId);
        }
      } catch (error: unknown) {
        showError(getUserFacingError(error, tErrors, t('errorCreateTreatment')));
      } finally {
        setCreatingStandalone(false);
      }
    },
    [
      creatingStandalone,
      flushDraftSave,
      selectedDay,
      resetToLiveContext,
      hydrateFromTreatment,
      refreshHistory,
      showError,
      t,
      tErrors,
    ],
  );

  const deleteStandaloneTreatment = useCallback(
    async (item: DayStripItem) => {
      if (!canEdit || item.kind !== 'unscheduled' || !item.canDelete) return;
      if (!window.confirm(t('confirmDeleteEmptyTreatment'))) return;
      if (autosaveTimerRef.current) {
        clearTimeout(autosaveTimerRef.current);
        autosaveTimerRef.current = null;
      }
      const wasSelected = selectedStandaloneId === item.id;
      if (wasSelected) {
        draftHydratingRef.current = true;
      }
      try {
        while (saveInFlightRef.current) {
          await new Promise((resolve) => setTimeout(resolve, 50));
        }
        // Chip-delete / cleared type can look empty in the strip before autosave
        // finishes. Persist [] first so DELETE /treatments/:id (empty-only) succeeds.
        await treatmentsApi.saveDraftByTreatment(item.id, { details: [] });
        await treatmentsApi.deleteStandalone(item.id);
        setStandaloneTreatments((prev) => prev.filter((row) => row.id !== item.id));
        if (wasSelected) {
          resetToLiveContext();
          setSelectedStandaloneId(null);
          setSelectedAppointmentId(null);
        }
      } catch (error: unknown) {
        if (wasSelected) {
          draftHydratingRef.current = false;
        }
        showError(getUserFacingError(error, tErrors, t('errorDeleteTreatment')));
      }
    },
    [
      canEdit,
      resetToLiveContext,
      selectedStandaloneId,
      showError,
      t,
      tErrors,
    ],
  );

  const canAccessOrganizations = canAccessDashboardRoute(currentOrganization, '/organizations');

  const onSelectDay = useCallback(
    (day: Date) => {
      void (async () => {
        const ok = await flushDraftSave();
        if (!ok) return;
        const patientIdToRefresh = historyPatientId;
        resetToLiveContext();
        setSearchedPatient(null);
        setNewTreatmentPickerOpen(false);
        setSelectionLocked(false);
        setSelectedAppointmentId(null);
        setSelectedStandaloneId(null);
        setSelectedDay(startOfLocalDay(day));
        if (patientIdToRefresh) {
          await refreshHistory(patientIdToRefresh);
        }
      })();
    },
    [flushDraftSave, resetToLiveContext, historyPatientId, refreshHistory],
  );

  const handleSelectPreviewTreatment = useCallback((treatment: PastTreatment) => {
    setSelectedPreviewId(treatment.id);
  }, []);

  const exitBrowse = useCallback(() => {
    setSelectedPreviewId(null);
  }, []);

  const loadTreatmentIntoWorkspace = useCallback(
    async (
      treatment: PastTreatment,
      focusDetailClientId?: string,
      options?: { scrollToLabPanel?: boolean },
    ) => {
      const ok = workspaceModeRef.current === 'live' ? await flushDraftSave() : true;
      if (!ok) return false;

      let treatmentToLoad = treatment;
      try {
        const draftResponse = treatment.appointmentId
          ? await treatmentsApi.getDraft(treatment.appointmentId)
          : await treatmentsApi.getDraftByTreatment(treatment.id);
        if (draftResponse.data) {
          treatmentToLoad = draftResponse.data;
        }
      } catch {
        // Fall back to the history snapshot when draft cannot be loaded.
      }

      const isHistorical = isTreatmentDayHistorical(treatmentToLoad.treatmentAt, todayStart);
      setWorkspaceMode(isHistorical ? 'historical' : 'live');
      setSelectedPreviewId(null);
      const nextDay = startOfLocalDay(new Date(treatmentToLoad.treatmentAt));
      setSelectedDay((prev) => (compareLocalDayStart(prev, nextDay) === 0 ? prev : nextDay));
      setSelectionLocked(true);
      if (treatmentToLoad.appointmentId ?? treatment.appointmentId) {
        setSelectedAppointmentId(treatmentToLoad.appointmentId ?? treatment.appointmentId ?? null);
        setSelectedStandaloneId(null);
      } else {
        setSelectedAppointmentId(null);
        setSelectedStandaloneId(treatmentToLoad.id);
        setStandaloneTreatments((prev) =>
          prev.some((row) => row.id === treatmentToLoad.id) ? prev : [...prev, treatmentToLoad],
        );
      }

      skipNextGetDraftRef.current = true;
      draftHydratingRef.current = true;
      if (focusDetailClientId && options?.scrollToLabPanel !== false) {
        pendingScrollToLabRef.current = true;
      }
      hydrateFromTreatment(treatmentToLoad);
      draftHydratingRef.current = false;

      if (focusDetailClientId) {
        if (options?.scrollToLabPanel !== false) {
          pendingScrollToLabRef.current = true;
        }
        setActiveDetailId(focusDetailClientId);
        const mappedLabCases = withoutEmptyLabCaseDrafts(
          (treatmentToLoad.labCases ?? []).map(mapLabCaseDraftFromApi),
        );
        const linked = mappedLabCases.find(
          (lc) => !lc.sentAt && lc.detailClientId === focusDetailClientId,
        );
        if (linked) {
          setActiveLabCaseId(linked.clientId);
        }
        if (options?.scrollToLabPanel !== false) {
          requestAnimationFrame(() => {
            scrollWithinMainScrollContainer(labPanelRef.current);
          });
        }
      }

      return true;
    },
    [flushDraftSave, hydrateFromTreatment, todayStart],
  );

  const handleSelectSearchedPatient = useCallback(
    (patient: Patient) => {
      void (async () => {
        const alreadySelected =
          selectedAppointment?.patientId === patient.id ||
          selectedStandalone?.patientId === patient.id ||
          searchedPatient?.id === patient.id;
        if (alreadySelected && hasLiveContext) {
          return;
        }

        const ok = await flushDraftSave();
        if (!ok) return;

        setPatientSearchBusy(true);
        try {
          const stripAppointment = appointments.find((row) => row.patientId === patient.id);
          const stripStandalone = standaloneTreatments.find(
            (row) => row.patientId === patient.id && !row.patient?.isWalkIn,
          );
          if (stripAppointment || stripStandalone) {
            draftHydratingRef.current = true;
            resetToLiveContext();
            setSearchedPatient(null);
            setNewTreatmentPickerOpen(false);
            setSelectionLocked(true);
            if (stripAppointment) {
              setSelectedAppointmentId(stripAppointment.id);
              setSelectedStandaloneId(null);
            } else if (stripStandalone) {
              setSelectedAppointmentId(null);
              setSelectedStandaloneId(stripStandalone.id);
            }
            return;
          }

          setSearchedPatient({
            id: patient.id,
            firstName: patient.firstName,
            lastName: patient.lastName,
            mobile: patient.mobile,
            email: patient.email,
          });
          resetToLiveContext();
          setNewTreatmentPickerOpen(false);
          setSelectedAppointmentId(null);
          setSelectedStandaloneId(null);
          setSelectionLocked(true);
          setHistory([]);
          setHistoryLoading(true);

          const response = await treatmentsApi.listPatientHistory(patient.id, 1);
          const latest = response.data[0];
          if (latest) {
            await loadTreatmentIntoWorkspace(latest);
          }
        } catch (error: unknown) {
          showError(getUserFacingError(error, tErrors, t('errorLoadHistory')));
          setSearchedPatient(null);
        } finally {
          setPatientSearchBusy(false);
        }
      })();
    },
    [
      selectedAppointment?.patientId,
      selectedStandalone?.patientId,
      searchedPatient?.id,
      hasLiveContext,
      flushDraftSave,
      appointments,
      standaloneTreatments,
      resetToLiveContext,
      loadTreatmentIntoWorkspace,
      showError,
      t,
      tErrors,
    ],
  );

  const handleLoadIntoWorkspace = useCallback(() => {
    if (!previewTreatment) return;
    void loadTreatmentIntoWorkspace(previewTreatment);
  }, [loadTreatmentIntoWorkspace, previewTreatment]);

  const handleGoToLabDispatch = useCallback(
    (item: LabDispatchAttentionItem) => {
      if (item.isCurrentDraft) {
        exitBrowse();
        setLabWorkspaceView('dispatch');
        if (item.detailClientId !== activeDetailId) {
          pendingScrollToLabRef.current = true;
          setActiveDetailId(item.detailClientId);
        }
        const linked = labCaseDrafts.find(
          (lc) => !lc.sentAt && lc.detailClientId === item.detailClientId,
        );
        if (linked) {
          setActiveLabCaseId(linked.clientId);
        }
        requestAnimationFrame(() => {
          scrollWithinMainScrollContainer(labPanelRef.current);
        });
        return;
      }

      const treatment =
        history.find((entry) => entry.id === item.treatmentId) ??
        historyPanelItems.find((entry) => entry.id === item.treatmentId);
      if (!treatment) return;
      void loadTreatmentIntoWorkspace(treatment, item.detailClientId);
    },
    [exitBrowse, activeDetailId, history, historyPanelItems, labCaseDrafts, loadTreatmentIntoWorkspace],
  );

  const handleSelectPatientLabCase = useCallback(
    (item: PatientLabCaseSummary) => {
      void (async () => {
        setSelectedRailLabCaseId(item.labCaseId);

        // Ensure a patient context is established before we potentially clear the last unread update,
        // so the rail section doesn't briefly unmount/collapse.
        if (item.patientId && item.patientId !== activePatientId) {
          setSearchedPatient({
            id: item.patientId,
            firstName: item.patientFirstName,
            lastName: item.patientLastName,
          });
        }

        try {
          await notificationsApi.markCaseRead(item.labCaseId);
          notifyTabBadgesChanged();
          handleLabCaseMarkedRead(item.labCaseId);
        } catch {
          // Non-blocking — workspace navigation still proceeds.
        }

        let treatment =
          history.find((entry) => entry.id === item.treatmentId) ??
          historyPanelItems.find((entry) => entry.id === item.treatmentId) ??
          (selectedAppointment?.id === item.appointmentId ? currentDraftPreview : null);

        if (!treatment && item.patientId) {
          try {
            const response = await treatmentsApi.listPatientHistory(item.patientId, 50);
            treatment = response.data.find((entry) => entry.id === item.treatmentId) ?? null;
          } catch (error: unknown) {
            showError(getUserFacingError(error, tErrors, t('errorLoadHistory')));
            return;
          }
        }

        if (!treatment?.appointmentId) return;

        if (
          selectedAppointmentId === treatment.appointmentId &&
          workspaceMode === 'live' &&
          !isBrowsing
        ) {
          setLabWorkspaceView('dispatch');
          if (item.detailClientId !== activeDetailId) {
            pendingScrollToLabRef.current = true;
            setActiveDetailId(item.detailClientId);
          }
          const matchingDraft = labCaseDrafts.find((lc) => lc.id === item.labCaseId);
          if (matchingDraft) {
            setActiveLabCaseId(matchingDraft.clientId);
          }
          requestAnimationFrame(() => {
            scrollWithinMainScrollContainer(labPanelRef.current);
          });
          return;
        }

        await loadTreatmentIntoWorkspace(treatment, item.detailClientId, {
          scrollToLabPanel: true,
        });
      })();
    },
    [
      activeDetailId,
      activePatientId,
      currentDraftPreview,
      handleLabCaseMarkedRead,
      history,
      historyPanelItems,
      isBrowsing,
      labCaseDrafts,
      loadTreatmentIntoWorkspace,
      selectedAppointment?.id,
      selectedAppointmentId,
      showError,
      t,
      tErrors,
      workspaceMode,
    ],
  );

  useEffect(() => {
    const labCaseId = pendingLabCaseIdRef.current;
    if (!labCaseId) return;
    const match =
      unreadLabCases.find((item) => item.labCaseId === labCaseId) ??
      patientLabCases.find((item) => item.labCaseId === labCaseId);
    if (!match) return;
    pendingLabCaseIdRef.current = null;
    void handleSelectPatientLabCase(match);
  }, [unreadLabCases, patientLabCases, handleSelectPatientLabCase]);

  useEffect(() => {
    const match = patientLabCases.find((item) => item.detailClientId === activeDetailId);
    if (match) {
      setSelectedRailLabCaseId(match.labCaseId);
    }
  }, [activeDetailId, patientLabCases]);

  const uploadForDetail = useCallback(
    async (
      detailClientId: string,
      files: FileList | File[],
      onProgress?: (percent: number) => void,
    ) => {
      if (!canEditTreatmentForDay || !hasLiveContext) return;
      const target = detailsRef.current.find((d) => d.clientId === detailClientId);
      if (target && isDetailLocked(target)) return;
      const list = files instanceof FileList ? Array.from(files) : files;
      if (!list.length) return;

      setUploadBusyDetailId(detailClientId);
      try {
        const uploaded = selectedAppointment
          ? await treatmentsApi.uploadDetailAttachments(
              selectedAppointment.id,
              detailClientId,
              list,
              onProgress,
            )
          : await treatmentsApi.uploadDetailAttachmentsByTreatment(
              selectedStandalone!.id,
              detailClientId,
              list,
              onProgress,
            );
        setDetails((prev) =>
          prev.map((d) =>
            d.clientId === detailClientId
              ? { ...d, attachmentMetas: [...d.attachmentMetas, ...uploaded.data] }
              : d,
          ),
        );
        showSuccess(t('successFilesUploaded', { count: uploaded.data.length }));
      } catch (error: unknown) {
        showError(getUserFacingError(error, tErrors, t('errorUpload')));
      } finally {
        setUploadBusyDetailId(null);
      }
    },
    [canEditTreatmentForDay, isDetailLocked, hasLiveContext, selectedAppointment, selectedStandalone, showSuccess, showError, t, tErrors],
  );

  const handleLabCasesChange = useCallback(
    (next: LabCaseDraft[]) => {
      const prevCleaned = withoutEmptyLabCaseDrafts(labCaseDrafts);
      const cleaned = withoutEmptyLabCaseDrafts(next);
      labCaseDraftsRef.current = cleaned;
      setLabCaseDrafts(cleaned);

      if (!cleaned.some((lc) => lc.detailClientId === activeDetailId)) {
        setActiveLabCaseId((prev) =>
          prev && cleaned.some((lc) => lc.clientId === prev) ? prev : null,
        );
      }

      const removedPersistedDraft = prevCleaned.some(
        (lc) => lc.id && !cleaned.some((row) => row.clientId === lc.clientId),
      );
      if (
        removedPersistedDraft &&
        hasLiveContext &&
        canEditTreatmentForDay
      ) {
        void (async () => {
          try {
            const saved = await persistDraft({ force: true });
            await persistLabCases(saved, cleaned);
          } catch (error: unknown) {
            showError(getUserFacingError(error, tErrors, t('errorSaveLabShipments')));
          }
        })();
      }
    },
    [
      activeDetailId,
      canEditTreatmentForDay,
      labCaseDrafts,
      persistDraft,
      persistLabCases,
      selectedAppointment,
      showError,
      t,
      tErrors,
    ],
  );

  /**
   * Voice entry.
   *
   * Confirm always appends a NEW detail — it never edits an existing one, and never
   * touches onAddDetail. Nothing is created until this runs, so cancelling or a failed
   * recording leaves the chip strip untouched.
   */
  const applyVoiceResult = useCallback(
    (result: VoiceExtractionResult, selection: VoiceApplySelection) => {
      const detail = newDetail(
        defaultTreatmentTypeForAppointment(selectedAppointment?.purpose, treatmentCatalog),
      );

      // Ticked rows land on top of the seeded defaults, so unticking the type row leaves
      // the appointment-purpose default rather than a blank.
      if (selection.treatmentType && result.treatmentType) {
        detail.treatmentType = result.treatmentType;
      }
      if (selection.teeth) {
        detail.teeth = [...result.teeth];
        detail.toothSelectionGroups = result.toothSelectionGroups.map((group) => ({
          ...group,
          teeth: [...group.teeth],
        }));
      }
      if (selection.comment && result.comment) {
        detail.comment = result.comment;
      }

      const nextDetails = [...detailsRef.current, detail];
      setDetails(nextDetails);
      // persistDraft reads detailsRef, and setDetails has not rendered yet.
      detailsRef.current = nextDetails;
      setActiveDetailId(detail.clientId);

      // Lab-side rows ride on a lab case draft keyed by the detail's *client* id, so a
      // brand-new unsaved detail can still carry one; it is persisted after the detail is.
      const wantsLabDraft =
        (selection.prosthesis && result.prosthesis) ||
        (selection.lab && result.labId) ||
        (selection.dueDate && result.dueDate);

      if (wantsLabDraft) {
        const draft = newLabCaseDraft();
        draft.detailClientId = detail.clientId;
        if (selection.lab && result.labId) {
          draft.destinationOrganizationId = result.labId;
        }
        if (selection.dueDate && result.dueDate) {
          draft.dueDate = result.dueDate;
        }
        if (selection.prosthesis && result.prosthesis) {
          // byTooth keys are plain strings; the group's teeth are FdiToothId.
          const groupOf = (tooth: string) =>
            result.toothSelectionGroups.find((group) =>
              (group.teeth as readonly string[]).includes(tooth),
            )?.groupId ?? '';
          // Only teeth that actually landed on the detail. Unticking "teeth" while
          // leaving "prosthesis" ticked would otherwise attach prosthesis rows for teeth
          // the treatment does not contain — nothing downstream filters them, and they
          // would reach task generation as work for teeth nobody is treating.
          const detailTeeth = new Set<string>(detail.teeth);
          draft.toothProsthesis = Object.entries(result.prosthesis.byTooth)
            .filter(([tooth]) => detailTeeth.has(tooth))
            .map(([tooth, prosthesisTypeCode]) => ({
              detailClientId: detail.clientId,
              tooth,
              prosthesisTypeCode,
              selectionGroupId: groupOf(tooth),
            }));
        }
        const updatedLabCases = [...labCaseDrafts, draft];
        setLabCaseDrafts(updatedLabCases);

        // Persist the new detail first so lab-case rows can use real treatmentDetailIds.
        void (async () => {
          try {
            const saved = await persistDraft({ force: true });
            // persistDraft returns a *preview* when the details are not persistable — one
            // blank detail is enough — and a preview's detail id falls back to the client
            // id. Check what came back, not the precondition, so this holds for every early
            // return persistDraft has.
            const savedDetail = saved.details.find((d) => d.clientId === detail.clientId);
            if (!savedDetail?.id || savedDetail.id === detail.clientId) return;
            await persistLabCases(saved, updatedLabCases);
          } catch (error: unknown) {
            showError(getUserFacingError(error, tErrors, t('errorSaveLabShipments')));
          }
        })();
      }

      setVoiceResult(null);
    },
    [
      labCaseDrafts,
      persistDraft,
      persistLabCases,
      selectedAppointment?.purpose,
      showError,
      t,
      tErrors,
      treatmentCatalog,
    ],
  );

  const handleRemoveDetail = useCallback(
    (detailClientId: string) => {
      if (!canEditTreatmentForDay) return;
      const idx = details.findIndex((d) => d.clientId === detailClientId);
      if (idx < 0) return;
      const target = details[idx];
      if (!target || isDetailLocked(target)) return;
      if (!window.confirm(
        details.length <= 1 ? t('confirmRemoveLastDetail') : t('confirmRemoveDetail'),
      )) return;

      const nextDetails = details.filter((d) => d.clientId !== detailClientId);
      const nextActive =
        activeDetailId === detailClientId
          ? (nextDetails[Math.min(idx, nextDetails.length - 1)]?.clientId ?? '')
          : activeDetailId;

      // Sync ref before any persist triggered by lab-case cleanup (same tick).
      detailsRef.current = nextDetails;
      setDetails(nextDetails);
      setActiveDetailId(nextActive);

      if (labCaseDrafts.some((lc) => lc.detailClientId === detailClientId)) {
        handleLabCasesChange(
          withoutEmptyLabCaseDrafts(
            labCaseDrafts.filter((lc) => lc.detailClientId !== detailClientId),
          ),
        );
      }
    },
    [
      activeDetailId,
      canEditTreatmentForDay,
      details,
      handleLabCasesChange,
      isDetailLocked,
      labCaseDrafts,
      t,
    ],
  );

  const handleTreatmentTypeChange = useCallback(
    (nextType: string) => {
      if (!canEditTreatmentForDay) return;
      const detail = details.find((d) => d.clientId === activeDetailId);
      if (!detail || isDetailLocked(detail)) return;
      if (detail.treatmentType === nextType) return;

      const leavingLab = labDependentCodes.has(detail.treatmentType);
      const enteringLab = labDependentCodes.has(nextType);
      const jobs =
        labCaseDraftForDetail(labCaseDrafts, activeDetailId)?.toothProsthesis ?? [];
      const hasWork =
        detail.teeth.length > 0 ||
        detail.toothSelectionGroups.some((g) => g.teeth.length > 0) ||
        jobs.length > 0;

      if (leavingLab && hasWork && !window.confirm(t('confirmLeaveProsthesis'))) {
        return;
      }

      const nextDetails = details.map((d) => {
        if (d.clientId !== activeDetailId) return d;
        if (leavingLab || enteringLab) {
          return {
            ...d,
            treatmentType: nextType,
            teeth: [],
            toothSelectionGroups: [],
          };
        }
        return { ...d, treatmentType: nextType };
      });
      detailsRef.current = nextDetails;
      setDetails(nextDetails);

      if (leavingLab) {
        const nextDrafts = labCaseDrafts.filter(
          (lc) => lc.detailClientId !== activeDetailId || Boolean(lc.sentAt),
        );
        if (nextDrafts.length !== labCaseDrafts.length) {
          handleLabCasesChange(nextDrafts);
        }
      }
    },
    [
      activeDetailId,
      canEditTreatmentForDay,
      details,
      handleLabCasesChange,
      isDetailLocked,
      labCaseDrafts,
      labDependentCodes,
      t,
    ],
  );

  const handleAddLabCase = useCallback(async () => {
    if (!canEditTreatmentForDay || !hasLiveContext) return;

    const cleaned = withoutEmptyLabCaseDrafts(labCaseDrafts);
    const existing = cleaned.find(
      (lc) => !lc.sentAt && lc.detailClientId === activeDetailId,
    );
    if (existing) {
      setActiveLabCaseId(existing.clientId);
      return;
    }

    const activeDetail = details.find((d) => d.clientId === activeDetailId);
    const shouldIncludeActive = Boolean(
      activeDetail && labDependentCodes.has(activeDetail.treatmentType),
    );

    const orphan = cleaned.find((lc) => !lc.sentAt && !lc.detailClientId);
    if (orphan && shouldIncludeActive) {
      const updatedLabCases = cleaned.map((lc) =>
        lc.clientId === orphan.clientId ? { ...lc, detailClientId: activeDetailId } : lc,
      );
      setLabCaseDrafts(updatedLabCases);
      setActiveLabCaseId(orphan.clientId);

      try {
        const saved = await persistDraft({ force: true });
        await persistLabCases(saved, updatedLabCases);
      } catch (error: unknown) {
        showError(getUserFacingError(error, tErrors, t('errorSaveLabShipments')));
      }
      return;
    }

    const next: LabCaseDraft = {
      ...newLabCaseDraft(),
      detailClientId: shouldIncludeActive ? activeDetailId : null,
      attachmentIds: activeDetail?.attachmentMetas.map((a) => a.id) ?? [],
    };
    const updatedLabCases = [...cleaned, next];
    setLabCaseDrafts(updatedLabCases);
    setActiveLabCaseId(next.clientId);

    try {
      const saved = await persistDraft({ force: true });
      await persistLabCases(saved, updatedLabCases);
    } catch (error: unknown) {
      showError(getUserFacingError(error, tErrors, t('errorSaveLabShipments')));
    }
  }, [
    activeDetailId,
    canEditTreatmentForDay,
    details,
    labCaseDrafts,
    labDependentCodes,
    persistDraft,
    persistLabCases,
    selectedAppointment,
    showError,
    t,
    tErrors,
  ]);

  // Auto-create an unsent draft when the active detail is prosthesis (no wizard step).
  useEffect(() => {
    if (!showLabDispatch) return;
    if (!canEditTreatmentForDay || !hasLiveContext) return;
    const activeDetail = details.find((d) => d.clientId === activeDetailId);
    if (!activeDetail || !labDependentCodes.has(activeDetail.treatmentType)) return;
    // Already shipped (or locked) — do not create another draft (avoids post-send flicker).
    if (isDetailLocked(activeDetail)) return;
    if (labCaseDrafts.some((lc) => lc.detailClientId === activeDetailId && lc.sentAt)) return;
    const hasDraft = labCaseDrafts.some((lc) => lc.detailClientId === activeDetailId);
    if (hasDraft) return;
    void handleAddLabCase();
  }, [
    activeDetailId,
    canEditTreatmentForDay,
    details,
    handleAddLabCase,
    hasLiveContext,
    isDetailLocked,
    labCaseDrafts,
    labDependentCodes,
    showLabDispatch,
  ]);

  const handleSendLabCase = useCallback(
    async (labCase: LabCaseDraft, comment?: string) => {
      if (!canEditTreatmentForDay || !hasLiveContext) return;
      if (!labCase.destinationOrganizationId) {
        showError(t('errorChooseOrg'));
        return;
      }
      if (!labCase.detailClientId) {
        showError(t('errorLabCaseNeedsDetails'));
        return;
      }

      setSendBusyId(labCase.clientId);
      try {
        if (autosaveTimerRef.current) {
          clearTimeout(autosaveTimerRef.current);
          autosaveTimerRef.current = null;
        }
        while (saveInFlightRef.current) {
          await new Promise((resolve) => setTimeout(resolve, 50));
        }

        const saved = await persistDraft({ force: true });
        const afterLabCases = await persistLabCases(saved);

        const refreshedLabCase = afterLabCases.labCases.find(
          (lc) => lc.clientId === labCase.clientId || lc.id === labCase.id,
        );
        if (!refreshedLabCase?.id) throw new Error(t('errorSendCase'));

        const trimmedComment = comment?.trim();
        if (trimmedComment) {
          await treatmentsApi.addLabCaseComment(refreshedLabCase.id, { body: trimmedComment });
        }

        const response = await treatmentsApi.sendLabCase(refreshedLabCase.id);

        const draftResponse = selectedAppointment
          ? await treatmentsApi.getDraft(selectedAppointment.id)
          : await treatmentsApi.getDraftByTreatment(selectedStandalone!.id);
        if (draftResponse.data?.details?.length) {
          const mapped = draftResponse.data.details.map(mapDetailFromApi);
          detailsRef.current = mapped;
          setDetails(mapped);
          setActiveDetailId((prev) => {
            const stillExists = mapped.some((d) => d.clientId === prev);
            return stillExists ? prev : (mapped[0]?.clientId ?? '');
          });
          setSavedSnapshot(serializeDetails(mapped));
        } else {
          const sentDetailClientId = labCase.detailClientId;
          setDetails((prev) => {
            const next = prev.map((detail) => {
              if (detail.clientId !== sentDetailClientId) return detail;
              return {
                ...detail,
                labCaseId: response.data.id,
                sentAt: response.data.sentAt,
                sends: response.data.sends,
                sendToOrganizationIds: response.data.destinationOrganizationId
                  ? [response.data.destinationOrganizationId]
                  : detail.sendToOrganizationIds,
              };
            });
            detailsRef.current = next;
            return next;
          });
        }

        setLabCaseDrafts((prev) =>
          prev.map((lc) =>
            lc.clientId === labCase.clientId
              ? {
                  ...lc,
                  id: response.data.id,
                  sentAt: response.data.sentAt,
                  destinationOrganizationId: response.data.destinationOrganizationId,
                  sends: response.data.sends,
                  taskProgress: response.data.taskProgress ?? lc.taskProgress,
                  shareUrl: response.data.shareUrl ?? lc.shareUrl,
                }
              : lc,
          ),
        );

        setRecentOrganizationIds((prev) => {
          const orgId = labCase.destinationOrganizationId!;
          rememberRecentLab(currentOrganization?.id, orgId);
          return [orgId, ...prev.filter((id) => id !== orgId)].slice(0, MAX_RECENT_LABS);
        });
        showSuccess(t('successCaseSent'));
        notifyTabBadgesChanged();
        if (selectedAppointment?.patientId) {
          // Silent: avoid rail/history loading flicker while staying on Lab step.
          void refreshHistory(selectedAppointment.patientId, { silentLabCases: true });
        } else if (selectedStandalone?.patientId) {
          void refreshHistory(selectedStandalone.patientId, { silentLabCases: true });
        }
      } catch (error: unknown) {
        showError(getUserFacingError(error, tErrors, t('errorSendCase')));
      } finally {
        setSendBusyId(null);
      }
    },
    [
      canEditTreatmentForDay,
      selectedAppointment,
      persistDraft,
      persistLabCases,
      refreshHistory,
      showSuccess,
      showError,
      t,
      tErrors,
      currentOrganization?.id,
    ],
  );

  const labDispatchPanel = (
    <LabCasesDispatchPanel
      details={details}
      activeDetailId={activeDetailId}
      labCases={labCaseDrafts}
      labDependentCodes={labDependentCodes}
      treatmentCatalog={treatmentCatalog}
      prosthesisCatalog={prosthesisCatalog}
      labCaseSummary={activeLabCaseSummary}
      locale={locale}
      onLabCaseSummaryChange={handleLabCaseSummaryChange}
      onLabCaseMarkedRead={handleLabCaseMarkedRead}
      onLabCaseActivityChange={() => {
        if (historyPatientId) {
          void refreshPatientLabCases(historyPatientId, { silent: true });
        }
      }}
      activeLabCaseId={activeLabCaseId}
      onLabCasesChange={handleLabCasesChange}
      disabled={!canEditTreatmentForDay}
      canEdit={canEdit}
      orgs={orgs}
      organizationSearch={organizationSearch}
      onOrganizationSearchChange={setOrganizationSearch}
      recentOrganizationIds={recentOrganizationIds}
      sendBusyId={sendBusyId}
      onSendLabCase={(lc, comment) => handleSendLabCase(lc, comment)}
      onCommentError={showError}
      canInviteLab={canAccessOrganizations}
      onInviteLab={() => router.push('/organizations?action=invite-lab')}
    />
  );

  if (!canView) {
    return (
      <div className="surface-card p-6 max-w-xl">
        <h2 className="text-lg font-semibold text-text-primary">{t('noPermissionTitle')}</h2>
        <p className="text-sm text-text-secondary mt-2">{t('noPermissionBody')}</p>
      </div>
    );
  }

  return (
    <div className="space-y-4">
      <header className="flex flex-col gap-3 sm:flex-row sm:items-center sm:gap-4">
        <div className="min-w-0 shrink-0">
          <h1 className="text-xl sm:text-2xl font-semibold text-text-primary">{t('title')}</h1>
          {!canEdit ? (
            <p className="text-sm text-text-secondary mt-1">{t('subtitleReadOnly')}</p>
          ) : null}
        </div>
        <div className="min-w-0 flex-1">
          <PatientSearchCombobox
            search={patientSearch}
            onSearchChange={setPatientSearch}
            patients={patientSearchResults}
            loading={patientSearchLoading || patientSearchBusy}
            onSelectPatient={handleSelectSearchedPatient}
            placeholder={tPatients('searchPlaceholder')}
            emptyResultsMessage={tPatients('noResults')}
          />
        </div>
      </header>

      <AppointmentsStrip
        stripHidden={stripHidden}
        onToggleStripHidden={() => setStripHidden((s) => !s)}
        selectedDay={selectedDay}
        onSelectDay={onSelectDay}
        items={dayStripItems}
        selectedItemId={selectedStripItemId}
        onSelectItem={onPickStripItem}
        onDeleteUnscheduled={canEdit ? deleteStandaloneTreatment : undefined}
        treatmentCatalog={treatmentCatalog}
        loading={apptsLoading}
      />

      {workspaceMode === 'historical' && (
        <p className="text-sm text-emerald-700 dark:text-emerald-400 rounded-[var(--radius-md)] border border-emerald-500/40 bg-emerald-500/10 px-3 py-2">
          {t('historicalReadonlyNotice')}
        </p>
      )}

      {isViewingPastDay && workspaceMode === 'live' && (
        <p className="text-sm text-text-secondary rounded-[var(--radius-md)] border border-border/60 bg-background-secondary/50 px-3 py-2">
          {t('pastDayNotice')}
        </p>
      )}

      <div className="treatment-layout-grid grid grid-cols-1 xl:grid-cols-[minmax(300px,380px)_minmax(0,1fr)] gap-4 items-start">
        <div className="space-y-3 min-w-0 xl:max-w-[380px]">
          <div className="surface-card p-3 space-y-3">
            {canEdit && !isViewingPastDay ? (
              <div className="space-y-2">
                <Button
                  type="button"
                  size="lg"
                  fullWidth
                  aria-expanded={newTreatmentPickerOpen}
                  onClick={() => setNewTreatmentPickerOpen((open) => !open)}
                >
                  {t('newTreatment')}
                </Button>
                {newTreatmentPickerOpen ? (
                  <NewTreatmentPatientPicker
                    creating={creatingStandalone}
                    currentPatient={namedActivePatient}
                    onSelectWalkIn={() => createStandaloneTreatment({ walkIn: true })}
                    onSelectPatient={(patient) =>
                      createStandaloneTreatment({ patientId: patient.id })
                    }
                    onSelectCurrentPatient={
                      namedActivePatient
                        ? () => createStandaloneTreatment({ patientId: namedActivePatient.id })
                        : undefined
                    }
                    onCancel={() => setNewTreatmentPickerOpen(false)}
                  />
                ) : null}
              </div>
            ) : null}

            {activePatient ? (
              <div
                className={`space-y-0.5 ${
                  canEdit && !isViewingPastDay ? 'border-t border-border/60 pt-3' : ''
                }`}
              >
                <p className="text-[10px] uppercase tracking-wide text-text-muted">
                  {t('selectedPatient')}
                </p>
                <p className="text-base font-semibold text-text-primary">{activePatientName}</p>
                {activePatient.purpose ? (
                  <p className="text-[11px] text-text-secondary">
                    {t('purposeLabel')}{' '}
                    <span className="text-text-primary">
                      {treatmentTypeLabelFromCatalog(activePatient.purpose, treatmentCatalog)}
                    </span>
                  </p>
                ) : null}
              </div>
            ) : (
              <p
                className={`text-sm text-text-muted ${
                  canEdit && !isViewingPastDay ? 'border-t border-border/60 pt-3' : ''
                }`}
              >
                {apptsLoading ? t('loadingAppointments') : t('selectDayWithAppointment')}
              </p>
            )}
          </div>

          {isBrowsing && previewTreatment ? (
            <>
              <div className="rounded-[var(--radius-md)] border border-primary/40 bg-primary/5 px-3 py-2 space-y-2">
                <p className="text-xs text-text-primary">
                  {t('browseBanner', {
                    date: formatAppDate(previewTreatment.treatmentAt, locale, APP_DATE.withWeekday),
                  })}
                </p>
                <div className="flex flex-wrap gap-2">
                  <Button type="button" variant="primary" size="sm" onClick={handleLoadIntoWorkspace}>
                    {t('loadIntoWorkspace')}
                  </Button>
                  <Button type="button" variant="ghost" size="sm" onClick={exitBrowse}>
                    {t('backToCurrentDraft')}
                  </Button>
                </div>
              </div>
              <TreatmentRailSection title={t('previewBrowsingTitle')} defaultExpanded>
                <div className="pt-2">
                  <TreatmentPreviewCard
                    treatment={previewTreatment}
                    heading=""
                    labDependentCodes={labDependentCodes}
                    treatmentCatalog={treatmentCatalog}
                    orgs={orgs}
                    embedded
                  />
                </div>
              </TreatmentRailSection>
            </>
          ) : null}

          {labAttentionItems.length > 0 ? (
            <TreatmentRailSection
              title={t('labAttentionTitle')}
              subtitle={t('labAttentionSubtitle')}
              count={labAttentionItems.length}
              variant="attention"
            >
              <LabDispatchAttentionPanel
                items={labAttentionItems}
                treatmentCatalog={treatmentCatalog}
                labDependentCodes={labDependentCodes}
                orgs={orgs}
                onGoToDispatch={handleGoToLabDispatch}
                compact
              />
            </TreatmentRailSection>
          ) : null}

          {activePatient ? (
            <TreatmentRailSection
              title={t('historyPatientScope', {
                patientName: activePatientName ?? '',
              })}
              subtitle={t('historySubtitle')}
              count={historyPanelItems.length}
            >
              <PastTreatmentsPanel
                items={historyPanelItems}
                currentAppointmentId={selectedAppointmentId}
                treatmentCatalog={treatmentCatalog}
                labDependentCodes={labDependentCodes}
                orgs={orgs}
                loading={historyLoading}
                selectedPreviewId={selectedPreviewId}
                onSelectTreatment={handleSelectPreviewTreatment}
                compact
              />
            </TreatmentRailSection>
          ) : null}

          {showLabShipmentsSection ? (
            <TreatmentRailSection
              title={t('labShipmentsTitle')}
              subtitle={labShipmentsSubtitle}
              count={displayedLabCases.length}
            >
              <TreatmentLabCasesPanel
                scope={labCasesScope}
                onScopeChange={setLabCasesScope}
                items={displayedLabCases}
                loading={labCasesListLoading}
                locale={locale}
                prosthesisCatalog={prosthesisCatalog}
                unreadUpdatesCount={unreadUpdatesCount}
                otherPatientsUnreadCount={otherPatientsUnreadCount}
                canShowPatientScope={Boolean(activePatient)}
                selectedLabCaseId={selectedRailLabCaseId ?? activeSentLabCaseId}
                onSelect={handleSelectPatientLabCase}
                compact
              />
            </TreatmentRailSection>
          ) : null}
        </div>

        <div className="space-y-3 min-w-0 w-full">
          {showSearchedPatientLoading ? (
            <div className="surface-card p-6">
              <p className="text-sm text-text-muted">{t('loading')}</p>
            </div>
          ) : showNoTreatmentFound ? (
            <div className="surface-card w-full p-6 space-y-3">
              <h2 className="text-lg font-semibold text-text-primary">
                {t('noTreatmentFoundTitle')}
              </h2>
              <p className="text-sm text-text-secondary">
                {t('noTreatmentFoundBody', {
                  name: activePatientName ?? '',
                  action: t('newTreatment'),
                })}
              </p>
            </div>
          ) : (
            <>
          <TreatmentDetailsEditor
            details={details}
            activeDetailId={activeDetailId}
            onActiveDetailChange={setActiveDetailId}
            onDetailsChange={setDetails}
            onTreatmentTypeChange={handleTreatmentTypeChange}
            isDetailLocked={isDetailLocked}
            labDependentCodes={labDependentCodes}
            treatmentCatalog={treatmentDropdownCatalog}
            disabled={!canEditTreatmentForDay}
            canEdit={canEdit}
            saveStatus={saveStatus}
            uploadBusy={uploadBusyDetailId === activeDetailId}
            onAddDetail={() => {
              const seedFromAppointment =
                details.length === 0 && selectedAppointment
                  ? defaultTreatmentTypeForAppointment(
                      selectedAppointment.purpose,
                      treatmentCatalog,
                    )
                  : undefined;
              const next = newDetail(seedFromAppointment);
              setDetails((prev) => [...prev, next]);
              setActiveDetailId(next.clientId);
            }}
            onRemoveDetail={handleRemoveDetail}
            onUploadFiles={(files, onProgress) =>
              uploadForDetail(activeDetailId, files, onProgress)
            }
            onRemoveAttachment={(attachmentId) => {
              setDetails((prev) =>
                prev.map((d) =>
                  d.clientId === activeDetailId
                    ? {
                        ...d,
                        attachmentMetas: d.attachmentMetas.filter((a) => a.id !== attachmentId),
                      }
                    : d,
                ),
              );
              setLabCaseDrafts((prev) =>
                prev.map((lc) =>
                  lc.detailClientId === activeDetailId && !lc.sentAt
                    ? {
                        ...lc,
                        attachmentIds: lc.attachmentIds.filter((id) => id !== attachmentId),
                      }
                    : lc,
                ),
              );
            }}
            showChrome
            showFields
            hasArchJobs={activeHasArchJobs}
            voice={voiceForEditor}
            chartLocked={!activeTypeSelected && !showWholeTreatmentPlan && labWorkspaceView !== 'dispatch'}
            chartLockMessage={t('selectTypeBeforeTeeth')}
            showLabDispatchToggle={showLabDispatch}
            labWorkspaceView={labWorkspaceView}
            onLabWorkspaceViewChange={(view) => {
              setShowWholeTreatmentPlan(false);
              setLabWorkspaceView(view);
            }}
            chart={
              <div ref={labPanelRef} className="min-w-0 w-full">
              {showLabDispatch && labWorkspaceView === 'dispatch' ? (
                labDispatchPanel
              ) : prosthesisAssignActive ? (
                  <ProsthesisAssignChart
                    className="w-full"
                    groups={
                      activeDetail?.toothSelectionGroups?.length
                        ? activeDetail.toothSelectionGroups
                        : groupsFromFlatTeeth(activeDetail?.teeth ?? [])
                    }
                    toothProsthesis={
                      labCaseDraftForDetail(labCaseDrafts, activeDetailId)?.toothProsthesis ??
                      []
                    }
                    detailClientId={activeDetailId}
                    catalog={prosthesisCatalog}
                    disabled={!canEditTreatmentForDay || activeLocked}
                    headerControl={
                      <WholePlanToggle
                        pressed={showWholeTreatmentPlan}
                        label={t('toothChartWholePlan')}
                        onToggle={() => setShowWholeTreatmentPlan((open) => !open)}
                      />
                    }
                    onToggleLink={(a, b) => {
                      if (
                        !canEditTreatmentForDay ||
                        activeLocked ||
                        !activeDetailId ||
                        !activeTypeSelected
                      ) {
                        return;
                      }
                      const detail = details.find((d) => d.clientId === activeDetailId);
                      if (!detail) return;
                      const currentGroups =
                        detail.toothSelectionGroups.length > 0
                          ? detail.toothSelectionGroups
                          : groupsFromFlatTeeth(detail.teeth);
                      const edgeLinked = linkedEdgesFromGroups(currentGroups).has(
                        toothEdgeKey(a, b),
                      );
                      const nextGroups = edgeLinked
                        ? unlinkAdjacentTeeth(currentGroups, a, b)
                        : linkAdjacentTeeth(currentGroups, a, b);
                      if (!nextGroups) return;
                      setDetails((prev) =>
                        prev.map((d) =>
                          d.clientId !== activeDetailId
                            ? d
                            : {
                                ...d,
                                toothSelectionGroups: nextGroups,
                                teeth: deriveTeethFromGroups(nextGroups),
                              },
                        ),
                      );
                      setLabCaseDrafts((prev) =>
                        prev.map((lc) => {
                          if (lc.detailClientId !== activeDetailId) return lc;
                          return {
                            ...lc,
                            toothProsthesis: pruneToothProsthesisForGroups(
                              lc.toothProsthesis,
                              activeDetailId,
                              nextGroups,
                            ),
                          };
                        }),
                      );
                    }}
                    onChange={({ groups, toothProsthesis }) => {
                      const nextDetails = details.map((d) =>
                        d.clientId !== activeDetailId
                          ? d
                          : {
                              ...d,
                              toothSelectionGroups: groups,
                              teeth: deriveTeethFromGroups(groups),
                            },
                      );
                      detailsRef.current = nextDetails;
                      setDetails(nextDetails);
                      const prev = labCaseDraftsRef.current;
                      const existing = prev.find(
                        (lc) => lc.detailClientId === activeDetailId && !lc.sentAt,
                      );
                      const nextDrafts = existing
                        ? prev.map((lc) =>
                            lc.clientId === existing.clientId ? { ...lc, toothProsthesis } : lc,
                          )
                        : [
                            ...prev,
                            {
                              ...newLabCaseDraft(),
                              detailClientId: activeDetailId,
                              toothProsthesis,
                            },
                          ];
                      handleLabCasesChange(nextDrafts);
                    }}
                  />
                ) : (
                <FdiToothChart
                  className="w-full"
                  selected={chartSelectedTeeth}
                  linkedEdges={chartLinkedEdges}
                  connectedTeeth={showWholeTreatmentPlan ? undefined : connectedSelectedTeeth}
                  toothColors={chartToothColors}
                  readOnly={showWholeTreatmentPlan}
                  headerControl={
                    <WholePlanToggle
                      pressed={showWholeTreatmentPlan}
                      label={t('toothChartWholePlan')}
                      onToggle={() => setShowWholeTreatmentPlan((open) => !open)}
                    />
                  }
                  onToggle={(fdi, event) => {
                    if (
                      !canEditTreatmentForDay ||
                      activeLocked ||
                      showWholeTreatmentPlan ||
                      !activeDetailId ||
                      !activeTypeSelected
                    ) {
                      return;
                    }

                    const detail = details.find((d) => d.clientId === activeDetailId);
                    if (!detail) return;
                    const currentGroups =
                      detail.toothSelectionGroups.length > 0
                        ? detail.toothSelectionGroups
                        : groupsFromFlatTeeth(detail.teeth);

                    let nextGroups: ReturnType<typeof toggleToothInGroups> | null = null;

                    if (event.shiftKey) {
                      const anchor = rangeAnchorRef.current;
                      if (!anchor || anchor === fdi) {
                        rangeAnchorRef.current = fdi;
                        return;
                      }
                      nextGroups = applyShiftRange(currentGroups, anchor, fdi);
                      rangeAnchorRef.current = fdi;
                      if (!nextGroups) return;
                    } else {
                      nextGroups = toggleToothInGroups(currentGroups, fdi);
                      rangeAnchorRef.current = fdi;
                    }

                    setDetails((prev) =>
                      prev.map((d) =>
                        d.clientId !== activeDetailId
                          ? d
                          : {
                              ...d,
                              toothSelectionGroups: nextGroups!,
                              teeth: deriveTeethFromGroups(nextGroups!),
                            },
                      ),
                    );

                    setLabCaseDrafts((prev) =>
                      prev.map((lc) => {
                        if (lc.detailClientId !== activeDetailId) return lc;
                        return {
                          ...lc,
                          toothProsthesis: pruneToothProsthesisForGroups(
                            lc.toothProsthesis,
                            activeDetailId,
                            nextGroups!,
                          ),
                        };
                      }),
                    );
                  }}
                  onToggleLink={(a, b) => {
                    if (
                      !canEditTreatmentForDay ||
                      activeLocked ||
                      showWholeTreatmentPlan ||
                      !activeDetailId ||
                      !activeTypeSelected
                    ) {
                      return;
                    }
                    const detail = details.find((d) => d.clientId === activeDetailId);
                    if (!detail) return;
                    const currentGroups =
                      detail.toothSelectionGroups.length > 0
                        ? detail.toothSelectionGroups
                        : groupsFromFlatTeeth(detail.teeth);
                    const edgeLinked = linkedEdgesFromGroups(currentGroups).has(toothEdgeKey(a, b));
                    const nextGroups = edgeLinked
                      ? unlinkAdjacentTeeth(currentGroups, a, b)
                      : linkAdjacentTeeth(currentGroups, a, b);
                    if (!nextGroups) return;

                    setDetails((prev) =>
                      prev.map((d) =>
                        d.clientId !== activeDetailId
                          ? d
                          : {
                              ...d,
                              toothSelectionGroups: nextGroups,
                              teeth: deriveTeethFromGroups(nextGroups),
                            },
                      ),
                    );

                    setLabCaseDrafts((prev) =>
                      prev.map((lc) => {
                        if (lc.detailClientId !== activeDetailId) return lc;
                        return {
                          ...lc,
                          toothProsthesis: pruneToothProsthesisForGroups(
                            lc.toothProsthesis,
                            activeDetailId,
                            nextGroups,
                          ),
                        };
                      }),
                    );
                  }}
                  disabled={
                    !canEditTreatmentForDay ||
                    activeLocked ||
                    !activeTypeSelected
                  }
                  onReset={() => {
                    if (
                      !canEditTreatmentForDay ||
                      activeLocked ||
                      showWholeTreatmentPlan ||
                      !activeDetailId ||
                      !activeTypeSelected
                    ) {
                      return;
                    }
                    const detail = details.find((d) => d.clientId === activeDetailId);
                    if (!detail) return;
                    const currentGroups =
                      detail.toothSelectionGroups.length > 0
                        ? detail.toothSelectionGroups
                        : groupsFromFlatTeeth(detail.teeth);
                    if (deriveTeethFromGroups(currentGroups).length === 0) return;
                    if (!window.confirm(t('confirmResetChart'))) return;
                    const nextGroups = groupsFromFlatTeeth([]);
                    setDetails((prev) =>
                      prev.map((d) =>
                        d.clientId !== activeDetailId
                          ? d
                          : {
                              ...d,
                              toothSelectionGroups: nextGroups,
                              teeth: [],
                            },
                      ),
                    );
                    setLabCaseDrafts((prev) =>
                      prev.map((lc) => {
                        if (lc.detailClientId !== activeDetailId) return lc;
                        return {
                          ...lc,
                          toothProsthesis: pruneToothProsthesisForGroups(
                            lc.toothProsthesis,
                            activeDetailId,
                            nextGroups,
                          ),
                        };
                      }),
                    );
                  }}
                />
              )
              }
              </div>
            }
          />
            </>
          )}
        </div>
      </div>
      {voiceResult ? (
        <VoiceReviewSheet
          result={voiceResult}
          treatmentCatalog={treatmentCatalog}
          prosthesisCatalog={prosthesisCatalog}
          labs={orgs}
          onApply={(selection, applied) => applyVoiceResult(applied, selection)}
          onDiscard={() => setVoiceResult(null)}
        />
      ) : null}
    </div>
  );
}
