import { html, nothing } from 'lit';
import { query, property } from 'lit/decorators.js';
import { classMap } from 'lit/directives/class-map.js';
import { ifDefined } from 'lit/directives/if-defined.js';
import { animateTo, stopAnimations } from '../../internal/animate.mjs';
import { boolean } from '../../internal/boolean.mjs';
import { waitForEvent } from '../../internal/event.mjs';
import FlowRdfElement from '../../internal/flow-ui-rdf-element.mjs';
import Modal from '../../internal/modal.mjs';
import { lockBodyScrolling, unlockBodyScrolling } from '../../internal/scroll.mjs';
import { HasSlotController } from '../../internal/slot.mjs';
import { capitalize } from '../../internal/string.mjs';
import { watch } from '../../internal/watch.mjs';
import { getAnimation, setDefaultAnimation } from '../../utilities/animation-registry.mjs';
import { LocalizeController } from '../../utilities/localize.mjs';
import styles from './dialog.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 FlowUiDialog extends FlowRdfElement {
  constructor() {
    super(...arguments);
    this.hasSlotController = new HasSlotController(this, "footer");
    this.localize = new LocalizeController(this);
    this.open = false;
    this.title = "";
    this.noHeader = false;
    this.tabbed = false;
  }
  connectedCallback() {
    super.connectedCallback();
    this.noHeader = boolean(this.noHeader, true);
    this.open = boolean(this.open, true);
    this.tabbed = boolean(this.tabbed, true);
    this.handleDocumentKeyDown = this.handleDocumentKeyDown.bind(this);
    this.modal = new Modal(this);
  }
  firstUpdated() {
    this.dialog.hidden = !this.open;
    if (this.open) {
      this.addOpenListeners();
      this.modal.activate();
      lockBodyScrolling(this);
    }
    if (this.tabbed) {
      this.tabGroup.updateComplete.then(() => this.syncTabbedDialog());
    }
  }
  disconnectedCallback() {
    super.disconnectedCallback();
    unlockBodyScrolling(this);
  }
  requestClose(source) {
    const slRequestClose = this.emit("flow-ui-request-close", {
      cancelable: true,
      detail: { source }
    });
    if (slRequestClose.defaultPrevented) {
      const animation = getAnimation(this, "dialog.denyClose", { dir: this.localize.dir() });
      animateTo(this.panel, animation.keyframes, animation.options);
      return;
    }
    this.hide();
  }
  addOpenListeners() {
    document.addEventListener("keydown", this.handleDocumentKeyDown);
  }
  removeOpenListeners() {
    document.removeEventListener("keydown", this.handleDocumentKeyDown);
  }
  handleDocumentKeyDown(event) {
    if (this.open && event.key === "Escape") {
      event.stopPropagation();
      this.requestClose("keyboard");
    }
  }
  async handleOpenChange() {
    if (this.open) {
      this.emit("flow-ui-show");
      this.addOpenListeners();
      this.originalTrigger = document.activeElement;
      this.modal.activate();
      lockBodyScrolling(this);
      const autoFocusTarget = this.querySelector("[autofocus]");
      if (autoFocusTarget) {
        autoFocusTarget.removeAttribute("autofocus");
      }
      await Promise.all([stopAnimations(this.dialog), stopAnimations(this.overlay)]);
      this.dialog.hidden = false;
      requestAnimationFrame(() => {
        const slInitialFocus = this.emit("flow-ui-initial-focus", { cancelable: true });
        if (!slInitialFocus.defaultPrevented) {
          if (autoFocusTarget) {
            autoFocusTarget.focus({ preventScroll: true });
          } else {
            this.panel.focus({ preventScroll: true });
          }
        }
        if (autoFocusTarget) {
          autoFocusTarget.setAttribute("autofocus", "");
        }
      });
      const panelAnimation = getAnimation(this, "dialog.show", { dir: this.localize.dir() });
      const overlayAnimation = getAnimation(this, "dialog.overlay.show", { dir: this.localize.dir() });
      await Promise.all([
        animateTo(this.panel, panelAnimation.keyframes, panelAnimation.options),
        animateTo(this.overlay, overlayAnimation.keyframes, overlayAnimation.options)
      ]);
      this.emit("flow-ui-after-show");
    } else {
      this.emit("flow-ui-hide");
      this.removeOpenListeners();
      this.modal.deactivate();
      await Promise.all([stopAnimations(this.dialog), stopAnimations(this.overlay)]);
      const panelAnimation = getAnimation(this, "dialog.hide", { dir: this.localize.dir() });
      const overlayAnimation = getAnimation(this, "dialog.overlay.hide", { dir: this.localize.dir() });
      await Promise.all([
        animateTo(this.overlay, overlayAnimation.keyframes, overlayAnimation.options).then(() => {
          this.overlay.hidden = true;
        }),
        animateTo(this.panel, panelAnimation.keyframes, panelAnimation.options).then(() => {
          this.panel.hidden = true;
        })
      ]);
      this.dialog.hidden = true;
      this.overlay.hidden = false;
      this.panel.hidden = false;
      unlockBodyScrolling(this);
      const trigger = this.originalTrigger;
      if (typeof trigger?.focus === "function") {
        setTimeout(() => trigger.focus());
      }
      this.emit("flow-ui-after-hide");
    }
  }
  /** Shows the dialog. */
  async show() {
    if (this.open) {
      return void 0;
    }
    this.open = true;
    return waitForEvent(this, "flow-ui-after-show");
  }
  /** Hides the dialog */
  async hide() {
    if (!this.open) {
      return void 0;
    }
    this.open = false;
    return waitForEvent(this, "flow-ui-after-hide");
  }
  handleTabShow() {
    this.syncTabbedDialog();
  }
  syncTabbedDialog() {
    this.title = capitalize(this.tabGroup.activeTab?.panel) || "";
  }
  handleChildHide(ev) {
    ev.stopPropagation();
  }
  renderHeader(slot) {
    return html`
      <header slot=${ifDefined(slot)} part="header" class="dialog__header">
        <h2 part="heading" class="dialog__title" id="heading">
          <slot name="title">${this.title.length > 0 ? this.title : String.fromCharCode(65279)}</slot>
        </h2>
        <div part="header-actions" class="dialog__header-actions">
          <slot name="header-actions"></slot>
          <flow-ui-icon-button
            part="close-button"
            exportparts="base:close-button__base"
            class="dialog__close"
            name="x-lg"
            label=${this.localize.term("close")}
            library="system"
            @click="${() => this.requestClose("close-button")}"
          ></flow-ui-icon-button>
        </div>
      </header>
    `;
  }
  renderTabContainer() {
    return html`
      <flow-ui-tab-group class="dialog__tab-group" exportparts="nav:tab-group__nav,tabs:tab-group__tabs,active-tab-indicator:tab-group__active-tab-indicator,body:tab-group__tab-group-body" placement="start" @flow-ui-tab-show=${this.handleTabShow}>
        ${!this.noHeader ? this.renderHeader("header") : nothing}</slot>
        <slot name="nav" slot="nav"></slot>
        <slot @flow-ui-hide=${this.handleChildHide} @flow-ui-after-hide=${this.handleChildHide}></slot>
      </flow-ui-tab-group>
    `;
  }
  renderDefaultContainer() {
    return html`
      ${!this.noHeader ? this.renderHeader() : nothing}

      <slot
        part="body"
        class=${classMap({
      dialog__body: true
    })}
        @flow-ui-hide=${this.handleChildHide}
        @flow-ui-after-hide=${this.handleChildHide}
      ></slot>

      <footer part="footer" class="dialog__footer">
        <slot name="footer"></slot>
      </footer>
    `;
  }
  render() {
    return html`
      <div
        part="base"
        class=${classMap({
      dialog: true,
      "dialog--open": this.open,
      "dialog--has-footer": this.hasSlotController.test("footer")
    })}
        title=""
      >
        <div part="overlay" class="dialog__overlay" @click=${() => this.requestClose("overlay")} tabindex="-1"></div>

        <div
          part="panel"
          class="dialog__panel"
          role="dialog"
          aria-modal="true"
          aria-hidden=${this.open ? "false" : "true"}
          aria-label=${ifDefined(this.noHeader ? this.title : void 0)}
          aria-labelledby=${ifDefined(!this.noHeader ? "title" : void 0)}
          tabindex="0"
        >
          ${this.tabbed ? this.renderTabContainer() : this.renderDefaultContainer()}
        </div>
      </div>
    `;
  }
}
FlowUiDialog.styles = styles;
__decorateClass([
  query(".dialog")
], FlowUiDialog.prototype, "dialog", 2);
__decorateClass([
  query(".dialog__panel")
], FlowUiDialog.prototype, "panel", 2);
__decorateClass([
  query(".dialog__overlay")
], FlowUiDialog.prototype, "overlay", 2);
__decorateClass([
  query(".dialog__tab-group")
], FlowUiDialog.prototype, "tabGroup", 2);
__decorateClass([
  property({ type: Boolean, reflect: true })
], FlowUiDialog.prototype, "open", 2);
__decorateClass([
  property({ reflect: true })
], FlowUiDialog.prototype, "title", 2);
__decorateClass([
  property({ attribute: "no-header", type: Boolean, reflect: true })
], FlowUiDialog.prototype, "noHeader", 2);
__decorateClass([
  property({ type: Boolean, reflect: true })
], FlowUiDialog.prototype, "tabbed", 2);
__decorateClass([
  watch("open", { waitUntilFirstUpdate: true })
], FlowUiDialog.prototype, "handleOpenChange", 1);
setDefaultAnimation("dialog.show", {
  keyframes: [
    { opacity: 0, scale: 0.8 },
    { opacity: 1, scale: 1 }
  ],
  options: { duration: 250, easing: "ease" }
});
setDefaultAnimation("dialog.hide", {
  keyframes: [
    { opacity: 1, scale: 1 },
    { opacity: 0, scale: 0.8 }
  ],
  options: { duration: 250, easing: "ease" }
});
setDefaultAnimation("dialog.denyClose", {
  keyframes: [{ scale: 1 }, { scale: 1.02 }, { scale: 1 }],
  options: { duration: 250 }
});
setDefaultAnimation("dialog.overlay.show", {
  keyframes: [{ opacity: 0 }, { opacity: 1 }],
  options: { duration: 250 }
});
setDefaultAnimation("dialog.overlay.hide", {
  keyframes: [{ opacity: 1 }, { opacity: 0 }],
  options: { duration: 250 }
});

export { FlowUiDialog as default };
