import { html } 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 { ensureArray } from '../../internal/ensure-array.mjs';
import { FlowRdfFormControl } from '../../internal/flow-ui-rdf-element.mjs';
import { FormControlController, customErrorValidityState, validValidityState } from '../../internal/form.mjs';
import { watch } from '../../internal/watch.mjs';
import styles from './tool-button-group.styles.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 FlowUiToolButtonGroup extends FlowRdfFormControl {
  constructor() {
    super(...arguments);
    /** @internal */
    this.formControlController = new FormControlController(this);
    this.customValidityMessage = "";
    this.errorMessage = "";
    this.label = "";
    this.name = "option";
    this.value = "";
    this.size = "medium";
    this.pill = false;
    this.outline = false;
    this.variant = "primary";
    this.form = "";
    this.vertical = false;
    this.mode = "radio";
  }
  /** Gets the validity state object */
  get validity() {
    const hasCustomValidityMessage = this.customValidityMessage !== "";
    if (hasCustomValidityMessage) {
      return customErrorValidityState;
    }
    return validValidityState;
  }
  /** Gets the validation message */
  get validationMessage() {
    const hasCustomValidityMessage = this.customValidityMessage !== "";
    if (hasCustomValidityMessage) {
      return this.customValidityMessage;
    }
    return "";
  }
  connectedCallback() {
    super.connectedCallback();
    this.pill = boolean(this.pill, true);
    this.outline = boolean(this.outline, true);
    this.vertical = boolean(this.vertical, true);
  }
  firstUpdated() {
    this.formControlController.updateValidity();
  }
  getAllToolButtons() {
    return [...this.querySelectorAll("flow-ui-tool-button")];
  }
  handleButtonClick(event) {
    const target = event.target.closest("flow-ui-tool-button");
    if (!target) {
      return;
    }
    const toolButtons = this.getAllToolButtons();
    const oldValue = this.value;
    if (target.disabled) {
      return;
    }
    if (this.mode === "radio") {
      target.checked = true;
      this.value = target.value;
    } else {
      target.checked = !target.checked;
      this.value = toolButtons.filter((button) => !button.disabled && button.checked).map((button) => button.value);
      if (!target.checked) {
        target.blur();
      }
    }
    this.updateCheckedButtons();
    if (this.value !== oldValue) {
      this.emit("flow-ui-change");
      this.emit("flow-ui-input");
    }
  }
  handleKeyDown(event) {
    if (this.mode === "checkbox") {
      return;
    }
    if (!["ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight", " "].includes(event.key)) {
      return;
    }
    const buttons = this.getAllToolButtons().filter((radio) => !radio.disabled);
    const checkedButton = buttons.find((button) => button.checked) ?? buttons[0];
    const incr = event.key === " " ? 0 : ["ArrowUp", "ArrowLeft"].includes(event.key) ? -1 : 1;
    const oldValue = this.value;
    let index = buttons.indexOf(checkedButton) + incr;
    if (index < 0) {
      index = buttons.length - 1;
    }
    if (index > buttons.length - 1) {
      index = 0;
    }
    this.getAllToolButtons().forEach((radio) => {
      radio.checked = false;
    });
    this.value = buttons[index].value;
    buttons[index].checked = true;
    buttons[index].shadowRoot.querySelector("button").focus();
    if (this.value !== oldValue) {
      this.emit("flow-ui-change");
      this.emit("flow-ui-input");
    }
    event.preventDefault();
  }
  handleInvalid(event) {
    this.formControlController.setValidity(false);
    this.formControlController.emitInvalidEvent(event);
  }
  syncButtons() {
    if (customElements.get("flow-ui-tool-button")) {
      const buttons = this.getAllToolButtons();
      const valueArray = ensureArray(this.value);
      buttons.forEach((button) => {
        button.checked = valueArray.includes(button.value);
        button.size = this.size;
        button.pill = this.pill;
        button.outline = this.outline;
        button.variant = this.variant;
      });
      if (this.mode === "checkbox") {
        buttons.forEach((button) => {
          const buttonControl = button.shadowRoot?.querySelector("button");
          if (buttonControl) {
            buttonControl.tabIndex = 0;
          }
        });
      } else if (!buttons.some((button) => button.checked)) {
        const buttonControl = buttons[0].shadowRoot?.querySelector("button");
        if (buttonControl) {
          buttonControl.tabIndex = 0;
        }
      }
      const buttonGroup = this.shadowRoot?.querySelector("flow-ui-button-group");
      if (buttonGroup) {
        buttonGroup.disableRole = true;
      }
    } else {
      customElements.whenDefined("flow-ui-tool-button").then(() => this.syncButtons());
    }
  }
  updateCheckedButtons() {
    const buttons = this.getAllToolButtons();
    const valueArray = ensureArray(this.value);
    buttons.forEach((button) => button.checked = valueArray.includes(button.value));
    this.updateTabbableState();
    this.formControlController.setValidity(this.validity.valid);
  }
  handleSizeChange() {
    this.syncButtons();
  }
  handleOutlineChange() {
    this.syncButtons();
  }
  handleVariantChange() {
    this.syncButtons();
  }
  handlePillChange() {
    this.syncButtons();
  }
  handleValueChange() {
    if (this.hasUpdated) {
      this.updateCheckedButtons();
    }
  }
  updateTabbableState() {
    const buttons = this.getAllToolButtons();
    buttons.forEach((button) => {
      const buttonControl = button.shadowRoot?.querySelector("button");
      if (buttonControl) {
        buttonControl.tabIndex = this.mode === "checkbox" ? 0 : button.checked ? 0 : -1;
      }
    });
  }
  /** Checks for validity but does not show a validation message. Returns `true` when valid and `false` when invalid. */
  checkValidity() {
    const hasCustomValidityMessage = this.customValidityMessage !== "";
    if (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();
  }
  render() {
    const defaultSlot = html`
      <slot
        @click=${this.handleButtonClick}
        @keydown=${this.handleKeyDown}
        @slotchange=${this.syncButtons}
        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--radio-group": true
    })}
        role="radiogroup"
        aria-labelledby="label"
        aria-describedby="help-text"
        aria-errormessage="error-message"
      >
        <div part="form-control-input" class="form-control-input">
          <div class="visually-hidden">
            <div id="error-message" aria-live="assertive">${this.errorMessage}</div>
            <label class="radio-group__validation">
              <input
                type="text"
                class="radio-group__validation-input"
                tabindex=${this.mode === "radio" ? "-1" : "0"}
                hidden
                @invalid=${this.handleInvalid}
              />
            </label>
          </div>

          <flow-ui-button-group
            class=${classMap({
      "button-group": true,
      "button-group--x-small": this.size === "x-small",
      "button-group--small": this.size === "small",
      "button-group--medium": this.size === "medium",
      "button-group--large": this.size === "large",
      "button-group--outline": this.outline,
      "button-group--no-outline": !this.outline
    })}
            part="button-group"
            exportparts="base:button-group__base"
            ?vertical=${this.vertical}
          >
            ${defaultSlot}
          </flow-ui-button-group>
        </div>
      </fieldset>
    `;
  }
}
FlowUiToolButtonGroup.styles = styles;
__decorateClass([
  query(".radio-group__validation-input")
], FlowUiToolButtonGroup.prototype, "validationInput", 2);
__decorateClass([
  state()
], FlowUiToolButtonGroup.prototype, "errorMessage", 2);
__decorateClass([
  property()
], FlowUiToolButtonGroup.prototype, "label", 2);
__decorateClass([
  property()
], FlowUiToolButtonGroup.prototype, "name", 2);
__decorateClass([
  property({
    converter: {
      fromAttribute: (value) => value.split(" "),
      toAttribute: (value) => value.join(" ")
    }
  })
], FlowUiToolButtonGroup.prototype, "value", 2);
__decorateClass([
  property({ reflect: true })
], FlowUiToolButtonGroup.prototype, "size", 2);
__decorateClass([
  property({ type: Boolean, reflect: true })
], FlowUiToolButtonGroup.prototype, "pill", 2);
__decorateClass([
  property({ type: Boolean, reflect: true })
], FlowUiToolButtonGroup.prototype, "outline", 2);
__decorateClass([
  property()
], FlowUiToolButtonGroup.prototype, "variant", 2);
__decorateClass([
  property({ reflect: true })
], FlowUiToolButtonGroup.prototype, "form", 2);
__decorateClass([
  property({ type: Boolean, reflect: true })
], FlowUiToolButtonGroup.prototype, "vertical", 2);
__decorateClass([
  property()
], FlowUiToolButtonGroup.prototype, "mode", 2);
__decorateClass([
  watch("size", { waitUntilFirstUpdate: true })
], FlowUiToolButtonGroup.prototype, "handleSizeChange", 1);
__decorateClass([
  watch("outline", { waitUntilFirstUpdate: true })
], FlowUiToolButtonGroup.prototype, "handleOutlineChange", 1);
__decorateClass([
  watch("variant", { waitUntilFirstUpdate: true })
], FlowUiToolButtonGroup.prototype, "handleVariantChange", 1);
__decorateClass([
  watch("pill", { waitUntilFirstUpdate: true })
], FlowUiToolButtonGroup.prototype, "handlePillChange", 1);
__decorateClass([
  watch("value")
], FlowUiToolButtonGroup.prototype, "handleValueChange", 1);
__decorateClass([
  watch("mode", { waitUntilFirstUpdate: true })
], FlowUiToolButtonGroup.prototype, "updateTabbableState", 1);

export { FlowUiToolButtonGroup as default };
