export function collectTimelineMediaFiles(tracks = []) {
  const files = new Set();
  for (const track of tracks) {
    if (track?.type !== 'media') continue;
    for (const segment of track.segments || []) {
      const file = String(segment?.imageFile || '').trim();
      if (file) files.add(file);
    }
  }
  return [...files];
}

export function selectPlayableVideoBuffer(buffer, requestedBuffer) {
  const useSecondary = requestedBuffer === 'B'
    && buffer?.readyB
    && buffer.videoB;
  const activeBuffer = useSecondary ? 'B' : 'A';
  return {
    activeBuffer,
    activeVideo: activeBuffer === 'A' ? buffer?.videoA : buffer?.videoB,
    inactiveVideo: activeBuffer === 'A' ? buffer?.videoB : buffer?.videoA,
  };
}

function waitWithTimeout(promise, timeoutMs, filename) {
  if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) return promise;
  let timeout;
  return Promise.race([
    promise,
    new Promise((_, reject) => {
      timeout = setTimeout(
        () => reject(new Error(`Timed out while preloading ${filename}`)),
        timeoutMs,
      );
    }),
  ]).finally(() => clearTimeout(timeout));
}

export async function preloadTimelineMedia(
  tracks,
  loadMedia,
  {
    timeoutMs = 60000,
    onProgress = () => {},
  } = {},
) {
  const files = collectTimelineMediaFiles(tracks);
  let loaded = 0;

  const results = await Promise.all(files.map(async filename => {
    try {
      await waitWithTimeout(
        Promise.resolve().then(() => loadMedia(filename)),
        timeoutMs,
        filename,
      );
      loaded += 1;
      onProgress({ filename, loaded, total: files.length, ok: true });
      return null;
    } catch (error) {
      loaded += 1;
      onProgress({ filename, loaded, total: files.length, ok: false, error });
      return { filename, error };
    }
  }));

  return {
    total: files.length,
    loaded: files.length - results.filter(Boolean).length,
    failed: results.filter(Boolean),
  };
}
