export const DEFAULT_CHAPTER_TIME_BASE = '1/1000' as const;

const TIME_BASE_PATTERN = /^([1-9]\d*)\/([1-9]\d*)$/u;
const MAX_TIME_BASE_COMPONENT = 2_147_483_647n;

export interface ParsedChapterTimeBase {
  readonly numerator: number;
  readonly denominator: number;
  readonly normalized: string;
  readonly secondsPerTick: number;
}

/**
 * Parses the positive integer rational accepted by FFMETADATA TIMEBASE.
 * Components are bounded to FFmpeg's signed 32-bit AVRational range.
 */
export function parseChapterTimeBase(
  value: unknown
): ParsedChapterTimeBase | undefined {
  if (typeof value !== 'string') return undefined;
  const match = TIME_BASE_PATTERN.exec(value.trim());
  if (!match) return undefined;
  const numeratorValue = match[1];
  const denominatorValue = match[2];
  if (numeratorValue === undefined || denominatorValue === undefined) {
    return undefined;
  }
  const numerator = BigInt(numeratorValue);
  const denominator = BigInt(denominatorValue);
  if (
    numerator > MAX_TIME_BASE_COMPONENT ||
    denominator > MAX_TIME_BASE_COMPONENT
  ) {
    return undefined;
  }
  const numericNumerator = Number(numerator);
  const numericDenominator = Number(denominator);
  return Object.freeze({
    numerator: numericNumerator,
    denominator: numericDenominator,
    normalized: `${numericNumerator}/${numericDenominator}`,
    secondsPerTick: numericNumerator / numericDenominator,
  });
}

export function chapterSecondsToTicks(
  seconds: number,
  timeBase: ParsedChapterTimeBase
): number | undefined {
  if (!Number.isFinite(seconds) || seconds < 0) return undefined;
  const ticks = Math.round(
    (seconds * timeBase.denominator) / timeBase.numerator
  );
  return Number.isSafeInteger(ticks) ? ticks : undefined;
}
