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

"use strict";

/**
 * Tests responsive mode links for `@media` sidebar width and height related
 * conditions.
 */

loader.lazyRequireGetter(
  this,
  "ResponsiveUIManager",
  "resource://devtools/client/responsive/manager.js"
);

const TESTCASE_URI = TEST_BASE_HTTPS + "media-rules.html";
const responsiveModeToggleClass = ".media-responsive-mode-toggle";

add_task(async function () {
  // ensure that original RDM size is big enough so it doesn't match the
  // media queries by default.
  await pushPref("devtools.responsive.viewport.width", 1000);
  await pushPref("devtools.responsive.viewport.height", 1000);

  const { ui } = await openStyleEditorForURL(TESTCASE_URI);

  const editor = ui.editors[1];
  await openEditor(editor);

  const tab = gBrowser.selectedTab;
  testNumberOfLinks(editor);
  await testMediaLink(editor, tab, ui, 2, "width", 550);
  await testMediaLink(editor, tab, ui, 3, "height", 300);

  const onMediaChange = waitForManyEvents(ui, 1000);
  await closeRDM(tab);

  info("Wait for at-rules-list-changed events to settle on StyleEditorUI");
  await onMediaChange;
  doFinalChecks(editor);
});

function testNumberOfLinks(editor) {
  const sidebar = editor.details.querySelector(".stylesheet-sidebar");
  const conditions = sidebar.querySelectorAll(".at-rule-condition");

  info("Testing if media rules have the appropriate number of links");
  ok(
    !conditions[0].querySelector(responsiveModeToggleClass),
    "There should be no links in the first media rule."
  );
  ok(
    !conditions[1].querySelector(responsiveModeToggleClass),
    "There should be no links in the second media rule."
  );
  ok(
    conditions[2].querySelector(responsiveModeToggleClass),
    "There should be 1 responsive mode link in the media rule"
  );
  is(
    conditions[3].querySelectorAll(responsiveModeToggleClass).length,
    2,
    "There should be 2 responsive mode links in the media rule"
  );
}

async function testMediaLink(editor, tab, ui, itemIndex, type, value) {
  const sidebar = editor.details.querySelector(".stylesheet-sidebar");
  const conditions = sidebar.querySelectorAll(".at-rule-condition");
  const onRDMOpened = once(ui, "responsive-mode-opened");

  ok(
    sidebar
      .querySelectorAll(".at-rule-condition")
      [itemIndex].classList.contains("media-condition-unmatched"),
    `The ${type} condition is not matched when not in responsive mode`
  );

  info("Launching responsive mode");
  conditions[itemIndex].querySelector(responsiveModeToggleClass).click();
  await onRDMOpened;
  const rdmUI = ResponsiveUIManager.getResponsiveUIForTab(tab);
  await waitForResizeTo(rdmUI, type, value);
  rdmUI.transitionsEnabled = false;

  info("Wait for RDM ui to be fully loaded");
  await waitForRDMLoaded(rdmUI);

  // Ensure that the content has reflowed, which will ensure that all the
  // element classes are reported correctly.
  await promiseContentReflow(rdmUI);

  ok(
    ResponsiveUIManager.isActiveForTab(tab),
    "Responsive mode should be active."
  );
  await waitFor(() => {
    const el = sidebar.querySelectorAll(".at-rule-condition")[itemIndex];
    return !el.classList.contains("media-condition-unmatched");
  });
  ok(true, "media rule should now be matched after responsive mode is active");

  const dimension = (await getSizing(rdmUI))[type];
  is(dimension, value, `${type} should be properly set.`);
}

function doFinalChecks(editor) {
  const sidebar = editor.details.querySelector(".stylesheet-sidebar");
  let conditions = sidebar.querySelectorAll(".at-rule-condition");
  conditions = sidebar.querySelectorAll(".at-rule-condition");
  ok(
    conditions[2].classList.contains("media-condition-unmatched"),
    "The width condition should now be unmatched"
  );
  ok(
    conditions[3].classList.contains("media-condition-unmatched"),
    "The height condition should now be unmatched"
  );
}

/* Helpers */
function waitForResizeTo(rdmUI, type, value) {
  return new Promise(resolve => {
    const onResize = data => {
      if (data[type] != value) {
        return;
      }
      rdmUI.off("content-resize", onResize);
      info(`Got content-resize to a ${type} of ${value}`);
      resolve();
    };
    info(`Waiting for content-resize to a ${type} of ${value}`);
    rdmUI.on("content-resize", onResize);
  });
}

function promiseContentReflow(ui) {
  return SpecialPowers.spawn(ui.getViewportBrowser(), [], async function () {
    return new Promise(resolve => {
      content.window.requestAnimationFrame(() => {
        content.window.requestAnimationFrame(resolve);
      });
    });
  });
}

async function getSizing(rdmUI) {
  const browser = rdmUI.getViewportBrowser();
  const sizing = await SpecialPowers.spawn(browser, [], async function () {
    return {
      width: content.innerWidth,
      height: content.innerHeight,
    };
  });
  return sizing;
}

function openEditor(editor) {
  getLinkFor(editor).click();

  return editor.getSourceEditor();
}

function getLinkFor(editor) {
  return editor.summary.querySelector(".stylesheet-name");
}
