/* FutureMedia — downloader.js
 *
 * Thin wrapper around yt-dlp (via the `yt-dlp-exec` npm package), which does
 * the actual platform-specific extraction work. yt-dlp is a well-maintained
 * open-source project — this module just shapes its output for our API and
 * reports progress back to the caller.
 *
 * IMPORTANT: only download content you own, that's in the public domain, or
 * that you otherwise have the right to save. Respect each platform's terms
 * of service and applicable copyright law.
 */

const path = require('path');
const fs = require('fs');
const ytdlp = require('yt-dlp-exec');
const config = require('./config.json');

const DOWNLOADS_DIR = path.resolve(__dirname, config.downloadsFolder);
const LOGS_DIR = path.resolve(__dirname, config.logsFolder);

for (const dir of [DOWNLOADS_DIR, LOGS_DIR]) {
  if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
}

function log(line) {
  const stamp = new Date().toISOString();
  fs.appendFileSync(path.join(LOGS_DIR, 'downloads.log'), `[${stamp}] ${line}\n`);
}

/** Fetch metadata for a URL without downloading it. */
async function analyze(url) {
  const info = await ytdlp(url, {
    dumpSingleJson: true,
    noWarnings: true,
    noCheckCertificates: true,
    preferFreeFormats: true,
  });

  const bestFormat = (info.formats || [])
    .filter((f) => f.vcodec !== 'none')
    .sort((a, b) => (b.height || 0) - (a.height || 0))[0];

  return {
    title: info.title || 'media',
    platform: info.extractor_key || info.extractor || 'Unknown',
    duration: info.duration || 0,
    size: bestFormat && bestFormat.filesize
      ? `${(bestFormat.filesize / (1024 * 1024)).toFixed(1)} MB`
      : 'N/A',
    quality: bestFormat && bestFormat.height ? `${bestFormat.height}p` : 'Best',
    qualities: [...new Set((info.formats || []).map((f) => f.height).filter(Boolean))]
      .sort((a, b) => b - a)
      .map((h) => `${h}p`),
    thumbnail: info.thumbnail || null,
  };
}

/**
 * Download media to disk. Calls onProgress({ percent, speed, eta }) as
 * yt-dlp reports progress on stderr. Resolves with the resulting filename
 * (relative to DOWNLOADS_DIR) so the caller can serve it back to the client.
 */
function download(url, { type = 'video', quality = 'best' } = {}, onProgress) {
  return new Promise((resolve, reject) => {
    const outputTemplate = path.join(DOWNLOADS_DIR, config.filenameFormat);
    const startedAt = Date.now();

    const args = {
      output: outputTemplate,
      noWarnings: true,
      noCheckCertificates: true,
    };

    if (type === 'audio') {
      args.extractAudio = true;
      args.audioFormat = 'mp3';
      args.format = 'bestaudio';
    } else {
      args.format = quality === 'best'
        ? 'bestvideo+bestaudio/best'
        : `bestvideo[height<=${parseInt(quality, 10)}]+bestaudio/best`;
    }

    const subprocess = ytdlp.exec(url, args);

    subprocess.stderr?.on('data', (chunk) => {
      const text = chunk.toString();
      const match = text.match(/(\d+(?:\.\d+)?)%.*?(\d+(?:\.\d+)?\w+\/s).*?ETA\s+(\S+)/);
      if (match && onProgress) {
        onProgress({ percent: parseFloat(match[1]), speed: match[2], eta: match[3] });
      }
    });

    subprocess.on('close', (code) => {
      if (code !== 0) {
        log(`FAIL ${url} (${type}, ${quality}) — exit code ${code}`);
        reject(new Error(`yt-dlp exited with code ${code}`));
        return;
      }

      // Find the file yt-dlp just wrote (newest file created after we started).
      const newest = fs.readdirSync(DOWNLOADS_DIR)
        .map((name) => ({ name, mtime: fs.statSync(path.join(DOWNLOADS_DIR, name)).mtimeMs }))
        .filter((f) => f.mtime >= startedAt - 1000)
        .sort((a, b) => b.mtime - a.mtime)[0];

      if (!newest) {
        reject(new Error('Download finished but the output file was not found.'));
        return;
      }

      log(`OK   ${url} (${type}, ${quality}) → ${newest.name}`);
      resolve({ success: true, filename: newest.name });
    });

    subprocess.on('error', (err) => {
      log(`ERROR ${url} — ${err.message}`);
      reject(err);
    });
  });
}

module.exports = { analyze, download, DOWNLOADS_DIR };
