export type MediaStreamType =
  'video' | 'audio' | 'subtitle' | 'attachment' | 'data' | 'unknown';

export type ProbeWarningCode =
  | 'invalid-field'
  | 'invalid-fraction'
  | 'missing-stream-index'
  | 'duplicate-stream-index'
  | 'unknown-stream-type'
  | 'invalid-stream'
  | 'invalid-chapter';

export interface ProbeWarning {
  code: ProbeWarningCode;
  path: string;
  message: string;
  received?: string;
}

export interface MediaStreamProbe {
  index: number;
  type: MediaStreamType;
  codecName?: string;
  codecLongName?: string;
  profile?: string;
  durationSeconds?: number;
  bitRate?: number;
  language?: string;
  title?: string;
  disposition: Record<string, boolean>;

  width?: number;
  height?: number;
  codedWidth?: number;
  codedHeight?: number;
  pixelFormat?: string;
  timeBase?: string;
  sampleAspectRatio?: string;
  displayAspectRatio?: string;
  /**
   * Display-matrix or legacy rotate-tag metadata normalized to the signed
   * range (-180, 180]. The encoded width and height are not swapped.
   */
  rotationDegrees?: number;
  frameRate?: number;

  sampleRate?: number;
  channels?: number;
  channelLayout?: string;
  sampleFormat?: string;

  tags: Record<string, string>;
}

export interface ChapterProbe {
  id: number;
  startSeconds: number;
  endSeconds: number;
  timeBase?: string;
  title?: string;
  tags: Record<string, string>;
}

export interface MediaProbe {
  durationSeconds?: number;
  startTimeSeconds?: number;
  bitRate?: number;
  formatNames: string[];
  formatLongName?: string;
  tags: Record<string, string>;
  streams: MediaStreamProbe[];
  chapters: ChapterProbe[];
  warnings: ProbeWarning[];
}

export interface ParsedProbeReport {
  probe: MediaProbe;
  /**
   * The exact report emitted by ffprobe. It is kept separate from the
   * normalized model so application views cannot accidentally depend on
   * unvalidated fields.
   */
  rawReport: string;
}

export interface FractionParseOptions {
  /** Maximum absolute numerator or denominator accepted. */
  maxComponent?: number;
  /** Maximum absolute result accepted. */
  maxAbsoluteValue?: number;
  allowNegative?: boolean;
  allowZero?: boolean;
}

export type FractionParseFailure =
  | 'not-a-string-or-number'
  | 'empty'
  | 'invalid-syntax'
  | 'division-by-zero'
  | 'component-too-large'
  | 'result-too-large'
  | 'negative-not-allowed'
  | 'zero-not-allowed'
  | 'not-finite';

export type FractionParseResult =
  { ok: true; value: number } | { ok: false; reason: FractionParseFailure };
