import * as chai from "chai";
import { chaiDom } from "../../../util/chai-dom.mjs";
import { initJSDOM } from "../../../util/jsdom.mjs";

let expect = chai.expect;
chai.use(chaiDom);

let ChoiceCards;

function waitForCondition(check, { timeout = 4000, interval = 25 } = {}) {
  return new Promise((resolve, reject) => {
    const start = Date.now();

    const poll = () => {
      try {
        if (check()) {
          resolve();
          return;
        }
      } catch (e) {
        reject(e);
        return;
      }

      if (Date.now() - start >= timeout) {
        reject(new Error("Timed out while waiting for test condition."));
        return;
      }

      setTimeout(poll, interval);
    };

    poll();
  });
}

describe("ChoiceCards", function () {
  before(function (done) {
    initJSDOM()
      .then(() => {
        return import("element-internals-polyfill");
      })
      .then(() => {
        return import("../../../../source/components/form/form.mjs");
      })
      .then(() => {
        return import("../../../../source/components/form/choice-cards.mjs");
      })
      .then((m) => {
        ChoiceCards = m["ChoiceCards"];
        done();
      })
      .catch((e) => done(e));
  });

  beforeEach(() => {
    document.getElementById("mocks").innerHTML = '<div id="test"></div>';
  });

  afterEach(() => {
    document.getElementById("mocks").innerHTML = "";
  });

  it("creates a custom element instance", function () {
    expect(document.createElement("monster-choice-cards")).is.instanceof(
      ChoiceCards,
    );
  });

  it("renders choice cards from items", function () {
    const cards = document.createElement("monster-choice-cards");
    cards.setItems([
      { value: "assets", label: "Project assets" },
      { value: "api", label: "API collection" },
    ]);

    document.getElementById("test").appendChild(cards);

    const choices = cards.shadowRoot.querySelectorAll(
      '[data-monster-role="choice"]',
    );
    expect(choices.length).is.equal(2);
    expect(choices[0].textContent).contains("Project assets");
    expect(choices[1].textContent).contains("API collection");
  });

  it("renders custom card content from slots", function () {
    const cards = document.createElement("monster-choice-cards");
    cards.setItems([
      { value: "assets", label: "Project assets", contentSlot: "assets-card" },
      { value: "api", label: "API collection", contentSlot: "api-card" },
      { value: "manual", label: "Manual", contentSlot: "manual-card" },
    ]);

    const assets = document.createElement("span");
    assets.slot = "assets-card";
    assets.textContent = "Custom assets content";
    cards.appendChild(assets);

    document.getElementById("test").appendChild(cards);

    const choices = cards.shadowRoot.querySelectorAll(
      '[data-monster-role="choice"]',
    );
    expect(choices.length).is.equal(3);
    expect(
      cards.shadowRoot
        .querySelector('[data-choice-value="assets"] slot')
        .getAttribute("name"),
    ).is.equal("assets-card");
  });

  it("selects a card and emits change events", function (done) {
    const cards = document.createElement("monster-choice-cards");
    cards.setItems([
      { value: "assets", label: "Project assets" },
      { value: "api", label: "API collection" },
    ]);

    cards.addEventListener("monster-change", (event) => {
      expect(event.detail.value).is.equal("api");
      expect(cards.value).is.equal("api");
      expect(
        cards.shadowRoot
          .querySelector('[data-choice-value="api"]')
          .getAttribute("aria-checked"),
      ).is.equal("true");
      done();
    });

    document.getElementById("test").appendChild(cards);
    cards.shadowRoot.querySelector('[data-choice-value="api"]').click();
  });

  it("reads from and writes back to a form datasource", async function () {
    this.timeout(6000);

    document.getElementById("test").innerHTML = `
      <monster-datasource-dom id="choice-ds">
        <script type="application/json">
          [
            {
              "source": "assets"
            }
          ]
        </script>
      </monster-datasource-dom>
      <monster-form
        id="choice-form"
        data-monster-option-datasource-selector="#choice-ds"
        data-monster-option-mapping-data=""
        data-monster-option-mapping-index="0"
      >
        <monster-choice-cards
          id="choice-source"
          data-monster-attributes="value path:data.source"
          data-monster-bind="path:data.source"
          data-monster-options='{
            "items": [
              { "value": "assets", "label": "Assets", "contentSlot": "assets-card" },
              { "value": "api", "label": "API", "contentSlot": "api-card" }
            ]
          }'
        >
          <span slot="assets-card">Assets</span>
          <span slot="api-card">API</span>
        </monster-choice-cards>
      </monster-form>
    `;

    const datasource = document.getElementById("choice-ds");
    const cards = document.getElementById("choice-source");

    await waitForCondition(() => cards.value === "assets");

    cards.select("api");
    await waitForCondition(() => datasource.data?.[0]?.source === "api");
  });

  it("does not select disabled items", function () {
    const cards = document.createElement("monster-choice-cards");
    cards.setItems([
      { value: "assets", label: "Project assets" },
      { value: "api", label: "API collection", disabled: true },
    ]);

    document.getElementById("test").appendChild(cards);
    cards.select("api");

    expect(cards.value).is.equal(null);
  });
});
