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

"use strict";

// Test that background-image URLs have image preview tooltips in the rule-view
// and computed-view

const TEST_URI = `
  <style type="text/css">
    body {
      padding: 1em;
      background-image: url(data:image/png;base64, );
      background-repeat: repeat-y;
      background-position: right top;
    }
    .test-element {
      font-family: verdana;
      color: #333;
      background: url(chrome://global/skin/icons/help.svg) no-repeat left center;
      padding-left: 70px;
    }
  </style>
  <div class="test-element">test element</div>
`;

add_task(async function () {
  await addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
  let { inspector, view } = await openRuleView();

  info("Testing the background-image property on the body rule");
  await testBodyRuleView(view);

  info("Selecting the test div node");
  await selectNode(".test-element", inspector);
  info("Testing the the background property on the .test-element rule");
  await testDivRuleView(view);

  info(
    "Testing that image preview tooltips show even when there are " +
      "fields being edited"
  );
  await testTooltipAppearsEvenInEditMode(view);

  info("Switching over to the computed-view");
  const onComputedViewReady = inspector.once("computed-view-refreshed");
  view = selectComputedView(inspector);
  await onComputedViewReady;

  info("Testing that the background-image computed style has a tooltip too");
  await testComputedView(view);
});

async function testBodyRuleView(view) {
  info("Testing tooltips in the rule view");

  // XXX we have an intermittent here (Bug 1743594) where the rule view is still empty
  // at this point. We're currently investigating what's going on and a proper way to
  // wait in openRuleView, but for now, let's fix the intermittent by waiting until the
  // rule view has the expected content.
  const property = await waitFor(() =>
    getRuleViewProperty(view, "body", "background-image")
  );

  // Get the background-image property inside the rule view
  const { valueSpan } = property;
  const uriSpan = valueSpan.querySelector(".theme-link");

  const previewTooltip = await assertShowPreviewTooltip(view, uriSpan);

  const images = previewTooltip.panel.getElementsByTagName("img");
  is(images.length, 1, "Tooltip contains an image");
  const imgSrc = images[0].getAttribute("src");
  ok(
    imgSrc.includes("iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHe"),
    "The image URL seems fine"
  );

  await assertTooltipHiddenOnMouseOut(previewTooltip, uriSpan);

  info(
    "Check that middle-clicking on the link opens a new tab in the background"
  );
  let onTabOpen = BrowserTestUtils.waitForNewTab(
    gBrowser,
    imgSrc,
    // waitForLoad
    true
  );
  uriSpan.scrollIntoView();
  // uriSpan is an multi-line inline element, and since synthesizeMouse only get the
  // bounding rect, we might not click on the right place.
  // So here, use synthesizeMouseAtPoint and pass it the first quad position
  const uriSpanQuad = uriSpan.getBoxQuads()[0];
  EventUtils.synthesizeMouseAtPoint(
    uriSpanQuad.p1.x + 2,
    uriSpanQuad.p1.y + 2,
    {
      button: 1,
    },
    uriSpan.ownerGlobal
  );
  let tab = await onTabOpen;
  is(
    tab.selected,
    false,
    "Tab was opened in the background with a middle click"
  );
  await removeTab(tab);

  info(
    "Check that ctrl/cmd clicking on the link opens a new tab in the background"
  );
  onTabOpen = BrowserTestUtils.waitForNewTab(
    gBrowser,
    imgSrc,
    // waitForLoad
    true
  );
  EventUtils.synthesizeMouseAtPoint(
    uriSpanQuad.p1.x + 2,
    uriSpanQuad.p1.y + 2,
    {
      button: 1,
      [Services.appinfo.OS === "Darwin" ? "metaKey" : "ctrlKey"]: true,
    },
    uriSpan.ownerGlobal
  );
  tab = await onTabOpen;
  is(
    tab.selected,
    false,
    "Tab was opened in the background with ctrl/cmd + click"
  );
  await removeTab(tab);

  info("Check that clicking on the link opens a new tab in the foreground");
  onTabOpen = BrowserTestUtils.waitForNewTab(
    gBrowser,
    imgSrc,
    // waitForLoad
    true
  );
  EventUtils.synthesizeMouseAtPoint(
    uriSpanQuad.p1.x + 2,
    uriSpanQuad.p1.y + 2,
    {},
    uriSpan.ownerGlobal
  );
  tab = await onTabOpen;
  is(
    tab.selected,
    true,
    "Tab was opened in the foreground when clicking on the link"
  );
  await removeTab(tab);
}

async function testDivRuleView(view) {
  // Get the background property inside the rule view
  const { valueSpan } = getRuleViewProperty(
    view,
    ".test-element",
    "background"
  );
  const uriSpan = valueSpan.querySelector(".theme-link");

  const previewTooltip = await assertShowPreviewTooltip(view, uriSpan);

  const images = previewTooltip.panel.getElementsByTagName("img");
  is(images.length, 1, "Tooltip contains an image");
  ok(
    images[0].getAttribute("src").startsWith("data:"),
    "Tooltip contains a data-uri image as expected"
  );

  await assertTooltipHiddenOnMouseOut(previewTooltip, uriSpan);
}

async function testTooltipAppearsEvenInEditMode(view) {
  info("Switching to edit mode in the rule view");
  const editor = await turnToEditMode(view);

  info("Now trying to show the preview tooltip");
  const { valueSpan } = getRuleViewProperty(
    view,
    ".test-element",
    "background"
  );
  const uriSpan = valueSpan.querySelector(".theme-link");

  const previewTooltip = await assertShowPreviewTooltip(view, uriSpan);

  is(
    view.styleDocument.activeElement,
    editor.input,
    "Tooltip was shown in edit mode, and inplace-editor still focused"
  );

  await assertTooltipHiddenOnMouseOut(previewTooltip, uriSpan);
}

function turnToEditMode(ruleView) {
  const brace = ruleView.styleDocument.querySelector(".ruleview-ruleclose");
  return focusEditableField(ruleView, brace);
}

async function testComputedView(view) {
  const { valueSpan } = getComputedViewProperty(view, "background-image");
  const uriSpan = valueSpan.querySelector(".theme-link");

  // Scroll to ensure the line is visible as we see the box model by default
  valueSpan.scrollIntoView();

  const previewTooltip = await assertShowPreviewTooltip(view, uriSpan);

  const images = previewTooltip.panel.getElementsByTagName("img");
  is(images.length, 1, "Tooltip contains an image");

  ok(
    images[0].getAttribute("src").startsWith("data:"),
    "Tooltip contains a data-uri in the computed-view too"
  );

  await assertTooltipHiddenOnMouseOut(previewTooltip, uriSpan);
}
