/* Any copyright is dedicated to the Public Domain.
   http://creativecommons.org/publicdomain/zero/1.0/ */

"use strict";

const TEST_PATH = getRootDirectory(gTestPath).replace(
  "chrome://mochitests/content",
  "https://example.org"
);

var MockFilePicker = SpecialPowers.MockFilePicker;
MockFilePicker.init(window);

registerCleanupFunction(async function () {
  info("Running the cleanup code");
  MockFilePicker.cleanup();
  if (gTestDir && gTestDir.exists()) {
    // On Windows, sometimes nsIFile.remove() throws, probably because we're
    // still writing to the directory we're trying to remove, despite
    // waiting for the download to complete. Just retry a bit later...
    let succeeded = false;
    while (!succeeded) {
      try {
        gTestDir.remove(true);
        succeeded = true;
      } catch (ex) {
        await new Promise(requestAnimationFrame);
      }
    }
  }
});

let gTestDir = null;

function createTemporarySaveDirectory() {
  var saveDir = Services.dirsvc.get("TmpD", Ci.nsIFile);
  saveDir.append("testsavedir");
  if (!saveDir.exists()) {
    info("create testsavedir!");
    saveDir.create(Ci.nsIFile.DIRECTORY_TYPE, 0o755);
  }
  info("return from createTempSaveDir: " + saveDir.path);
  return saveDir;
}

function expectedImageAcceptHeader() {
  if (Services.prefs.prefHasUserValue("image.http.accept")) {
    return Services.prefs.getCharPref("image.http.accept");
  }

  return (
    (Services.prefs.getBoolPref("image.avif.enabled") ? "image/avif," : "") +
    (Services.prefs.getBoolPref("image.jxl.enabled") ? "image/jxl," : "") +
    (Services.prefs.getBoolPref("image.webp.enabled") ? "image/webp," : "") +
    "*/*"
  );
}

add_task(async function test_image_download() {
  await BrowserTestUtils.withNewTab(TEST_PATH + "dummy.html", async browser => {
    // Add the image, and wait for it to load.
    await SpecialPowers.spawn(browser, [], async function () {
      let loc = content.document.location.href;
      let imgloc = new content.URL("dummy.png", loc);
      let img = content.document.createElement("img");
      img.src = imgloc;
      await new Promise(resolve => {
        img.onload = resolve;
        content.document.body.appendChild(img);
      });
    });
    gTestDir = createTemporarySaveDirectory();

    let destFile = gTestDir.clone();

    MockFilePicker.displayDirectory = gTestDir;
    let fileName;
    MockFilePicker.showCallback = function (fp) {
      info("showCallback");
      fileName = fp.defaultString;
      info("fileName: " + fileName);
      destFile.append(fileName);
      info("path: " + destFile.path);
      MockFilePicker.setFiles([destFile]);
      MockFilePicker.filterIndex = 0; // just save the file
      info("done showCallback");
    };
    let publicDownloads = await Downloads.getList(Downloads.PUBLIC);
    let downloadFinishedPromise = new Promise(resolve => {
      publicDownloads.addView({
        onDownloadChanged(download) {
          info("Download changed!");
          if (download.succeeded || download.error) {
            info("Download succeeded or errored");
            publicDownloads.removeView(this);
            publicDownloads.removeFinished();
            resolve(download);
          }
        },
      });
    });
    let httpOnModifyPromise = TestUtils.topicObserved(
      "http-on-modify-request",
      (s, t, d) => {
        let channel = s.QueryInterface(Ci.nsIChannel);
        let uri = channel.URI && channel.URI.spec;
        if (!uri.endsWith("dummy.png")) {
          info("Ignoring request for " + uri);
          return false;
        }
        ok(channel instanceof Ci.nsIHttpChannel, "Should be HTTP channel");
        channel.QueryInterface(Ci.nsIHttpChannel);
        is(
          channel.getRequestHeader("Accept"),
          expectedImageAcceptHeader(),
          "Header should be image header"
        );
        return true;
      }
    );
    // open the context menu.
    let popup = document.getElementById("contentAreaContextMenu");
    let popupShown = BrowserTestUtils.waitForEvent(popup, "popupshown");
    BrowserTestUtils.synthesizeMouseAtCenter(
      "img",
      { type: "contextmenu", button: 2 },
      browser
    );
    await popupShown;
    let popupHidden = BrowserTestUtils.waitForEvent(popup, "popuphidden");
    popup.activateItem(popup.querySelector("#context-saveimage"));
    await popupHidden;
    info("Context menu hidden, waiting for download to finish");
    let imageDownload = await downloadFinishedPromise;
    ok(imageDownload.succeeded, "Image should have downloaded successfully");
    info("Waiting for http request to complete.");
    // Ensure we got the http request:
    await httpOnModifyPromise;
  });
});