import {
  __spreadProps,
  __spreadValues
} from "./chunk.S3NI7NKU.js";

// src/internal/form.ts
import { html } from "lit";
var formCollections = /* @__PURE__ */ new WeakMap();
var reportValidityOverloads = /* @__PURE__ */ new WeakMap();
var userInteractedControls = /* @__PURE__ */ new WeakMap();
var interactions = /* @__PURE__ */ new WeakMap();
var FormControlController = class {
  constructor(host, options) {
    this.handleFormData = (event) => {
      const disabled = this.options.disabled(this.host);
      const name = this.options.name(this.host);
      const value = this.options.value(this.host);
      const isButton = this.host.tagName.toLowerCase() === "sd-6-22-0-button";
      if (!disabled && !isButton && typeof name === "string" && name.length > 0 && typeof value !== "undefined") {
        if (Array.isArray(value)) {
          value.forEach((val) => {
            event.formData.append(name, val.toString());
          });
        } else {
          event.formData.append(name, value.toString());
        }
      }
    };
    this.handleFormSubmit = (event) => {
      var _a, _b;
      const disabled = this.options.disabled(this.host);
      const reportValidity = this.options.reportValidity;
      if (this.form && !this.form.noValidate) {
        (_a = formCollections.get(this.form)) == null ? void 0 : _a.forEach((control) => {
          this.setUserInteracted(control, true);
        });
      }
      if (this.form && !this.form.noValidate && !disabled && !reportValidity(this.host)) {
        event.preventDefault();
        event.stopImmediatePropagation();
        const invalidElements = (_b = this.form) == null ? void 0 : _b.querySelectorAll("[data-invalid]");
        const sdRadioGroups = Array.from(invalidElements).filter(
          (element) => element.tagName.toLowerCase() === "sd-6-22-0-radio-group"
        );
        sdRadioGroups.forEach((radioGroup) => {
          var _a2, _b2;
          (_b2 = (_a2 = radioGroup.shadowRoot) == null ? void 0 : _a2.querySelector("input")) == null ? void 0 : _b2.dispatchEvent(new Event("invalid"));
        });
        if (invalidElements == null ? void 0 : invalidElements.length) invalidElements[0].focus();
      }
    };
    this.handleFormReset = () => {
      this.options.setValue(this.host, this.options.defaultValue(this.host));
      this.setUserInteracted(this.host, false);
      interactions.set(this.host, []);
    };
    this.handleInteraction = (event) => {
      const emittedEvents = interactions.get(this.host);
      if (!emittedEvents.includes(event.type)) {
        emittedEvents.push(event.type);
      }
      if (emittedEvents.length === this.options.assumeInteractionOn.length) {
        this.setUserInteracted(this.host, true);
      }
    };
    // This is used by `reportValidity` to show validity state styles and messages without manual user interaction
    this.fakeUserInteraction = () => {
      this.setUserInteracted(this.host, true);
    };
    (this.host = host).addController(this);
    this.options = __spreadValues({
      form: (input) => {
        if (input.hasAttribute("form") && input.getAttribute("form") !== "") {
          const root = input.getRootNode();
          const formId = input.getAttribute("form");
          if (formId) {
            return root.getElementById(formId);
          }
        }
        return input.closest("form");
      },
      name: (input) => input.name,
      value: (input) => input.value,
      defaultValue: (input) => input.defaultValue,
      disabled: (input) => {
        var _a;
        return (_a = input.disabled) != null ? _a : false;
      },
      reportValidity: (input) => typeof input.reportValidity === "function" ? input.reportValidity() : true,
      setValue: (input, value) => input.value = value,
      assumeInteractionOn: ["sd-input"]
    }, options);
  }
  hostConnected() {
    const form = this.options.form(this.host);
    if (form) {
      this.attachForm(form);
    }
    interactions.set(this.host, []);
    this.options.assumeInteractionOn.forEach((event) => {
      this.host.addEventListener(event, this.handleInteraction);
    });
  }
  hostDisconnected() {
    this.detachForm();
    interactions.delete(this.host);
    this.options.assumeInteractionOn.forEach((event) => {
      this.host.removeEventListener(event, this.handleInteraction);
    });
  }
  hostUpdated() {
    var _a;
    const form = this.options.form(this.host);
    if (!form) {
      this.detachForm();
    }
    if (form && this.form !== form) {
      this.detachForm();
      this.attachForm(form);
    }
    if (this.host.hasUpdated) {
      this.setValidity((_a = this.host) == null ? void 0 : _a.validity.valid);
      this.updateValidityStyle();
    }
  }
  attachForm(form) {
    if (form) {
      this.form = form;
      if (formCollections.has(this.form)) {
        formCollections.get(this.form).add(this.host);
      } else {
        formCollections.set(this.form, /* @__PURE__ */ new Set([this.host]));
      }
      this.form.addEventListener("formdata", this.handleFormData);
      this.form.addEventListener("submit", this.handleFormSubmit);
      this.form.addEventListener("reset", this.handleFormReset);
      if (!reportValidityOverloads.has(this.form)) {
        reportValidityOverloads.set(this.form, this.form.reportValidity);
        this.form.reportValidity = () => this.reportFormValidity();
      }
    } else {
      this.form = void 0;
    }
  }
  detachForm() {
    var _a;
    if (this.form) {
      (_a = formCollections.get(this.form)) == null ? void 0 : _a.delete(this.host);
      this.form.removeEventListener("formdata", this.handleFormData);
      this.form.removeEventListener("submit", this.handleFormSubmit);
      this.form.removeEventListener("reset", this.handleFormReset);
      if (reportValidityOverloads.has(this.form)) {
        this.form.reportValidity = reportValidityOverloads.get(this.form);
        reportValidityOverloads.delete(this.form);
      }
    }
    this.form = void 0;
  }
  reportFormValidity() {
    if (this.form && !this.form.noValidate) {
      const elements = this.form.querySelectorAll("*");
      for (const element of elements) {
        if (typeof element.reportValidity === "function") {
          if (!element.reportValidity()) {
            return false;
          }
        }
      }
    }
    return true;
  }
  setUserInteracted(el, hasInteracted) {
    userInteractedControls.set(el, hasInteracted);
    el.requestUpdate();
  }
  doAction(type, invoker) {
    if (this.form) {
      const button = document.createElement("button");
      button.type = type;
      button.style.position = "absolute";
      button.style.width = "0";
      button.style.height = "0";
      button.style.clipPath = "inset(50%)";
      button.style.overflow = "hidden";
      button.style.whiteSpace = "nowrap";
      if (invoker) {
        button.name = invoker.name;
        button.value = invoker.value;
        ["formaction", "formenctype", "formmethod", "formnovalidate", "formtarget"].forEach((attr) => {
          if (invoker.hasAttribute(attr)) {
            button.setAttribute(attr, invoker.getAttribute(attr));
          }
        });
      }
      this.form.append(button);
      button.click();
      button.remove();
    }
  }
  /** Checks for the presence of the attributes 'data-user-valid' or 'data-user-invalid' on the host form element and updates its corresponding style state. */
  updateValidityStyle() {
    if (this.host.hasAttribute("data-user-valid") && this.host.checkValidity()) {
      if (this.host.showValidStyle !== void 0) this.host.showValidStyle = true;
      this.host.showInvalidStyle = false;
    } else if (this.host.hasAttribute("data-user-invalid") && !this.host.checkValidity()) {
      if (this.host.showValidStyle !== void 0) this.host.showValidStyle = false;
      this.host.showInvalidStyle = true;
    } else {
      if (this.host.showValidStyle !== void 0) this.host.showValidStyle = false;
      this.host.showInvalidStyle = false;
    }
  }
  /** Returns the associated `<form>` element, if one exists. */
  getForm() {
    var _a;
    return (_a = this.form) != null ? _a : null;
  }
  /** Returns a styled `<div>` element to display inline validation messages via its `textContent` property when a form element is invalid. */
  renderInvalidMessage(size) {
    const sizeClass = {
      sm: "text-sm",
      md: "text-base",
      lg: "text-base"
    }[size];
    return html`<div id="invalid-message" class="text-error text-left ${sizeClass}" part="invalid-message" aria-live="polite" ?hidden="${!this.host.showInvalidStyle}"></div>`;
  }
  /** Resets the form, restoring all the control to their default value */
  reset(invoker) {
    this.doAction("reset", invoker);
  }
  /** Submits the form, triggering validation and form data injection. */
  submit(invoker) {
    this.doAction("submit", invoker);
  }
  /**
   * Synchronously sets the form control's validity. Call this when you know the future validity but need to update
   * the host element immediately, i.e. before Lit updates the component in the next update.
   */
  setValidity(isValid) {
    var _a;
    const host = this.host;
    const hasInteracted = Boolean(userInteractedControls.get(host));
    const required = Boolean(host.required);
    if ((_a = this.form) == null ? void 0 : _a.noValidate) {
      host.removeAttribute("data-required");
      host.removeAttribute("data-optional");
      host.removeAttribute("data-invalid");
      host.removeAttribute("data-valid");
      host.removeAttribute("data-user-invalid");
      host.removeAttribute("data-user-valid");
      host.removeAttribute("aria-invalid");
    } else {
      host.toggleAttribute("data-required", required);
      host.toggleAttribute("data-optional", !required);
      host.toggleAttribute("data-invalid", !isValid);
      host.toggleAttribute("data-valid", isValid);
      host.toggleAttribute("data-user-invalid", !isValid && hasInteracted);
      host.toggleAttribute("data-user-valid", isValid && hasInteracted);
      host.setAttribute("aria-invalid", (!isValid).toString());
    }
  }
  /**
   * Updates the form control's validity based on the current value of `host.validity.valid`. Call this when anything
   * that affects constraint validation changes so the component receives the correct validity states.
   */
  updateValidity() {
    const host = this.host;
    this.setValidity(host == null ? void 0 : host.validity.valid);
  }
  /**
   * Dispatches a non-bubbling, cancelable custom event of type `sd-invalid`.
   * If no original `invalid` event has been passed then the `sd-invalid`
   * event will be cancelled before being dispatched.
   */
  emitInvalidEvent(originalInvalidEvent) {
    originalInvalidEvent == null ? void 0 : originalInvalidEvent.preventDefault();
    const sdInvalidEvent = new CustomEvent("sd-invalid", {
      bubbles: false,
      composed: false,
      cancelable: true,
      detail: {}
    });
    if (!originalInvalidEvent) {
      sdInvalidEvent.preventDefault();
    }
  }
};
var validValidityState = Object.freeze({
  badInput: false,
  customError: false,
  patternMismatch: false,
  rangeOverflow: false,
  rangeUnderflow: false,
  stepMismatch: false,
  tooLong: false,
  tooShort: false,
  typeMismatch: false,
  valid: true,
  valueMissing: false
});
var valueMissingValidityState = Object.freeze(__spreadProps(__spreadValues({}, validValidityState), {
  valid: false,
  valueMissing: true
}));
var customErrorValidityState = Object.freeze(__spreadProps(__spreadValues({}, validValidityState), {
  valid: false,
  customError: true
}));

export {
  formCollections,
  FormControlController,
  validValidityState,
  valueMissingValidityState,
  customErrorValidityState
};
