require("../__util__/test-init");
var AsyncVDOMBuilder = require("marko/runtime/vdom/AsyncVDOMBuilder");
var VElement = require("marko/runtime/vdom/VElement");
var expect = require("chai").expect;

function getChildNodes(parentNode) {
  var childNodes = [];

  var curChild = parentNode.___firstChild;
  while (curChild) {
    childNodes.push(curChild);
    curChild = curChild.___nextSibling;
  }

  return childNodes;
}
describe("AsyncVDOMBuilder", function() {
  it("sync", function() {
    var out = new AsyncVDOMBuilder();
    out.element("div", {}, 0);
    var tree = out.___getOutput();
    expect(getChildNodes(tree).length).to.equal(1);
  });

  it("end, then listen for finish", function(done) {
    var out = new AsyncVDOMBuilder();
    out.element("div", {}, 0);
    out.end();
    out.on("finish", function(result) {
      expect(getChildNodes(result.getOutput()).length).to.equal(1);
      done();
    });
  });

  it("async", function(done) {
    var out = new AsyncVDOMBuilder();
    out.element("div", {}, 0);
    var asyncOut = out.beginAsync();

    setTimeout(function() {
      asyncOut.element("span", {}, 0);
      asyncOut.end();
    }, 10);

    out.element("section", {}, 0);

    out.end();
    out.on("finish", function(result) {
      var tree = result.getOutput();
      expect(getChildNodes(tree).length).to.equal(3);
      expect(tree.___firstChild.___nodeName).to.equal("div");
      expect(tree.___firstChild.___nextSibling.___nodeName).to.equal("span");
      expect(
        tree.___firstChild.___nextSibling.___nextSibling.___nodeName
      ).to.equal("section");
      done();
    });
  });

  it("promise", function(done) {
    const out = new AsyncVDOMBuilder();
    out.element("div", {}, 0);
    out
      .end()
      .then(result => {
        expect(getChildNodes(result.getOutput()).length).to.equal(1);
        done();
      })
      .catch(done);
  });

  it("async flush", function(done) {
    var out = new AsyncVDOMBuilder();
    out.on("update", function(result) {
      expect(getChildNodes(result.getOutput()).length).to.equal(1);
    });
    out.once("finish", function(result) {
      expect(getChildNodes(result.getOutput()).length).to.equal(2);
      done();
    });

    out.element("div", {}, 0);
    out.flush();

    var asyncOut = out.beginAsync();

    setTimeout(function() {
      asyncOut.element("span", {}, 0);
      asyncOut.end();
    }, 10);

    out.end();
  });

  it("for loop", function(done) {
    var out = new AsyncVDOMBuilder();
    out.once("finish", function(result) {
      var tree = result.getOutput();
      var childNodes = getChildNodes(tree);
      var header = childNodes[0];
      var list = childNodes[1];
      var paragraph = childNodes[2];
      expect(header.___nodeName).to.equal("h1");
      expect(list.___nodeName).to.equal("ul");
      expect(getChildNodes(list).length).to.equal(10);
      expect(paragraph.___nodeName).to.equal("p");
      done();
    });

    out.element("h1", {}, 0);

    out.beginElement("ul", {});

    for (var i = 0; i < 10; i++) {
      out.element("li", {}, 1).t(i);
    }

    out.endElement();

    out.element("p", {}, 0);

    out.end();
  });

  it("staticNode, comment", function(done) {
    var staticNode = new VElement("div", {}, 0, "f891ea3");
    var out = new AsyncVDOMBuilder();

    out.node(staticNode);
    out.text("Hello <em>World</em>");
    out.end();

    out.once("finish", function(result) {
      var tree = result.getOutput();
      var childNodes = getChildNodes(tree);
      expect(childNodes[0].___nodeName).to.equal("div");
      expect(childNodes[1].___nodeValue).to.equal("Hello <em>World</em>");
      done();
    });
  });

  // it('should handle timeouts correctly');
  //
  // it('should handle sync errors correctly');
  //
  // it('should handle timeout errors correctly');
  //
  // it('should avoid writes after end');
  //
  // it('globals');
});
