import type { FdiToothId, ToothSelectionGroup } from '@/types/treatment';

/** Mirrors the backend's ResolvedExtraction — values already resolved, plus what was not. */

export type VoiceUnresolvedReason =
  | 'not_permanent_tooth'
  | 'position_out_of_range'
  | 'tooth_missing_quadrant'
  | 'malformed'
  | 'span_not_same_arch'
  | 'unknown_catalog_code'
  | 'tooth_not_selected'
  | 'invalid_date';

export interface VoiceUnresolvedItem {
  /** The transcript span that could not be resolved, so the clinician sees what was heard. */
  spoken: string;
  reason: VoiceUnresolvedReason;
  /**
   * FDI codes still consistent with what was heard, when a choice would settle it — the
   * review sheet offers them as chips. Only `tooth_missing_quadrant` carries these.
   */
  candidates?: string[];
}

export interface VoiceProsthesisResult {
  byTooth: Record<string, string>;
  /** False means the case cannot ship — every tooth needs a prosthesis type. */
  complete: boolean;
  missingTeeth: FdiToothId[];
}

export interface VoiceExtractionResult {
  transcript: string;
  treatmentType: string | null;
  teeth: FdiToothId[];
  toothSelectionGroups: ToothSelectionGroup[];
  comment: string | null;
  prosthesis: VoiceProsthesisResult | null;
  labId: string | null;
  /** When false, the lab row must not tick itself — the name only approximately matched. */
  labMatchExact: boolean;
  dueDate: string | null;
  unresolved: VoiceUnresolvedItem[];
}

export interface VoiceAvailability {
  enabled: boolean;
  locales: string[];
  /** null means uncapped. */
  maxRecordingMs: number | null;
}

/** Which review rows the clinician ticked. */
export interface VoiceApplySelection {
  treatmentType: boolean;
  teeth: boolean;
  comment: boolean;
  prosthesis: boolean;
  lab: boolean;
  dueDate: boolean;
}

export type VoicePhase = 'idle' | 'recording' | 'processing';
