import {
  IsBase64,
  IsIn,
  IsInt,
  IsString,
  MaxLength,
  Min,
} from 'class-validator';

/** Containers OpenRouter's transcription endpoint accepts, and MediaRecorder can produce. */
export const VOICE_AUDIO_FORMATS = [
  'webm',
  'mp4',
  'm4a',
  'aac',
  'ogg',
  'wav',
  'mp3',
  'flac',
] as const;

export type VoiceAudioFormat = (typeof VOICE_AUDIO_FORMATS)[number];

/** Locales the app ships; a profile still has to be configured for one to be usable. */
export const VOICE_LOCALES = ['en', 'fa', 'nl'] as const;

export class ExtractVoiceDto {
  /**
   * Base64 audio, no data: prefix. Capped well above a 2-minute opus clip (~400 KB) but
   * far below OpenRouter's 25 MB ceiling, so an oversized upload is rejected before it
   * costs a vendor call.
   */
  @IsString()
  @IsBase64()
  @MaxLength(8_000_000)
  audio: string;

  @IsIn(VOICE_AUDIO_FORMATS)
  format: VoiceAudioFormat;

  /**
   * The clinician's IANA zone. The server derives "today" from it rather than trusting a
   * client-supplied date, which is what relative deadlines resolve against.
   */
  @IsString()
  @MaxLength(64)
  timeZone: string;

  /**
   * Recording length as measured by the client.
   *
   * Required, not optional: an optional value means omitting it bypasses
   * VOICE_MAX_RECORDING_MS entirely, which would make the cap advisory.
   */
  @IsInt()
  @Min(0)
  durationMs: number;

  /**
   * The locale the clinician is actually speaking, as the UI offered the microphone.
   *
   * Sent explicitly rather than read from `user.language`: the two can diverge (a
   * bookmarked /fa/ URL, a language toggle whose save failed), and a mismatch would
   * transcribe Persian with an English hint and anchor "next Thursday" to the wrong
   * week start. Gating the button and resolving the request must agree by construction.
   */
  @IsIn(VOICE_LOCALES)
  locale: string;
}
