/*! Copyright 2026 Fonticons, Inc. - https://webawesome.com/license */
import { aTimeout, expect } from "@open-wc/testing";
import { html } from "lit";
import { html as staticHTML, unsafeStatic } from "lit/static-html.js";
import { fixtures } from "./fixture.js";
import { clickOnElement } from "./pointer-utilities.js";
function runFormControlBaseTests(tagNameOrConfig) {
  const isStringArg = typeof tagNameOrConfig === "string";
  const tagName = isStringArg ? tagNameOrConfig : tagNameOrConfig.tagName;
  const init = isStringArg || !tagNameOrConfig.init ? null : tagNameOrConfig.init || null;
  const displayName = isStringArg ? tagName : `${tagName} (${tagNameOrConfig.variantName})`;
  const renderControl = (fixtureType) => async () => {
    const controlFn = createFormControl(fixtureType);
    const control = await controlFn(tagName);
    init?.(control);
    return control;
  };
  runAllValidityTests(tagName, displayName, renderControl);
}
function runAllValidityTests(tagName, displayName, renderControl) {
  describe(`Form validity base test for ${displayName}`, () => {
    for (const fixture of fixtures) {
      describe(`with ${fixture.type} rendering`, () => {
        const createControl = renderControl(fixture);
        let mode = "standard";
        before(async () => {
          mode = getMode(await createControl());
        });
        if (mode === "slButtonOfTypeButton") {
          runSpecialTests_slButtonOfTypeButton(createControl);
        } else if (mode === "slButtonWithHRef") {
          runSpecialTests_slButtonWithHref(createControl);
        } else {
          runSpecialTests_standard(createControl);
        }
        it("should have a property `validity` of type `object`", async () => {
          const control = await createControl();
          expect(control).satisfy(() => control.validity !== null && typeof control.validity === "object");
        });
        it("should have a property `validationMessage` of type `string`", async () => {
          const control = await createControl();
          expect(control).satisfy(() => typeof control.validationMessage === "string");
        });
        it("should implement method `checkValidity`", async () => {
          const control = await createControl();
          expect(control).satisfies(() => typeof control.checkValidity === "function");
        });
        it("should implement method `setCustomValidity`", async () => {
          const control = await createControl();
          expect(control).satisfies(() => typeof control.setCustomValidity === "function");
        });
        it("should implement method `reportValidity`", async () => {
          const control = await createControl();
          expect(control).satisfies(() => typeof control.reportValidity === "function");
        });
        it("should be valid initially", async () => {
          const control = await createControl();
          expect(control.validity.valid).to.equal(true);
        });
        it("should make sure that calling `.checkValidity()` will return `true` when valid", async () => {
          const control = await createControl();
          expect(control.checkValidity()).to.equal(true);
        });
        it.skip("should make sure that calling `.reportValidity()` will return `true` when valid", async () => {
          const control = await createControl();
          expect(control.reportValidity()).to.equal(true);
          await clickOnElement(document.body);
          await aTimeout(100);
        });
        it("should not emit an `wa-invalid` event when `.checkValidity()` is called while valid", async () => {
          const control = await createControl();
          const emittedEvents = await checkEventEmissions(control, "wa-invalid", () => control.checkValidity());
          expect(emittedEvents.length).to.equal(0);
        });
        it("should not emit an `wa-invalid` event when `.reportValidity()` is called while valid", async () => {
          const control = await createControl();
          const emittedEvents = await checkEventEmissions(control, "wa-invalid", () => control.reportValidity());
          expect(emittedEvents.length).to.equal(0);
        });
        if (tagName !== "wa-radio-group") {
          it("should not emit an `wa-invalid` event when `.checkValidity()` is called in custom error case while disabled", async () => {
            const control = await createControl();
            control.setCustomValidity("error");
            control.disabled = true;
            await control.updateComplete;
            const emittedEvents = await checkEventEmissions(control, "wa-invalid", () => control.checkValidity());
            expect(emittedEvents.length).to.equal(0);
          });
          it("should not emit an `wa-invalid` event when `.reportValidity()` is called in custom error case while disabled", async () => {
            const control = await createControl();
            control.setCustomValidity("error");
            control.disabled = true;
            await control.updateComplete;
            const emittedEvents = await checkEventEmissions(control, "wa-invalid", () => control.reportValidity());
            expect(emittedEvents.length).to.equal(0);
          });
          it("Should find the correct form when given a form property", async () => {
            const formId = "test-form";
            const form = await fixture(html`<form id="${formId}"></form>`);
            const control = await createControl();
            expect(control.getForm()).to.equal(null);
            control.form = "test-form";
            await control.updateComplete;
            expect(control.getForm()).to.equal(form);
          });
          it("Should find the correct form when given a form attribute", async () => {
            const formId = "test-form";
            const form = await fixture(html`<form id="${formId}"></form>`);
            const control = await createControl();
            expect(control.getForm()).to.equal(null);
            control.setAttribute("form", "test-form");
            await control.updateComplete;
            expect(control.getForm()).to.equal(form);
          });
          it("Should be invalid if a `customError` property is passed.", async () => {
            const control = await createControl();
            control.customError = "MyError";
            await control.updateComplete;
            expect(control.validity.valid).to.equal(false);
            expect(control.customStates.has("invalid")).to.equal(true);
            expect(control.validationMessage).to.equal("MyError");
          });
          it("Should be invalid if a `customError` attribute is passed.", async () => {
            const control = await createControl();
            control.setAttribute("custom-error", "MyError");
            await control.updateComplete;
            expect(control.customStates.has("invalid")).to.equal(true);
            expect(control.validationMessage).to.equal("MyError");
          });
          it("Should properly move into and out of `:disabled` when using a <fieldset>", async () => {
            const control = await createControl();
            const fieldset = await fixture(html`<fieldset></fieldset>`);
            expect(control.disabled).to.equal(false);
            fieldset.append(control);
            fieldset.disabled = true;
            await control.updateComplete;
            expect(control.disabled).to.equal(true);
            expect(control.matches(":disabled")).to.equal(true);
            expect(control.customStates.has("disabled")).to.equal(true);
            fieldset.disabled = false;
            await control.updateComplete;
            expect(control.disabled).to.equal(false);
            expect(control.hasAttribute("disabled")).to.equal(false);
            expect(control.matches(":disabled")).to.equal(false);
            expect(control.customStates.has("disabled")).to.equal(false);
          });
          it("Should reflect the disabled attribute if its attribute is directly added", async () => {
            const control = await createControl();
            expect(control.disabled).to.equal(false);
            control.disabled = true;
            await control.updateComplete;
            expect(control.disabled).to.equal(true);
            expect(control.hasAttribute("disabled")).to.equal(true);
            expect(control.matches(":disabled")).to.equal(true);
            expect(control.customStates.has("disabled")).to.equal(true);
            control.disabled = false;
            await control.updateComplete;
            expect(control.disabled).to.equal(false);
            expect(control.hasAttribute("disabled")).to.equal(false);
            expect(control.matches(":disabled")).to.equal(false);
            expect(control.customStates.has("disabled")).to.equal(false);
          });
        }
      });
    }
  });
}
function runSpecialTests_slButtonOfTypeButton(createControl) {
  it("should make sure that `.validity.valid` is `false` in custom error case", async () => {
    const control = await createControl();
    control.setCustomValidity("error");
    expect(control.validity.valid).to.equal(false);
  });
  it("should make sure that calling `.checkValidity()` will still return `true` when custom error has been set", async () => {
    const control = await createControl();
    control.setCustomValidity("error");
    expect(control.checkValidity()).to.equal(false);
    await clickOnElement(document.body);
    await aTimeout(100);
  });
  it("should make sure that calling `.reportValidity()` will still return `true` when custom error has been set", async () => {
    const control = await createControl();
    control.setCustomValidity("error");
    expect(control.reportValidity()).to.equal(false);
    await clickOnElement(document.body);
    await aTimeout(100);
  });
  it("should emit an `wa-invalid` event when `.checkValidity()` is called in custom error case, and not disabled", async () => {
    const control = await createControl();
    control.setCustomValidity("error");
    control.disabled = false;
    await control.updateComplete;
    const emittedEvents = await checkEventEmissions(control, "wa-invalid", () => control.checkValidity());
    expect(emittedEvents.length).to.equal(1);
  });
  it("should emit an `wa-invalid` event when `.reportValidity()` is called in custom error case, and not disabled", async () => {
    const control = await createControl();
    control.setCustomValidity("error");
    control.disabled = false;
    await control.updateComplete;
    const emittedEvents = await checkEventEmissions(control, "wa-invalid", () => control.reportValidity());
    expect(emittedEvents.length).to.equal(1);
  });
}
function runSpecialTests_slButtonWithHref(createControl) {
  it("should make sure that calling `.checkValidity()` will return `false` in custom error case", async () => {
    const control = await createControl();
    control.setCustomValidity("error");
    expect(control.checkValidity()).to.equal(false);
  });
  it("should make sure that calling `.reportValidity()` will return `false` in custom error case", async () => {
    const control = await createControl();
    control.setCustomValidity("error");
    expect(control.reportValidity()).to.equal(false);
    await clickOnElement(document.body);
    await aTimeout(100);
  });
  it("should emit an `wa-invalid` event when `.checkValidity()` is called in custom error case", async () => {
    const control = await createControl();
    control.setCustomValidity("error");
    await control.updateComplete;
    const emittedEvents = await checkEventEmissions(control, "wa-invalid", () => control.checkValidity());
    expect(emittedEvents.length).to.equal(1);
  });
  it("should emit an `wa-invalid` event when `.reportValidity()` is called in custom error case", async () => {
    const control = await createControl();
    control.setCustomValidity("error");
    await control.updateComplete;
    const emittedEvents = await checkEventEmissions(control, "wa-invalid", () => control.reportValidity());
    expect(emittedEvents.length).to.equal(1);
  });
}
function runSpecialTests_standard(createControl) {
  it("should make sure that `.validity.valid` is `false` in custom error case", async () => {
    const control = await createControl();
    control.setCustomValidity("error");
    expect(control.validity.valid).to.equal(false);
  });
  it("should make sure that calling `.checkValidity()` will return `false` in custom error case", async () => {
    const control = await createControl();
    control.setCustomValidity("error");
    expect(control.checkValidity()).to.equal(false);
  });
  it("should make sure that calling `.reportValidity()` will return `false` in custom error case", async () => {
    const control = await createControl();
    control.setCustomValidity("error");
    expect(control.reportValidity()).to.equal(false);
    await clickOnElement(document.body);
    await aTimeout(100);
  });
  it("should emit an `wa-invalid` event when `.checkValidity()` is called in custom error case and not disabled", async () => {
    const control = await createControl();
    control.setCustomValidity("error");
    control.disabled = false;
    await control.updateComplete;
    const emittedEvents = await checkEventEmissions(control, "wa-invalid", () => control.checkValidity());
    expect(emittedEvents.length).to.equal(1);
  });
  it("should emit an `wa-invalid` event when `.reportValidity()` is called in custom error case and not disabled", async () => {
    const control = await createControl();
    control.setCustomValidity("error");
    control.disabled = false;
    await control.updateComplete;
    const emittedEvents = await checkEventEmissions(control, "wa-invalid", () => control.reportValidity());
    expect(emittedEvents.length).to.equal(1);
  });
}
function createFormControl(fixtureFn) {
  return async (tagName) => {
    const tag = unsafeStatic(`${tagName}`);
    const control = await fixtureFn(staticHTML`<${tag}></${tag}>`);
    await customElements.whenDefined(tagName);
    await control.updateComplete;
    return control;
  };
}
function checkEventEmissions(control, eventType, action) {
  const emittedEvents = [];
  const eventHandler = (event) => {
    emittedEvents.push(event);
  };
  return new Promise((resolve) => {
    (async () => {
      try {
        control.addEventListener(eventType, eventHandler);
        action();
        await aTimeout(300);
      } finally {
        control.removeEventListener(eventType, eventHandler);
      }
      resolve(emittedEvents);
    })();
  });
}
function getMode(control) {
  if (control.localName === "wa-button" && //
  "href" in control && "type" in control && control.type === "button" && !control.href) {
    return "slButtonOfTypeButton";
  }
  if (control.localName === "wa-button" && "href" in control && !!control.href) {
    return "slButtonWithHRef";
  }
  return "standard";
}
export {
  runFormControlBaseTests
};
