// yt-dlp lifecycle helpers: version check, GitHub-latest comparison, and
// multi-strategy auto-update. Self-contained — module-private memoization
// for the GitHub check (capped to once per 24h to avoid hammering the
// API).

import { execFile } from "child_process";
import { promisify } from "util";
import path from "path";
import fs from "fs/promises";

const execFileAsync = promisify(execFile);

let ytdlpVersion = null;
let ytdlpLastCheck = 0;
const UPDATE_CHECK_INTERVAL = 24 * 60 * 60 * 1000; // 24 hours

// ── Version + update-availability check ─────────────────────────────────────
// Returns `{ installed, version, updateAvailable, latestVersion }`.
// Suppresses errors — a missing yt-dlp returns `installed: false`, a
// failed GitHub call just leaves `latestVersion` as null. The GitHub
// fetch is rate-limited to once per 24h.
export async function checkYtdlp() {
  const info = { installed: false, version: null, updateAvailable: false, latestVersion: null };
  try {
    const { stdout } = await execFileAsync("yt-dlp", ["--version"]);
    info.installed = true;
    info.version = stdout.trim();
    ytdlpVersion = info.version;
  } catch {
    return info;
  }

  const now = Date.now();
  if (now - ytdlpLastCheck > UPDATE_CHECK_INTERVAL) {
    ytdlpLastCheck = now;
    try {
      const resp = await fetch("https://api.github.com/repos/yt-dlp/yt-dlp/releases/latest", {
        headers: { "Accept": "application/vnd.github.v3+json" },
        signal: AbortSignal.timeout(5000),
      });
      if (resp.ok) {
        const data = await resp.json();
        info.latestVersion = data.tag_name?.replace(/^v/, "") || null;
        if (info.latestVersion && info.version !== info.latestVersion) {
          info.updateAvailable = true;
        }
      }
    } catch {} // Network errors are fine, just skip the check
  }
  return info;
}

// ── Multi-strategy auto-update ──────────────────────────────────────────────
// Tries strategies in order until one works:
//   1. yt-dlp -U                 (built-in self-update, when permitted)
//   2. pip3/pip install -U       (containers, macOS)
//   3. brew upgrade yt-dlp       (macOS local dev)
//   4. Direct binary download    (StartOS fallback to /data/bin/)
//
// `dataDir` is needed only for strategy 4. Returns `{ success, message }`.
export async function autoUpdateYtdlp(dataDir) {
  console.log("  ↻  Updating yt-dlp...");

  // Strategy 1: yt-dlp's built-in self-update
  try {
    const { stdout } = await execFileAsync("yt-dlp", ["-U"], { timeout: 60000 });
    console.log(`  ${stdout.trim()}`);
    return { success: true, message: stdout.trim() };
  } catch {
    console.log("  …  Self-update failed, trying pip...");
  }

  // Strategy 2: pip3 / pip
  for (const pip of ["pip3", "pip"]) {
    try {
      await execFileAsync(pip, ["install", "-U", "yt-dlp"], { timeout: 120000 });
      console.log(`  ✓  Updated via ${pip}`);
      return { success: true, message: `Updated via ${pip}` };
    } catch {}
  }

  // Strategy 3: Homebrew (macOS local dev only)
  try {
    await execFileAsync("brew", ["upgrade", "yt-dlp"], { timeout: 120000 });
    console.log("  ✓  Updated via Homebrew");
    return { success: true, message: "Updated via Homebrew" };
  } catch {}

  // Strategy 4: Direct binary download to persistent storage (StartOS fallback)
  try {
    const binDir = path.join(dataDir, "bin");
    await fs.mkdir(binDir, { recursive: true });
    const binPath = path.join(binDir, "yt-dlp");
    console.log("  …  Trying direct binary download...");
    const { stdout } = await execFileAsync("sh", ["-c",
      `curl -L -o "${binPath}" "https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp" && chmod +x "${binPath}" && "${binPath}" --version`
    ], { timeout: 120000 });
    console.log(`  ✓  Downloaded yt-dlp binary: ${stdout.trim()}`);
    return { success: true, message: `Downloaded binary: ${stdout.trim()}` };
  } catch {
    console.log("  ✗  All update strategies failed");
    return { success: false, message: "Auto-update failed. Try updating manually from the StartOS Actions menu." };
  }
}
