import fs from "node:fs/promises";
import path from "node:path";
import { ColibriManifest } from "../schemas/manifest.js";

async function downloadFile(url: string, destination: string): Promise<void> {
  const response = await fetch(url);

  if (!response.ok) {
    throw new Error(`Failed to download ${url}: HTTP ${response.status}`);
  }

  const buffer = Buffer.from(await response.arrayBuffer());
  await fs.mkdir(path.dirname(destination), { recursive: true });
  await fs.writeFile(destination, buffer);
}

function extensionFromUrl(url: string, fallback: string): string {
  try {
    const pathname = new URL(url).pathname;
    const ext = path.extname(pathname);
    return ext !== "" ? ext : fallback;
  } catch {
    return fallback;
  }
}

export type DownloadedAssets = {
  voFile?: string;
  musicFile?: string;
  screenRecordingFile?: string;
  brollFiles: Record<string, string>;
};

export async function downloadManifestAssets(
  manifest: ColibriManifest,
  workDir: string,
): Promise<DownloadedAssets> {
  await fs.mkdir(workDir, { recursive: true });

  const result: DownloadedAssets = { brollFiles: {} };

  if (manifest.vo_url) {
    const file = path.join(workDir, `vo${extensionFromUrl(manifest.vo_url, ".mp3")}`);
    await downloadFile(manifest.vo_url, file);
    result.voFile = file;
  }

  if (manifest.music_url) {
    const file = path.join(workDir, `music${extensionFromUrl(manifest.music_url, ".mp3")}`);
    await downloadFile(manifest.music_url, file);
    result.musicFile = file;
  }

  if (manifest.screen_recording_url) {
    const file = path.join(
      workDir,
      `screen-recording${extensionFromUrl(manifest.screen_recording_url, ".mp4")}`,
    );
    await downloadFile(manifest.screen_recording_url, file);
    result.screenRecordingFile = file;
  }

  for (const clip of manifest.broll_clips ?? []) {
    if (!clip.url || !clip.scene_id) {
      continue;
    }

    const file = path.join(
      workDir,
      `broll-${clip.scene_id}${extensionFromUrl(clip.url, ".mp4")}`,
    );
    await downloadFile(clip.url, file);
    result.brollFiles[clip.scene_id] = file;
  }

  return result;
}

export async function removeWorkDir(workDir: string): Promise<void> {
  await fs.rm(workDir, { recursive: true, force: true });
}
