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

"use strict";

const CSSCompleter = require("resource://devtools/client/shared/sourceeditor/css-autocompleter.js");

const CSS_URI =
  "http://mochi.test:8888/browser/devtools/client/shared/sourceeditor" +
  "/test/css_statemachine_testcases.css";
const TESTS_URI =
  "http://mochi.test:8888/browser/devtools/client" +
  "/shared/sourceeditor/test/css_autocompletion_tests.json";

const source = read(CSS_URI);
const { tests } = JSON.parse(read(TESTS_URI));

const TEST_URI =
  "data:text/html;charset=UTF-8," +
  encodeURIComponent(`
    <!DOCTYPE html>
    <html>
      <head>
        <title>CSS State machine tests.</title>
        <style>
          #progress {
            width: 500px; height: 30px;
            border: 1px solid black;
            position: relative
          }
          #progress div {
            width: 0%; height: 100%;
            background: green;
            position: absolute;
            z-index: -1; top: 0
          }
          #progress.failed div {
            background: red !important;
          }
          #progress.failed:after {
            content: 'Some tests failed';
            color: white
          }
          #progress:before {
            content: 'Running test ' attr(data-progress) ' of ${tests.length}';
              color: white;
              text-shadow: 0 0 2px darkgreen;
            }
        </style>
      </head>
      <body>
        <h2>State machine tests for CSS autocompleter.</h2><br>
        <div id='progress' data-progress='0'>
          <div></div>
        </div>
        <div id='devtools-menu' class='devtools-toolbarbutton'></div>
        <div id='devtools-toolbarbutton' class='devtools-menulist'></div>
        <div id='devtools-anotherone'></div>
        <div id='devtools-yetagain'></div>
        <div id='devtools-itjustgoeson'></div>
        <div id='devtools-okstopitnow'></div>
        <div class='hidden-labels-box devtools-toolbarbutton devtools-menulist'></div>
        <div class='devtools-menulist'></div>
        <div class='devtools-menulist'></div>",
        <tabs class='devtools-toolbarbutton'><tab></tab><tab></tab><tab></tab></tabs><tabs></tabs>
        <button class='category-name visible'></button>
        <div class='devtools-toolbarbutton' label='true'>
        <hbox class='toolbarbutton-menubutton-button'></hbox></div>
      </body>
    </html>
  `);

let browser;
let index = 0;
let completer = null;
let inspector;

add_task(async function test() {
  const tab = await addTab(TEST_URI);
  browser = tab.linkedBrowser;
  await runTests();
  browser = null;
  gBrowser.removeCurrentTab();
});

async function runTests() {
  const target = await createAndAttachTargetForTab(gBrowser.selectedTab);
  inspector = await target.getFront("inspector");
  const walker = inspector.walker;
  const cssPropertiesFront = await target.getFront("cssProperties");
  completer = new CSSCompleter({
    walker,
    cssProperties: cssPropertiesFront.cssProperties,
  });
  await checkStateAndMoveOn();
  await completer.walker.release();
  await target.destroy();
  inspector = null;
  completer = null;
}

async function checkStateAndMoveOn() {
  if (index == tests.length) {
    return;
  }

  const [lineCh, baseExpectedSuggestions, prefSuggestions] = tests[index];
  const [line, ch] = lineCh;

  let expectedSuggestions;
  if (prefSuggestions) {
    const additional = [];
    for (const [pref, property] of prefSuggestions) {
      if (SpecialPowers.getBoolPref(pref)) {
        additional.push(property);
      }
    }
    expectedSuggestions = baseExpectedSuggestions.concat(additional);
    expectedSuggestions.sort();
  } else {
    expectedSuggestions = baseExpectedSuggestions;
  }

  ++index;
  await SpecialPowers.spawn(
    browser,
    [[index, tests.length]],
    function ([idx, len]) {
      const progress = content.document.getElementById("progress");
      const progressDiv = content.document.querySelector("#progress > div");
      progress.dataset.progress = idx;
      progressDiv.style.width = (100 * idx) / len + "%";
    }
  );

  const actualSuggestions = await completer.complete(limit(source, lineCh), {
    line,
    ch,
  });
  await checkState(expectedSuggestions, actualSuggestions);
  await checkStateAndMoveOn();
}

async function checkState(expected, actual) {
  if (expected.length != actual.length) {
    ok(
      false,
      "Number of suggestions did not match up for state " +
        index +
        ". Expected: " +
        expected.length +
        ", Actual: " +
        actual.length
    );
    await SpecialPowers.spawn(browser, [], function () {
      const progress = content.document.getElementById("progress");
      progress.classList.add("failed");
    });
    return;
  }

  for (let i = 0; i < actual.length; i++) {
    if (expected[i] != actual[i].label) {
      ok(
        false,
        "Suggestion " +
          i +
          " of state " +
          index +
          " did not match up" +
          ". Expected: " +
          expected[i] +
          ". Actual: " +
          actual[i].label
      );
      return;
    }
  }
  ok(true, "Test " + index + " passed. ");
}
