export type VoiceProviderKind = "openai_realtime" | "grok_voice";

export type AudioCodec = "pcm16" | "opus";

export interface AudioFormat {
  codec: AudioCodec;
  sampleRateHz: number;
  channels: 1 | 2;
}

export interface AudioFrame {
  data: Uint8Array;
  format: AudioFormat;
  timestampMs?: number;
}

export interface ToolInvocation {
  id: string;
  name: string;
  arguments: Record<string, unknown>;
}

export interface ProviderTranscriptEvent {
  role: "caller" | "agent";
  text: string;
  isFinal: boolean;
}

export interface VoiceProviderEvents {
  onAudio?: (frame: AudioFrame) => void | Promise<void>;
  onTranscript?: (event: ProviderTranscriptEvent) => void | Promise<void>;
  onToolCall?: (toolCall: ToolInvocation) => void | Promise<void>;
  onError?: (error: Error) => void | Promise<void>;
  onClose?: (reason?: string) => void | Promise<void>;
}

export interface VoiceProviderSession {
  readonly provider: VoiceProviderKind;
  readonly sessionId: string;
  sendAudio(frame: AudioFrame): Promise<void>;
  sendText(text: string): Promise<void>;
  sendToolResult(toolCallId: string, result: unknown): Promise<void>;
  interrupt(): Promise<void>;
  close(reason?: string): Promise<void>;
}

export interface VoiceProvider {
  readonly kind: VoiceProviderKind;
  connect(input: VoiceProviderConnectInput): Promise<VoiceProviderSession>;
}

export interface VoiceProviderConnectInput {
  callId: string;
  instructions: string;
  voice?: string;
  inputFormat: AudioFormat;
  outputFormat: AudioFormat;
  tools: VoiceToolDefinition[];
  events: VoiceProviderEvents;
  safetyIdentifier?: string;
}

export interface VoiceToolDefinition {
  name: string;
  description: string;
  parameters: Record<string, unknown>;
}

export type CallDisposition =
  | "resolved_by_ai"
  | "rescheduled"
  | "transferred"
  | "callback_required"
  | "verification_failed"
  | "no_matching_patient"
  | "no_valid_slot"
  | "urgent_or_medical_escalation"
  | "amd_write_failed"
  | "rc_media_failed"
  | "voice_provider_failed";

export interface RingCentralCallMetadata {
  extensionId?: string;
  deviceId?: string;
  sessionId?: string;
  telephonySessionId?: string;
  callLogId?: string;
  callerNumber?: string;
  calledNumber?: string;
  transferDestination?: string;
  recordingContentUri?: string;
}

export interface VoiceCallTranscriptEntry {
  at: string;
  role: "caller" | "agent";
  text: string;
  isFinal: boolean;
}

export interface VoiceCallToolAuditEntry {
  at: string;
  id: string;
  name: string;
  arguments: Record<string, unknown>;
  result?: unknown;
}

export interface VoiceCallReconciliation {
  reconciledAt: string;
  matched: boolean;
  matchedBy?: "telephonySessionId" | "sessionId" | "callId";
  callLogId?: string;
  sessionId?: string;
  telephonySessionId?: string;
  recordingContentUri?: string;
}

export interface VoiceCallAuditRecord {
  callId: string;
  telephonyProvider: "ringcentral";
  voiceProvider: VoiceProviderKind;
  ringCentral: RingCentralCallMetadata;
  disposition: CallDisposition;
  startedAt: string;
  endedAt?: string;
  transcripts?: VoiceCallTranscriptEntry[];
  toolCalls?: VoiceCallToolAuditEntry[];
  reconciliation?: VoiceCallReconciliation;
  notes?: string[];
}

export interface PatientCandidate {
  patientId: string;
  legalName: string;
  dob: string;
  phones: string[];
}

export interface VerifiedPatient {
  patientId: string;
  legalName: string;
}

export interface NextAppointmentSummary {
  appointmentId?: string;
  startsAt: string;
  spokenDateTime: string;
  providerName: string;
  status?: string;
}

export interface PatientVerificationInput {
  callerNumber: string;
  statedLegalName: string;
  statedDob: string;
  candidates: PatientCandidate[];
}

export type VerificationFailureReason =
  | "no_candidates"
  | "multiple_candidates"
  | "phone_mismatch"
  | "name_mismatch"
  | "dob_mismatch";

export type PatientVerificationResult =
  | { ok: true; patient: VerifiedPatient }
  | { ok: false; reason: VerificationFailureReason };

export interface AppointmentRef {
  appointmentId: string;
  patientId: string;
  providerId: string;
  serviceCode: string;
  startsAt: string;
}

export interface RescheduleSlot {
  providerId: string;
  serviceCode: string;
  startsAt: string;
  durationMinutes: number;
}

export interface ApprovalToken {
  approvedBy: string;
  approvedAt: string;
  scope: string;
}
