import { html, nothing } from 'lit';
import { query, state, property } from 'lit/decorators.js';
import { classMap } from 'lit/directives/class-map.js';
import { ifDefined } from 'lit/directives/if-defined.js';
import { DateTime } from 'luxon';
import { stopAnimations, animateTo } from '../../internal/animate.mjs';
import { boolean } from '../../internal/boolean.mjs';
import { defaultValue } from '../../internal/default-value.mjs';
import { waitForEvent } from '../../internal/event.mjs';
import { FlowRdfFormControl } from '../../internal/flow-ui-rdf-element.mjs';
import { FormControlController } from '../../internal/form.mjs';
import { HasSlotController } from '../../internal/slot.mjs';
import { isStringFull } from '../../internal/type-checks.mjs';
import { watch } from '../../internal/watch.mjs';
import { getAnimation, setDefaultAnimation } from '../../utilities/animation-registry.mjs';
import { LocalizeController } from '../../utilities/localize.mjs';
import styles from './date-time-picker.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;
};
const popupOptions = {
  small: { distance: -1, skidding: -4 },
  medium: { distance: -3, skidding: -9 },
  large: { distance: -5, skidding: -15 }
};
class FlowUiDateTimePicker extends FlowRdfFormControl {
  constructor() {
    super(...arguments);
    this.formControlController = new FormControlController(this, {
      assumeInteractionOn: ["flow-ui-blur", "flow-ui-input"]
    });
    this.hasSlotController = new HasSlotController(this, "help-text", "label");
    this.localize = new LocalizeController(this);
    this.hasFocus = false;
    this.displayLabel = "";
    this.name = "";
    this.value = "";
    this.displayMode = "datetime";
    this.format = "FFF";
    this.defaultValue = "";
    this.size = "medium";
    this.placeholder = "";
    this.disabled = false;
    this.clearable = false;
    this.open = false;
    this.hoist = false;
    this.filled = false;
    this.pill = false;
    this.label = "";
    this.placement = "bottom-end";
    this.helpText = "";
    this.form = "";
    this.required = false;
    this.inline = false;
    this.divider = false;
  }
  /** Gets the validity state object */
  get validity() {
    return this.valueInput.validity;
  }
  /** Gets the validation message */
  get validationMessage() {
    return this.valueInput.validationMessage;
  }
  connectedCallback() {
    super.connectedCallback();
    this.clearable = boolean(this.clearable, true);
    this.disabled = boolean(this.disabled, true);
    this.hoist = boolean(this.hoist, true);
    this.required = boolean(this.required, true);
    this.filled = boolean(this.filled, true);
    this.pill = boolean(this.pill, true);
    this.inline = boolean(this.inline, true);
    this.handleDocumentFocusIn = this.handleDocumentFocusIn.bind(this);
    this.handleDocumentKeyDown = this.handleDocumentKeyDown.bind(this);
    this.handleDocumentMouseDown = this.handleDocumentMouseDown.bind(this);
    this.open = false;
  }
  addOpenListeners() {
    document.addEventListener("focusin", this.handleDocumentFocusIn);
    document.addEventListener("keydown", this.handleDocumentKeyDown);
    document.addEventListener("mousedown", this.handleDocumentMouseDown);
  }
  removeOpenListeners() {
    document.removeEventListener("focusin", this.handleDocumentFocusIn);
    document.removeEventListener("keydown", this.handleDocumentKeyDown);
    document.removeEventListener("mousedown", this.handleDocumentMouseDown);
  }
  updateDisplayLabel() {
    try {
      if (isStringFull(this.value)) {
        const zone = isStringFull(this.timezone) ? this.timezone : void 0;
        const locale = isStringFull(this.locale) ? this.locale : void 0;
        this.displayLabel = DateTime.fromISO(this.value, { zone, locale }).toFormat(this.format);
      } else {
        this.displayLabel = "";
      }
    } catch (e) {
      console.warn(e.message);
    }
  }
  handleFocus() {
    this.hasFocus = true;
    this.displayInput.setSelectionRange(0, 0);
    this.emit("flow-ui-focus");
  }
  handleBlur() {
    this.hasFocus = false;
    this.emit("flow-ui-blur");
  }
  handleDocumentFocusIn(event) {
    const path = event.composedPath();
    if (this && !path.includes(this)) {
      this.hide();
    }
  }
  handleDocumentKeyDown(event) {
    const target = event.target;
    const isClearButton = target.closest(".datepicker__clear") !== null;
    const isIconButton = target.closest("flow-ui-icon-button") !== null;
    if (isClearButton || isIconButton) {
      return;
    }
    if (event.key === "Escape" && this.open) {
      event.preventDefault();
      event.stopPropagation();
      this.hide();
      this.displayInput.focus({ preventScroll: true });
    }
    if (event.key === "Enter") {
      event.preventDefault();
      event.stopImmediatePropagation();
      if (!this.open) {
        this.show();
        return;
      }
      return;
    }
  }
  handleDocumentMouseDown(event) {
    const path = event.composedPath();
    if (this && !path.includes(this)) {
      this.hide();
    }
  }
  handleLabelClick() {
    this.displayInput.focus();
  }
  handleComboboxMouseDown(event) {
    const path = event.composedPath();
    const isIconButton = path.some((el) => el instanceof Element && el.tagName.toLowerCase() === "flow-ui-icon-button");
    if (this.disabled || isIconButton) {
      return;
    }
    event.preventDefault();
    this.displayInput.focus({ preventScroll: true });
    this.open = !this.open;
  }
  handleComboboxKeyDown(event) {
    event.stopPropagation();
    this.handleDocumentKeyDown(event);
  }
  handleClearClick(event) {
    event.stopPropagation();
    if (this.value !== "") {
      this.value = "";
      this.displayInput.focus({ preventScroll: true });
      this.updateComplete.then(() => {
        this.emit("flow-ui-clear");
        this.emit("flow-ui-input");
        this.emit("flow-ui-change");
      });
    }
  }
  handleClearMouseDown(event) {
    event.stopPropagation();
    event.preventDefault();
  }
  handleCalendarChange(event) {
    event.stopPropagation();
    const target = event.target;
    if (this.value !== target.value) {
      this.value = target.value;
      this.updateComplete.then(() => {
        this.formControlController.updateValidity();
        this.emit("flow-ui-input");
        this.emit("flow-ui-change");
      });
    }
  }
  handleInvalid(event) {
    this.formControlController.setValidity(false);
    this.formControlController.emitInvalidEvent(event);
  }
  handleDisabledChange() {
    if (this.disabled) {
      this.open = false;
      this.handleOpenChange();
    }
  }
  handleValueChange() {
  }
  async handleOpenChange() {
    if (this.open && !this.disabled) {
      this.emit("flow-ui-show");
      this.addOpenListeners();
      await stopAnimations(this);
      this.calendarContainer.hidden = false;
      this.popup.active = true;
      const { keyframes, options } = getAnimation(this, "select.show", { dir: this.localize.dir() });
      await animateTo(this.popup.popup, keyframes, options);
      this.emit("flow-ui-after-show");
    } else {
      this.emit("flow-ui-hide");
      this.removeOpenListeners();
      await stopAnimations(this);
      const { keyframes, options } = getAnimation(this, "select.hide", { dir: this.localize.dir() });
      await animateTo(this.popup.popup, keyframes, options);
      this.calendarContainer.hidden = true;
      this.popup.active = false;
      this.emit("flow-ui-after-hide");
    }
  }
  /** Shows the calendar. */
  async show() {
    if (this.open || this.disabled) {
      this.open = false;
      return void 0;
    }
    this.open = true;
    return waitForEvent(this, "flow-ui-after-show");
  }
  /** Hides the calendar. */
  async hide() {
    if (!this.open || this.disabled) {
      this.open = false;
      return void 0;
    }
    this.open = false;
    return waitForEvent(this, "flow-ui-after-hide");
  }
  /** Checks for validity but does not show a validation message. Returns `true` when valid and `false` when invalid. */
  checkValidity() {
    return this.valueInput.checkValidity();
  }
  /** 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() {
    return this.valueInput.reportValidity();
  }
  /** Sets a custom validation message. Pass an empty string to restore validity. */
  setCustomValidity(message) {
    this.valueInput.setCustomValidity(message);
    this.formControlController.updateValidity();
  }
  /** Sets focus on the control. */
  focus(options) {
    this.displayInput.focus(options);
  }
  /** Removes focus from the control. */
  blur() {
    this.displayInput.blur();
  }
  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 hasClearIcon = this.clearable && !this.disabled && this.value.length > 0;
    const isPlaceholderVisible = this.placeholder && this.value.length === 0;
    const popupOption = popupOptions[this.size] ?? popupOptions.medium;
    return html`
      <div
        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--filled": this.filled,
      "form-control--has-label": hasLabel,
      "form-control--has-help-text": hasHelpText,
      "form-control--has-divider": this.divider,
      "form-control--inline": this.inline
    })}
      >
        <label
          id="label"
          part="form-control-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-popup
            class=${classMap({
      datepicker: true,
      "datepicker--standard": true,
      "datepicker--filled": this.filled,
      "datepicker--pill": this.pill,
      "datepicker--open": this.open,
      "datepicker--disabled": this.disabled,
      "datepicker--focused": this.hasFocus,
      "datepicker--placeholder-visible": isPlaceholderVisible,
      "datepicker--top": this.placement === "top",
      "datepicker--bottom": this.placement === "bottom",
      "datepicker--small": this.size === "small",
      "datepicker--medium": this.size === "medium",
      "datepicker--large": this.size === "large"
    })}
            placement=${this.placement}
            strategy=${this.hoist ? "fixed" : "absolute"}
            flip
            shift
            auto-size="both"
            arrow
            distance=${popupOption.distance}
            skidding=${popupOption.skidding}
            arrow-placement="end"
          >
            <div
              part="combobox"
              class="datepicker__combobox"
              slot="anchor"
              @keydown=${this.handleComboboxKeyDown}
              @mousedown=${this.handleComboboxMouseDown}
            >
              <slot part="prefix" name="prefix" class="datepicker__prefix"></slot>

              <div class="input__wrapper">
                <input
                  part="display-input"
                  class="datepicker__display-input"
                  type="text"
                  placeholder=${this.placeholder}
                  .disabled=${this.disabled}
                  .value=${this.displayLabel}
                  autocomplete="off"
                  spellcheck="false"
                  autocapitalize="off"
                  readonly
                  aria-controls="listbox"
                  aria-expanded=${this.open ? "true" : "false"}
                  aria-haspopup="listbox"
                  aria-labelledby="label"
                  aria-disabled=${this.disabled ? "true" : "false"}
                  aria-describedby="help-text"
                  role="combobox"
                  tabindex="0"
                  @focus=${this.handleFocus}
                  @blur=${this.handleBlur}
                />
                <span class="input__sizer">${this.displayLabel || this.placeholder}</span>
              </div>

              <input
                class="datepicker__value-input"
                type="text"
                ?disabled=${this.disabled}
                ?required=${this.required}
                .value=${this.value}
                tabindex="-1"
                aria-hidden="true"
                @focus=${() => this.focus()}
                @invalid=${this.handleInvalid}
              />

              ${hasClearIcon ? html`
                    <button
                      part="clear-button"
                      class="datepicker__clear"
                      type="button"
                      aria-label=${this.localize.term("clearEntry")}
                      @mousedown=${this.handleClearMouseDown}
                      @click=${this.handleClearClick}
                      tabindex="-1"
                    >
                      <slot name="clear-icon">
                        <flow-ui-icon name="x-circle-fill" library="system"></flow-ui-icon>
                      </slot>
                    </button>
                  ` : ""}

              <slot name="mode-icon" part="mode-icon" class="datepicker__mode-icon">
                <flow-ui-icon
                  library="system"
                  name=${this.displayMode === "time" ? "clock" : "calendar"}
                ></flow-ui-icon>
              </slot>
            </div>

            <div part="calendar-container" class="datepicker__calendar-container" tabindex="-1">
              ${this.open ? html`
                    <flow-ui-calendar
                      value=${this.value}
                      display-mode=${this.displayMode}
                      size=${this.size}
                      timezone=${ifDefined(this.timezone)}
                      locale=${ifDefined(this.locale)}
                      @flow-ui-change=${this.handleCalendarChange}
                    ></flow-ui-calendar>
                  ` : nothing}
            </div>
          </flow-ui-popup>
        </div>

        ${this.divider ? this.renderDivider() : nothing}
      </div>
    `;
  }
}
FlowUiDateTimePicker.styles = styles;
__decorateClass([
  query(".datepicker")
], FlowUiDateTimePicker.prototype, "popup", 2);
__decorateClass([
  query(".datepicker__display-input")
], FlowUiDateTimePicker.prototype, "displayInput", 2);
__decorateClass([
  query(".datepicker__value-input")
], FlowUiDateTimePicker.prototype, "valueInput", 2);
__decorateClass([
  query(".datepicker__calendar-container")
], FlowUiDateTimePicker.prototype, "calendarContainer", 2);
__decorateClass([
  state()
], FlowUiDateTimePicker.prototype, "hasFocus", 2);
__decorateClass([
  state()
], FlowUiDateTimePicker.prototype, "displayLabel", 2);
__decorateClass([
  property()
], FlowUiDateTimePicker.prototype, "name", 2);
__decorateClass([
  property({ reflect: true })
], FlowUiDateTimePicker.prototype, "value", 2);
__decorateClass([
  property({ attribute: "display-mode" })
], FlowUiDateTimePicker.prototype, "displayMode", 2);
__decorateClass([
  property()
], FlowUiDateTimePicker.prototype, "format", 2);
__decorateClass([
  property()
], FlowUiDateTimePicker.prototype, "timezone", 2);
__decorateClass([
  property()
], FlowUiDateTimePicker.prototype, "locale", 2);
__decorateClass([
  defaultValue()
], FlowUiDateTimePicker.prototype, "defaultValue", 2);
__decorateClass([
  property({ reflect: true })
], FlowUiDateTimePicker.prototype, "size", 2);
__decorateClass([
  property()
], FlowUiDateTimePicker.prototype, "placeholder", 2);
__decorateClass([
  property({ type: Boolean, reflect: true })
], FlowUiDateTimePicker.prototype, "disabled", 2);
__decorateClass([
  property({ type: Boolean })
], FlowUiDateTimePicker.prototype, "clearable", 2);
__decorateClass([
  property({ type: Boolean, reflect: true })
], FlowUiDateTimePicker.prototype, "open", 2);
__decorateClass([
  property({ type: Boolean })
], FlowUiDateTimePicker.prototype, "hoist", 2);
__decorateClass([
  property({ type: Boolean, reflect: true })
], FlowUiDateTimePicker.prototype, "filled", 2);
__decorateClass([
  property({ type: Boolean, reflect: true })
], FlowUiDateTimePicker.prototype, "pill", 2);
__decorateClass([
  property()
], FlowUiDateTimePicker.prototype, "label", 2);
__decorateClass([
  property({ reflect: true })
], FlowUiDateTimePicker.prototype, "placement", 2);
__decorateClass([
  property({ attribute: "help-text" })
], FlowUiDateTimePicker.prototype, "helpText", 2);
__decorateClass([
  property({ reflect: true })
], FlowUiDateTimePicker.prototype, "form", 2);
__decorateClass([
  property({ type: Boolean, reflect: true })
], FlowUiDateTimePicker.prototype, "required", 2);
__decorateClass([
  property({ type: Boolean, reflect: true })
], FlowUiDateTimePicker.prototype, "inline", 2);
__decorateClass([
  property({ type: Boolean, reflect: true })
], FlowUiDateTimePicker.prototype, "divider", 2);
__decorateClass([
  watch(["value", "format", "timezone", "locale"])
], FlowUiDateTimePicker.prototype, "updateDisplayLabel", 1);
__decorateClass([
  watch("disabled", { waitUntilFirstUpdate: true })
], FlowUiDateTimePicker.prototype, "handleDisabledChange", 1);
__decorateClass([
  watch("value", { waitUntilFirstUpdate: true })
], FlowUiDateTimePicker.prototype, "handleValueChange", 1);
__decorateClass([
  watch("open", { waitUntilFirstUpdate: true })
], FlowUiDateTimePicker.prototype, "handleOpenChange", 1);
setDefaultAnimation("datetimepicker.show", {
  keyframes: [
    { opacity: 0, scale: 0.9 },
    { opacity: 1, scale: 1 }
  ],
  options: { duration: 100, easing: "ease" }
});
setDefaultAnimation("datetimepicker.hide", {
  keyframes: [
    { opacity: 1, scale: 1 },
    { opacity: 0, scale: 0.9 }
  ],
  options: { duration: 100, easing: "ease" }
});

export { FlowUiDateTimePicker as default };
