import type { VoiceIntent } from './voice.types';

/**
 * ASR and extraction are separate, independently swappable roles — they will not come from
 * the same vendor for every locale. Both resolve per locale from `config.voice.profiles`.
 */

export type AudioInput = {
  /** Raw base64, no data: prefix. */
  data: string;
  /** Container as the recorder produced it: webm, mp4, m4a, wav, … */
  format: string;
};

export type AsrUsage = {
  seconds: number | null;
  costUsd: number | null;
};

export type AsrResult = {
  text: string;
  usage: AsrUsage;
};

export interface AsrProvider {
  /** `localeHint` is ISO-639-1 and materially improves accuracy — always pass it. */
  transcribe(
    audio: AudioInput,
    localeHint: string,
    signal?: AbortSignal,
  ): Promise<AsrResult>;
}

export type ExtractionCatalog = {
  /** Catalog codes with their labels in the actor's locale, so the model matches spoken words. */
  treatmentTypes: { code: string; label: string }[];
  prosthesisTypes: { code: string; label: string }[];
  /** The clinic's linked labs — a closed choice list. */
  labs: { id: string; name: string }[];
};

export type ExtractionResult = {
  intent: VoiceIntent;
  costUsd: number | null;
};

export interface ExtractionProvider {
  extract(
    transcript: string,
    catalog: ExtractionCatalog,
    localeHint: string,
    signal?: AbortSignal,
  ): Promise<ExtractionResult>;
}

/** Raised when a vendor call fails; the service maps this onto the staged error codes. */
export class VoiceProviderError extends Error {
  constructor(
    readonly stage: 'asr' | 'extraction',
    message: string,
    readonly status?: number,
  ) {
    super(message);
    this.name = 'VoiceProviderError';
  }
}
