// Offscreen document: bridges Worker creation for Chrome MV3 service workers
// (Service workers cannot use `new Worker()` or `URL.createObjectURL`, so we handle both here)

let activeWorker = null;
let currentJobIsAudioOnly = false;

chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
  if (message.target !== 'offscreen') return;

  if (message.action === 'spawn_worker') {
    if (activeWorker) {
      activeWorker.terminate();
      activeWorker = null;
    }

    try {
      const worker = new Worker(
        new URL('./hls_worker_v2.js', import.meta.url),
        { type: 'module' }
      );
      activeWorker = worker;

      worker.onerror = (err) => {
        console.error("[Offscreen] Worker script error:", err);
        chrome.runtime.sendMessage({
          source: 'offscreen',
          type: 'worker_error',
          error: 'Worker Startup Failed. Check background console.'
        });
      };

      worker.onmessage = (e) => {
        if (e.data.type === 'complete_blob') {
          // In-memory fallback: create blob URL here to avoid serializing
          // large ArrayBuffers through chrome.runtime.sendMessage
          const isAudioOnly = e.data.isAudioOnly || currentJobIsAudioOnly;
          // Worker forwards outputFilename so the SABR vp9+opus .mkv container
          // keeps the matroska MIME (and ext, via background) on the Chrome
          // in-memory path — mirrors the OPFS create_blob_url branch below.
          const outputFilename = e.data.outputFilename || '';
          const outExt = (outputFilename.split('.').pop() || '').toLowerCase();
          const mimeType = isAudioOnly ? 'audio/mpeg' : (outExt === 'mkv' ? 'video/x-matroska' : 'video/mp4');
          const blob = new Blob([e.data.data], { type: mimeType });
          const blobUrl = URL.createObjectURL(blob);
          console.log(`[Offscreen] Created blob URL from in-memory fallback (${e.data.data.byteLength} bytes)`);
          setTimeout(() => URL.revokeObjectURL(blobUrl), 120000);

          chrome.runtime.sendMessage({
            source: 'offscreen',
            type: 'worker_message',
            data: { type: 'complete_blob_url', blobUrl, isAudioOnly, size: blob.size, outputFilename }
          });
        } else {
          chrome.runtime.sendMessage({
            source: 'offscreen',
            type: 'worker_message',
            data: e.data
          });
        }
      };

      sendResponse({ success: true });
    } catch (err) {
      sendResponse({ success: false, error: err.message });
    }
    return true;
  }

  if (message.action === 'post_to_worker') {
    if (activeWorker) {
      // Track isAudioOnly for blob creation in fallback path
      if (message.data && message.data.job && message.data.job.isAudioOnly !== undefined) {
        currentJobIsAudioOnly = message.data.job.isAudioOnly;
      }
      activeWorker.postMessage(message.data);
    }
    return false;
  }

  if (message.action === 'terminate_worker') {
    if (activeWorker) {
      activeWorker.terminate();
      activeWorker = null;
    }
    return false;
  }

  // Read OPFS file and create blob URL (URL.createObjectURL is not available in service workers)
  // The blob URL is sent back to background.js which calls chrome.downloads (not available here)
  if (message.action === 'create_blob_url') {
    (async () => {
      try {
        const { outputFilename, isAudioOnly } = message;
        console.log(`[Offscreen] Reading ${outputFilename} from OPFS...`);

        const opfsRoot = await navigator.storage.getDirectory();
        const fileHandle = await opfsRoot.getFileHandle(outputFilename);
        const file = await fileHandle.getFile();
        console.log(`[Offscreen] File size: ${file.size} bytes`);

        // SABR-forced videos mux to .mkv (vp9+opus). Set the matching MIME
        // so the blob URL type doesn't contradict the .mkv filename ext.
        const mimeType = isAudioOnly
          ? 'audio/mpeg'
          : (outputFilename.toLowerCase().endsWith('.mkv') ? 'video/x-matroska' : 'video/mp4');

        // Pass OPFS File straight to URL.createObjectURL — File is a Blob
        // subclass referencing OPFS bytes out-of-line, so we avoid the
        // Firefox 2 GB Blob-constructor ArrayBuffer cap that breaks on
        // long videos (e.g. 2+ h 1080p → ~2.3 GB).
        const typedFile = new File([file], outputFilename, { type: mimeType });
        const url = URL.createObjectURL(typedFile);
        console.log(`[Offscreen] Created Blob URL from OPFS File (${isAudioOnly ? 'MP3' : 'MP4'})`);

        // NOTE: do not remove OPFS entry or revoke the blob URL here. The
        // browser streams from the blob URL while chrome.downloads is still
        // writing to disk; deleting the OPFS file mid-stream interrupts the
        // transfer (shown as an exclamation mark on the entry in Firefox).
        // Background waits for downloads.onChanged → state=complete, then
        // sends 'cleanup_blob_url' back to us.
        sendResponse({ success: true, blobUrl: url, outputFilename, size: file.size });
      } catch (err) {
        console.error("[Offscreen] Blob creation error:", err);
        sendResponse({ success: false, error: err.message });
      }
    })();
    return true; // Keep channel open for async sendResponse
  }

  if (message.action === 'cleanup_blob_url') {
    (async () => {
      try {
        const { blobUrl, outputFilename } = message;
        if (blobUrl) URL.revokeObjectURL(blobUrl);
        if (outputFilename) {
          const opfsRoot = await navigator.storage.getDirectory();
          await opfsRoot.removeEntry(outputFilename).catch(() => { });
        }
        sendResponse({ success: true });
      } catch (e) {
        sendResponse({ success: false, error: e.message });
      }
    })();
    return true;
  }
});
