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 FlowRdfElement from '../../internal/flow-ui-rdf-element.mjs';
import { scrollIntoView } from '../../internal/scroll.mjs';
import { HasSlotController } from '../../internal/slot.mjs';
import { watch } from '../../internal/watch.mjs';
import { LocalizeController } from '../../utilities/localize.mjs';
import styles from './tab-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 FlowUiTabGroup extends FlowRdfElement {
  constructor() {
    super(...arguments);
    this.localize = new LocalizeController(this);
    this.hasSlotController = new HasSlotController(this, "nav-accessories-start", "nav-accessories-end");
    this.tabs = [];
    this.panels = [];
    this.hasScrollControls = false;
    this.placement = "top";
    this.activation = "auto";
    this.noScrollControls = false;
  }
  connectedCallback() {
    super.connectedCallback();
    this.noScrollControls = boolean(this.noScrollControls, true);
    this.controlSplitView = boolean(this.controlSplitView, true);
    this.resizeObserver = new ResizeObserver(() => {
      this.repositionIndicator();
      this.updateScrollControls();
    });
    this.mutationObserver = new MutationObserver((mutations) => {
      if (mutations.some((m) => !["aria-labelledby", "aria-controls"].includes(m.attributeName))) {
        setTimeout(() => this.setAriaLabels());
      }
      if (mutations.some((m) => m.attributeName === "disabled")) {
        this.syncTabsAndPanels();
      } else if (mutations.some((m) => m.attributeName === "active")) {
        const tabs = mutations.filter(
          (m) => m.attributeName === "active" && m.target.tagName.toLowerCase() === "flow-ui-tab"
        ).map((m) => m.target);
        const newActiveTab = tabs.find((tab) => tab.active);
        if (newActiveTab) {
          this.setActiveTab(newActiveTab);
        }
      }
    });
    this.updateComplete.then(() => {
      this.syncTabsAndPanels();
      this.setActiveTab(this.tabs.find((el) => el.active) ?? this.tabs[0], { emitEvents: false });
      this.mutationObserver.observe(this, { attributes: true, childList: true, subtree: true });
      this.resizeObserver.observe(this.nav);
    });
  }
  disconnectedCallback() {
    this.mutationObserver.disconnect();
    this.resizeObserver.unobserve(this.nav);
  }
  getAllTabs(options = { includeDisabled: true }) {
    let slot = this.shadowRoot.querySelector('slot[name="nav"]');
    if (slot.assignedElements().length === 1 && slot.assignedElements()[0].tagName.toLowerCase() === "slot") {
      slot = slot.assignedElements()[0];
    }
    return [...slot.assignedElements()].filter((el) => {
      return options.includeDisabled ? el.tagName.toLowerCase() === "flow-ui-tab" : el.tagName.toLowerCase() === "flow-ui-tab" && !el.disabled;
    });
  }
  get activeTab() {
    return this._activeTab;
  }
  getAllPanels() {
    let slot = this.body;
    if (slot.assignedElements().length === 1 && slot.assignedElements()[0].tagName.toLowerCase() === "slot") {
      slot = slot.assignedElements()[0];
    }
    return [...slot.assignedElements()].filter((el) => el.tagName.toLowerCase() === "flow-ui-tab-panel");
  }
  handleClick(event) {
    const target = event.target;
    const tab = target.closest("flow-ui-tab");
    const tabGroup = tab?.tabGroup;
    if (tabGroup !== this) {
      return;
    }
    if (this.controlSplitView && !tab?.disabled) {
      const parentSplitPanel = this.closest("flow-ui-split-view-pane");
      if (parentSplitPanel) {
        if (tab === this._activeTab) {
          if (parentSplitPanel.closed) {
            parentSplitPanel.expand();
          } else {
            parentSplitPanel.collapse();
          }
        } else {
          if (parentSplitPanel.closed) {
            parentSplitPanel.expand();
          }
        }
      }
    }
    if (tab !== null) {
      this.setActiveTab(tab, { scrollBehavior: "smooth" });
    }
    if (tab === this._activeTab && !tab.disabled) {
      this.emit("flow-ui-panel-toggle");
    } else if (tab !== null) {
      this.setActiveTab(tab, { scrollBehavior: "smooth" });
    }
  }
  handleKeyDown(event) {
    const target = event.target;
    const tab = target.closest("flow-ui-tab");
    const tabGroup = tab?.tabGroup ?? tab?.closest("flow-ui-tab-group");
    if (tabGroup !== this) {
      return;
    }
    if (["Enter", " "].includes(event.key)) {
      if (tab !== null) {
        this.setActiveTab(tab, { scrollBehavior: "smooth" });
        event.preventDefault();
      }
    }
    if (["ArrowLeft", "ArrowRight", "ArrowUp", "ArrowDown", "Home", "End"].includes(event.key)) {
      const activeEl = this.tabs.find((t) => t.matches(":focus"));
      const isRtl = this.localize.dir() === "rtl";
      if (activeEl?.tagName.toLowerCase() === "flow-ui-tab") {
        let index = this.tabs.indexOf(activeEl);
        if (event.key === "Home") {
          index = 0;
        } else if (event.key === "End") {
          index = this.tabs.length - 1;
        } else if (["top", "bottom"].includes(this.placement) && event.key === (isRtl ? "ArrowRight" : "ArrowLeft") || ["start", "end"].includes(this.placement) && event.key === "ArrowUp") {
          index--;
        } else if (["top", "bottom"].includes(this.placement) && event.key === (isRtl ? "ArrowLeft" : "ArrowRight") || ["start", "end"].includes(this.placement) && event.key === "ArrowDown") {
          index++;
        }
        if (index < 0) {
          index = this.tabs.length - 1;
        }
        if (index > this.tabs.length - 1) {
          index = 0;
        }
        this.tabs[index].focus({ preventScroll: true });
        if (this.activation === "auto") {
          this.setActiveTab(this.tabs[index], { scrollBehavior: "smooth" });
        }
        scrollIntoView(this.tabs[index], this.nav, this.isHorizontal() ? "horizontal" : "vertical");
        event.preventDefault();
      }
    }
  }
  handleScrollToStart() {
    if (this.isHorizontal()) {
      this.nav.scroll({
        left: this.localize.dir() === "rtl" ? this.nav.scrollLeft + this.nav.clientWidth : this.nav.scrollLeft - this.nav.clientWidth,
        behavior: "smooth"
      });
    } else {
      this.nav.scroll({
        top: this.nav.scrollTop - this.nav.clientHeight,
        behavior: "smooth"
      });
    }
  }
  handleScrollToEnd() {
    if (this.isHorizontal()) {
      this.nav.scroll({
        left: this.localize.dir() === "rtl" ? this.nav.scrollLeft - this.nav.clientWidth : this.nav.scrollLeft + this.nav.clientWidth,
        behavior: "smooth"
      });
    } else {
      this.nav.scroll({
        top: this.nav.scrollTop + this.nav.clientHeight,
        behavior: "smooth"
      });
    }
  }
  isHorizontal() {
    return ["top", "bottom"].includes(this.placement);
  }
  setActiveTab(tab, options) {
    options = {
      emitEvents: true,
      scrollBehavior: "auto",
      ...options
    };
    if (tab !== this._activeTab && !tab.disabled) {
      const previousTab = this._activeTab;
      this._activeTab = tab;
      this.tabs.forEach((el) => el.active = el === this._activeTab);
      this.panels.forEach((el) => el.active = el.name === this._activeTab?.panel);
      this.syncIndicator();
      if (["top", "bottom"].includes(this.placement)) {
        scrollIntoView(this._activeTab, this.nav, "horizontal", options.scrollBehavior);
      }
      if (options.emitEvents) {
        if (previousTab) {
          this.emit("flow-ui-tab-hide", { detail: { name: previousTab.panel } });
        }
        this.emit("flow-ui-tab-show", { detail: { name: this._activeTab.panel } });
      }
    }
  }
  setAriaLabels() {
    this.tabs.forEach((tab) => {
      const panel = this.panels.find((el) => el.name === tab.panel);
      if (panel) {
        tab.setAttribute("aria-controls", panel.getAttribute("id"));
        panel.setAttribute("aria-labelledby", tab.getAttribute("id"));
      }
    });
  }
  repositionIndicator() {
    const currentTab = this.activeTab;
    if (!currentTab) {
      return;
    }
    const width = currentTab.clientWidth;
    const height = currentTab.clientHeight;
    const isRtl = this.localize.dir() === "rtl";
    const allTabs = this.getAllTabs();
    const precedingTabs = allTabs.slice(0, allTabs.indexOf(currentTab));
    const offset = precedingTabs.reduce(
      (previous, current) => ({
        left: previous.left + current.clientWidth,
        top: previous.top + current.clientHeight
      }),
      { left: 0, top: 0 }
    );
    switch (this.placement) {
      case "top":
      case "bottom":
        this.indicator.style.width = `${width}px`;
        this.indicator.style.height = "auto";
        this.indicator.style.translate = isRtl ? `${-1 * offset.left}px` : `${offset.left}px`;
        break;
      case "start":
      case "end":
        this.indicator.style.width = "auto";
        this.indicator.style.height = `${height}px`;
        this.indicator.style.translate = `0 ${offset.top}px`;
        break;
    }
  }
  // This stores tabs and panels so we can refer to a cache instead of calling querySelectorAll() multiple times.
  syncTabsAndPanels() {
    this.tabs = this.getAllTabs({ includeDisabled: false });
    this.panels = this.getAllPanels();
    this.tabs.forEach((tab) => {
      tab.tabGroup = this;
      tab.placement = this.placement;
    });
    if (this._activeTab && this.tabs.includes(this._activeTab) === false) {
      this.setActiveTab(this.tabs.find((el) => !el.disabled) ?? this.tabs[0], { emitEvents: true });
    } else {
      this.syncIndicator();
      this.updateComplete.then(() => this.updateScrollControls());
    }
  }
  updateScrollControls() {
    if (this.noScrollControls) {
      this.hasScrollControls = false;
    } else if (["top", "bottom"].includes(this.placement)) {
      this.hasScrollControls = this.nav.scrollWidth > this.nav.clientWidth;
    } else {
      this.hasScrollControls = this.nav.scrollHeight > this.nav.clientHeight;
    }
  }
  syncIndicator() {
    const tab = this.activeTab;
    if (tab) {
      this.indicator.style.display = "block";
      this.repositionIndicator();
    } else {
      this.indicator.style.display = "none";
    }
  }
  /** Shows the specified tab panel. */
  show(panel) {
    const tab = this.tabs.find((el) => el.panel === panel);
    if (tab) {
      this.setActiveTab(tab, { scrollBehavior: "smooth" });
    }
  }
  render() {
    const isRtl = this.localize.dir() === "rtl";
    return html`
      <div
        part="base"
        class=${classMap({
      "tab-group": true,
      "tab-group--top": this.placement === "top",
      "tab-group--bottom": this.placement === "bottom",
      "tab-group--start": this.placement === "start",
      "tab-group--end": this.placement === "end",
      "tab-group--rtl": this.localize.dir() === "rtl",
      "tab-group--has-scroll-controls": this.hasScrollControls
    })}
        @click=${this.handleClick}
        @keydown=${this.handleKeyDown}
      >
        <div class="tab-group__nav-container" part="nav">
          <div class="tab-group__track"></div>

          ${this.hasSlotController.test("nav-accessories-start") ? html`
                <div class="tab-group__nav-accessories tab-group__nav-accessories--start" part="nav-accessories-start">
                  <slot name="nav-accessories-start"></slot>
                </div>
                <flow-ui-divider
                  class="tab-group__accessory-divider"
                  part="accessory-divider"
                  ?vertical=${this.isHorizontal()}
                ></flow-ui-divider>
              ` : ""}
          ${this.hasScrollControls ? html`
                <flow-ui-icon-button
                  part="scroll-button scroll-button--start"
                  exportparts="base:scroll-button__base"
                  class="tab-group__scroll-button tab-group__scroll-button--start"
                  name=${this.isHorizontal() ? isRtl ? "chevron-right" : "chevron-left" : "chevron-up"}
                  library="system"
                  label=${this.localize.term("scrollToStart")}
                  @click=${this.handleScrollToStart}
                ></flow-ui-icon-button>
              ` : ""}

          <div class="tab-group__nav">
            <div part="tabs" class="tab-group__tabs" role="tablist">
              <div part="active-tab-indicator" class="tab-group__indicator"></div>
              <slot name="nav" @slotchange=${this.syncTabsAndPanels}></slot>
            </div>
          </div>

          ${this.hasScrollControls ? html`
                <flow-ui-icon-button
                  part="scroll-button scroll-button--end"
                  exportparts="base:scroll-button__base"
                  class="tab-group__scroll-button tab-group__scroll-button--end"
                  name=${this.isHorizontal() ? isRtl ? "chevron-left" : "chevron-right" : "chevron-down"}
                  library="system"
                  label=${this.localize.term("scrollToEnd")}
                  @click=${this.handleScrollToEnd}
                ></flow-ui-icon-button>
              ` : ""}
          ${this.hasSlotController.test("nav-accessories-end") ? html`
                <flow-ui-divider
                  class="tab-group__accessory-divider"
                  part="accessory-divider"
                  ?vertical=${this.isHorizontal()}
                ></flow-ui-divider>
                <div class="tab-group__nav-accessories tab-group__nav-accessories--end" part="nav-accessories-end">
                  <slot name="nav-accessories-end"></slot>
                </div>
              ` : ""}
        </div>

        <div class="tab-group__body-wrapper">
          <slot name="header" part="header" class="tab-group__header"></slot>
          <slot part="body" class="tab-group__body" @slotchange=${this.syncTabsAndPanels}></slot>
          <slot name="footer" part="footer" class="tab-group__footer"></slot>
        </div>
      </div>
    `;
  }
}
FlowUiTabGroup.styles = styles;
__decorateClass([
  query(".tab-group")
], FlowUiTabGroup.prototype, "tabGroup", 2);
__decorateClass([
  query(".tab-group__body")
], FlowUiTabGroup.prototype, "body", 2);
__decorateClass([
  query(".tab-group__nav")
], FlowUiTabGroup.prototype, "nav", 2);
__decorateClass([
  query(".tab-group__indicator")
], FlowUiTabGroup.prototype, "indicator", 2);
__decorateClass([
  state()
], FlowUiTabGroup.prototype, "hasScrollControls", 2);
__decorateClass([
  property()
], FlowUiTabGroup.prototype, "placement", 2);
__decorateClass([
  property()
], FlowUiTabGroup.prototype, "activation", 2);
__decorateClass([
  property({ attribute: "no-scroll-controls", type: Boolean })
], FlowUiTabGroup.prototype, "noScrollControls", 2);
__decorateClass([
  property({ type: Boolean, attribute: "control-split-view" })
], FlowUiTabGroup.prototype, "controlSplitView", 2);
__decorateClass([
  watch("noScrollControls", { waitUntilFirstUpdate: true })
], FlowUiTabGroup.prototype, "updateScrollControls", 1);
__decorateClass([
  watch("placement", { waitUntilFirstUpdate: true })
], FlowUiTabGroup.prototype, "syncIndicator", 1);

export { FlowUiTabGroup as default };
