export const WAVEFORM_PEAKS_VERSION = 1 as const;
export const MAX_WAVEFORM_BUCKET_COUNT = 65_536;
export const DEFAULT_MAX_PCM_SAMPLES = 100_000_000;

export type PcmEncoding = 's16le' | 'f32le';

export type PcmByteSource = ArrayBuffer | ArrayBufferView;

export interface RawPcmInput {
  readonly container: 'raw';
  readonly data: PcmByteSource;
  readonly encoding: PcmEncoding;
  readonly sampleRate: number;
}

export interface WavePcmInput {
  readonly container: 'wav';
  readonly data: PcmByteSource;
}

export type WaveformPcmInput = RawPcmInput | WavePcmInput;

export interface DecodedPcm {
  readonly encoding: PcmEncoding;
  readonly sampleRate: number;
  readonly samples: Float32Array;
}

export interface WaveformPeakData {
  readonly version: typeof WAVEFORM_PEAKS_VERSION;
  readonly sourceEncoding: PcmEncoding;
  readonly sampleRate: number;
  readonly sampleCount: number;
  readonly durationSeconds: number;
  readonly bucketCount: number;
  readonly minimum: Float32Array;
  readonly maximum: Float32Array;
  readonly rms: Float32Array;
}

export interface PeakAggregationOptions {
  /**
   * Requested maximum number of output buckets. The actual count is smaller
   * when the input contains fewer samples.
   */
  readonly bucketCount: number;
  /**
   * A lower per-call input limit can be used by resource policy. It cannot
   * exceed DEFAULT_MAX_PCM_SAMPLES.
   */
  readonly maxSamples?: number;
  readonly isCancelled?: () => boolean;
  readonly onProgress?: (progress: number) => void;
}

export interface WaveformRuntimeOptions {
  /**
   * Override worker construction for tests or constrained hosts. Set to null
   * to force synchronous aggregation.
   */
  readonly workerFactory?: WaveformWorkerFactory | null;
}

export interface WaveformAggregateOptions extends Omit<
  PeakAggregationOptions,
  'isCancelled'
> {
  readonly signal?: AbortSignal;
}

export interface WaveformWorkerLike {
  postMessage(message: unknown, transfer?: readonly Transferable[]): void;
  addEventListener(
    type: 'message',
    listener: (event: MessageEvent<unknown>) => void
  ): void;
  addEventListener(
    type: 'error' | 'messageerror',
    listener: (event: Event) => void
  ): void;
  removeEventListener(
    type: 'message',
    listener: (event: MessageEvent<unknown>) => void
  ): void;
  removeEventListener(
    type: 'error' | 'messageerror',
    listener: (event: Event) => void
  ): void;
  terminate(): void;
}

export type WaveformWorkerFactory = () => WaveformWorkerLike;

export interface WaveformWorkerInput {
  readonly container: WaveformPcmInput['container'];
  readonly data: ArrayBuffer;
  readonly encoding?: PcmEncoding;
  readonly sampleRate?: number;
}

export interface WaveformWorkerAggregateRequest {
  readonly type: 'aggregate';
  readonly requestId: number;
  readonly input: WaveformWorkerInput;
  readonly bucketCount: number;
  readonly maxSamples?: number;
}

export interface WaveformWorkerProgressResponse {
  readonly type: 'progress';
  readonly requestId: number;
  readonly progress: number;
}

export interface WaveformWorkerResultResponse {
  readonly type: 'result';
  readonly requestId: number;
  readonly peaks: WaveformPeakData;
}

export interface WaveformWorkerErrorResponse {
  readonly type: 'error';
  readonly requestId: number;
  readonly error: {
    readonly name: string;
    readonly message: string;
  };
}

export type WaveformWorkerResponse =
  | WaveformWorkerProgressResponse
  | WaveformWorkerResultResponse
  | WaveformWorkerErrorResponse;
