import { html, nothing } from 'lit';
import { query, state, property } from 'lit/decorators.js';
import { classMap } from 'lit/directives/class-map.js';
import { boolean } from '../../internal/boolean.mjs';
import { FlowRdfFormControl } from '../../internal/flow-ui-rdf-element.mjs';
import { FormControlController, customErrorValidityState, valueMissingValidityState, validValidityState } from '../../internal/form.mjs';
import { HasSlotController } from '../../internal/slot.mjs';
import { watch } from '../../internal/watch.mjs';
import styles from './checkbox-group.styles.mjs';
import { isNil } from '../../internal/type-checks.mjs';

var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __decorateClass = (decorators, target, key, kind) => {
  var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
  for (var i = decorators.length - 1, decorator; i >= 0; i--)
    if (decorator = decorators[i])
      result = (kind ? decorator(target, key, result) : decorator(result)) || result;
  if (kind && result)
    __defProp(target, key, result);
  return result;
};
class FlowUiCheckboxGroup extends FlowRdfFormControl {
  constructor() {
    super(...arguments);
    this.formControlController = new FormControlController(this);
    this.hasSlotController = new HasSlotController(this, "help-text", "label");
    this.customValidityMessage = "";
    this.errorMessage = "";
    this.defaultValue = [];
    this.label = "";
    this.helpText = "";
    this.name = "option";
    this.value = [];
    this.size = "medium";
    this.form = "";
    this.required = false;
    this.reverse = false;
    this.divider = false;
  }
  /** Gets the validity state object */
  get validity() {
    const isRequiredAndEmpty = this.required && !this.value;
    const hasCustomValidityMessage = this.customValidityMessage !== "";
    if (hasCustomValidityMessage) {
      return customErrorValidityState;
    } else if (isRequiredAndEmpty) {
      return valueMissingValidityState;
    }
    return validValidityState;
  }
  /** Gets the validation message */
  get validationMessage() {
    const isRequiredAndEmpty = this.required && !this.value;
    const hasCustomValidityMessage = this.customValidityMessage !== "";
    if (hasCustomValidityMessage) {
      return this.customValidityMessage;
    } else if (isRequiredAndEmpty) {
      return this.validationInput.validationMessage;
    }
    return "";
  }
  connectedCallback() {
    super.connectedCallback();
    this.required = boolean(this.required, true);
    this.reverse = boolean(this.reverse, true);
    this.divider = boolean(this.divider, true);
    this.defaultValue = this.value;
  }
  firstUpdated() {
    this.formControlController.updateValidity();
  }
  getAllCheckboxes() {
    return [...this.querySelectorAll("flow-ui-checkbox")];
  }
  handleCheckboxClick(event) {
    const target = event.target.closest("flow-ui-checkbox");
    const checkboxes = this.getAllCheckboxes();
    const oldValue = this.value;
    if (target.disabled) {
      return;
    }
    this.value = checkboxes.filter((checkbox) => checkbox.checked).map((checkbox) => checkbox.value);
    const arrayEqual = (arr1, arr2) => {
      if (arr1.length !== arr2.length)
        return false;
      return arr2.every((arr2Item) => arr1.includes(arr2Item));
    };
    if (!arrayEqual(this.value, oldValue)) {
      this.emit("flow-ui-change");
      this.emit("flow-ui-input");
    }
  }
  handleLabelClick() {
    const checkboxes = this.getAllCheckboxes();
    checkboxes[0]?.focus();
  }
  handleInvalid(event) {
    this.formControlController.setValidity(false);
    this.formControlController.emitInvalidEvent(event);
  }
  syncCheckboxes() {
    if (customElements.get("flow-ui-checkbox")) {
      const checkboxes = this.getAllCheckboxes();
      checkboxes.forEach((checkbox) => {
        checkbox.size = this.size;
        checkbox.reverse = this.reverse;
      });
      this.updateCheckedState();
    } else {
      customElements.whenDefined("flow-ui-checkbox").then(() => this.syncCheckboxes());
    }
  }
  updateCheckedState() {
    const checkboxes = this.getAllCheckboxes();
    checkboxes.forEach((checkbox) => checkbox.checked = this.value.includes(checkbox.value));
    this.formControlController.setValidity(this.validity.valid);
  }
  handleStyleChange() {
    this.syncCheckboxes();
  }
  handleValueChange() {
    if (isNil(this.value)) {
      this.value = [];
    }
    if (this.hasUpdated) {
      this.updateCheckedState();
    }
  }
  /** Checks for validity but does not show a validation message. Returns `true` when valid and `false` when invalid. */
  checkValidity() {
    const isRequiredAndEmpty = this.required && !this.value;
    const hasCustomValidityMessage = this.customValidityMessage !== "";
    if (isRequiredAndEmpty || hasCustomValidityMessage) {
      this.formControlController.emitInvalidEvent();
      return false;
    }
    return true;
  }
  /** Gets the associated form, if one exists. */
  getForm() {
    return this.formControlController.getForm();
  }
  /** Checks for validity and shows the browser's validation message if the control is invalid. */
  reportValidity() {
    const isValid = this.validity.valid;
    this.errorMessage = this.customValidityMessage || isValid ? "" : this.validationInput.validationMessage;
    this.formControlController.setValidity(isValid);
    this.validationInput.hidden = true;
    clearTimeout(this.validationTimeout);
    if (!isValid) {
      this.validationInput.hidden = false;
      this.validationInput.reportValidity();
      this.validationTimeout = setTimeout(() => this.validationInput.hidden = true, 1e4);
    }
    return isValid;
  }
  /** Sets a custom validation message. Pass an empty string to restore validity. */
  setCustomValidity(message = "") {
    this.customValidityMessage = message;
    this.errorMessage = message;
    this.validationInput.setCustomValidity(message);
    this.formControlController.updateValidity();
  }
  /** Stop propagation of flow-ui-input and flow-ui-change from child checkboxes */
  handleChildEvents(event) {
    event.stopPropagation();
  }
  render() {
    const hasLabelSlot = this.hasSlotController.test("label");
    const hasHelpTextSlot = this.hasSlotController.test("help-text");
    const hasLabel = this.label ? true : !!hasLabelSlot;
    const hasHelpText = this.helpText ? true : !!hasHelpTextSlot;
    const defaultSlot = html`
      <slot @click=${this.handleCheckboxClick} @slotchange=${this.syncCheckboxes} role="presentation"></slot>
    `;
    return html`
      <fieldset
        part="form-control"
        class=${classMap({
      "form-control": true,
      "form-control--small": this.size === "small",
      "form-control--medium": this.size === "medium",
      "form-control--large": this.size === "large",
      "form-control--checkbox-group": true,
      "form-control--has-label": hasLabel,
      "form-control--has-help-text": hasHelpText,
      "form-control--has-divider": this.divider
    })}
        role="radiogroup"
        aria-labelledby="label"
        aria-describedby="help-text"
        aria-errormessage="error-message"
      >
        <label
          part="form-control-label"
          id="label"
          class="form-control__label"
          aria-hidden=${hasLabel ? "false" : "true"}
          @click=${this.handleLabelClick}
        >
          <slot name="label">${this.label}</slot>
        </label>

        <slot
          name="help-text"
          part="form-control-help-text"
          id="help-text"
          class="form-control__help-text"
          aria-hidden=${hasHelpText ? "false" : "true"}
        >
          ${this.helpText}
        </slot>

        <div
          part="form-control-input"
          class="form-control-input"
          @flow-ui-input=${this.handleChildEvents}
          @flow-ui-change=${this.handleChildEvents}
        >
          <div class="visually-hidden">
            <div id="error-message" aria-live="assertive">${this.errorMessage}</div>
            <label class="checkbox-group__validation">
              <input
                type="text"
                class="checkbox-group__validation-input"
                ?required=${this.required}
                tabindex="-1"
                hidden
                @invalid=${this.handleInvalid}
              />
            </label>
          </div>
          ${defaultSlot}
        </div>

        ${this.divider ? this.renderDivider() : nothing}
      </fieldset>
    `;
  }
}
FlowUiCheckboxGroup.styles = styles;
__decorateClass([
  query("slot:not([name])")
], FlowUiCheckboxGroup.prototype, "defaultSlot", 2);
__decorateClass([
  query(".checkbox-group__validation-input")
], FlowUiCheckboxGroup.prototype, "validationInput", 2);
__decorateClass([
  state()
], FlowUiCheckboxGroup.prototype, "errorMessage", 2);
__decorateClass([
  state()
], FlowUiCheckboxGroup.prototype, "defaultValue", 2);
__decorateClass([
  property()
], FlowUiCheckboxGroup.prototype, "label", 2);
__decorateClass([
  property({ attribute: "help-text" })
], FlowUiCheckboxGroup.prototype, "helpText", 2);
__decorateClass([
  property()
], FlowUiCheckboxGroup.prototype, "name", 2);
__decorateClass([
  property({
    converter: {
      fromAttribute: (value) => value.split(" "),
      toAttribute: (value) => value.join(" ")
    }
  })
], FlowUiCheckboxGroup.prototype, "value", 2);
__decorateClass([
  property({ reflect: true })
], FlowUiCheckboxGroup.prototype, "size", 2);
__decorateClass([
  property({ reflect: true })
], FlowUiCheckboxGroup.prototype, "form", 2);
__decorateClass([
  property({ type: Boolean, reflect: true })
], FlowUiCheckboxGroup.prototype, "required", 2);
__decorateClass([
  property({ type: Boolean, reflect: true })
], FlowUiCheckboxGroup.prototype, "reverse", 2);
__decorateClass([
  property({ type: Boolean, reflect: true })
], FlowUiCheckboxGroup.prototype, "divider", 2);
__decorateClass([
  watch(["size", "reverse"], { waitUntilFirstUpdate: true })
], FlowUiCheckboxGroup.prototype, "handleStyleChange", 1);
__decorateClass([
  watch("value")
], FlowUiCheckboxGroup.prototype, "handleValueChange", 1);

export { FlowUiCheckboxGroup as default };
