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

// Test that changes in the style inspector are synchronized into the
// style editor.

const TESTCASE_URI = TEST_BASE_HTTP + "sync.html";

const expectedText = `
  body {
    border-width: 15px;
    /*! color: red; */
  }

  #testid {
    /*! font-size: 4em; */
  }
  `;

async function closeAndReopenToolbox() {
  await gDevTools.closeToolboxForTab(gBrowser.selectedTab);
  const { ui: newui } = await openStyleEditor();
  return newui;
}

/**
 * In this test, we are modifying rules via the inspector, which doesn't use STYLESHEET's onResourceUpdated event,
 * but the style editor do listen for these events. The issue is that the style editor triggers asynchronous updates
 * and new RDP requests which only happens randomly when the update notification happens late.
 * In order to prevent that, ensure waiting for all the updates notifications while doing the action in the inspector,
 * so that the style editor only gets STYLESHEET's available notification while opening.
 */
async function waitForNextStyleSheetResourceUpdate(inspector) {
  const { resourceCommand } = inspector.commands;

  const { promise, resolve } = Promise.withResolvers();
  const onAvailable = () => {};
  const onUpdated = () => {
    resourceCommand.unwatchResources([resourceCommand.TYPES.STYLESHEET], {
      onAvailable,
      onUpdated,
    });
    resolve();
  };
  await resourceCommand.watchResources([resourceCommand.TYPES.STYLESHEET], {
    onAvailable,
    onUpdated,
  });
  return { onResourceUpdated: promise };
}

add_task(async function () {
  await addTab(TESTCASE_URI);
  const { inspector, view } = await openRuleView();
  await selectNode("#testid", inspector);
  let ruleEditor = getRuleViewRuleEditorAt(view, 1);

  // Disable the "font-size" property.
  let { onResourceUpdated } =
    await waitForNextStyleSheetResourceUpdate(inspector);
  let propEditor = ruleEditor.rule.textProps[0].editor;
  let onModification = view.once("ruleview-changed");
  propEditor.enable.click();
  await onModification;
  await onResourceUpdated;

  // Disable the "color" property.  Note that this property is in a
  // rule that also contains a non-inherited property -- so this test
  // is also testing that property editing works properly in this
  // situation.
  ({ onResourceUpdated } =
    await waitForNextStyleSheetResourceUpdate(inspector));
  ruleEditor = getRuleViewRuleEditorAt(view, 2);
  propEditor = ruleEditor.rule.textProps[1].editor;
  onModification = view.once("ruleview-changed");
  propEditor.enable.click();
  await onModification;
  await onResourceUpdated;

  let { ui } = await openStyleEditor();

  let editor = await ui.editors[0].getSourceEditor();
  let text = editor.sourceEditor.getText();
  is(text, expectedText, "style inspector changes are synced");

  // Close and reopen the toolbox, to see that the edited text remains
  // available.
  ui = await closeAndReopenToolbox();
  editor = await ui.editors[0].getSourceEditor();
  text = editor.sourceEditor.getText();
  is(text, expectedText, "changes remain after close and reopen");

  // For the time being, the actor does not update the style's owning
  // node's textContent.  See bug 1205380.
  const textContent = await SpecialPowers.spawn(
    gBrowser.selectedBrowser,
    [],
    async function () {
      return content.document.querySelector("style").textContent;
    }
  );

  isnot(textContent, expectedText, "changes not written back to style node");
});
