import { WHISPER_SAMPLE_RATE } from '../types';

/** One planned window over the audio. Sample ranges are half-open [start, end). */
export interface ChunkPlanItem {
  index: number;
  startSample: number;
  endSample: number;
  startSec: number;
  endSec: number;
  isFirst: boolean;
  isLast: boolean;
}

export interface ChunkPlanOptions {
  /** Window length in seconds. Whisper's encoder works on 30s frames; keep < 30. */
  windowSec?: number;
  /** Overlap between adjacent windows, in seconds. */
  overlapSec?: number;
  sampleRate?: number;
}

/**
 * Plan fixed-size overlapping windows over `totalSamples`.
 *
 * Whisper can only attend to ~30s at a time, so long media must be windowed.
 * Adjacent windows overlap by `overlapSec` so the stitcher (see stitch.ts) can
 * drop words that Whisper truncates/hallucinates at a window edge. Every chunk
 * starts at `index * stride` where `stride = windowSamples - overlapSamples`,
 * and the final chunk is clamped to `totalSamples`.
 */
export function planChunks(totalSamples: number, opts: ChunkPlanOptions = {}): ChunkPlanItem[] {
  const sampleRate = opts.sampleRate ?? WHISPER_SAMPLE_RATE;
  const windowSec = opts.windowSec ?? 28;
  const overlapSec = opts.overlapSec ?? 2;

  if (!(totalSamples > 0)) return [];
  if (!(windowSec > 0)) throw new Error('windowSec must be > 0');
  if (overlapSec < 0 || overlapSec >= windowSec) {
    throw new Error('overlapSec must be in [0, windowSec)');
  }

  const windowSamples = Math.max(1, Math.round(windowSec * sampleRate));
  const overlapSamples = Math.round(overlapSec * sampleRate);
  const stride = windowSamples - overlapSamples; // > 0 by the guard above

  if (totalSamples <= windowSamples) {
    return [makeItem(0, 0, totalSamples, sampleRate, totalSamples)];
  }

  const items: ChunkPlanItem[] = [];
  for (let index = 0; ; index++) {
    const start = index * stride;
    const end = Math.min(start + windowSamples, totalSamples);
    items.push(makeItem(index, start, end, sampleRate, totalSamples));
    if (end >= totalSamples) break;
  }
  return items;
}

function makeItem(
  index: number,
  startSample: number,
  endSample: number,
  sampleRate: number,
  totalSamples: number,
): ChunkPlanItem {
  return {
    index,
    startSample,
    endSample,
    startSec: startSample / sampleRate,
    endSec: endSample / sampleRate,
    isFirst: startSample === 0,
    isLast: endSample >= totalSamples,
  };
}
