import { ElementIDUtils, ObjectUtils } from '@sankhyalabs/core';
import { h, Host } from '@stencil/core';
import { DropdownItem } from './structure/DropdownItem';
import { SubmenuControl } from './structure/SubmenuControl';
export class EzDropdown {
  constructor() {
    this._itemList = {};
    this._submenuList = [];
    this._openedMenuList = {};
    /**
     * Limitador de níveis de menu + submenu.
     * Valor 0, null ou undefined desativa o limitador.
     */
    this._levelLimits = 3;
    this.items = [];
    this.value = undefined;
    this.itemBuilder = undefined;
  }
  handleClickOutside(event) {
    if (!this._element.contains(event.target)) {
      this.ezOutsideClick.emit();
    }
  }
  //---------------------------------------------
  // Private methods
  //---------------------------------------------
  defaultItemBuilder(item, isLockedLevels, hasIcon, hasChildren) {
    return (h(DropdownItem, { item: item, hasIcon: hasIcon, hasChildren: hasChildren, isLockedLevels: isLockedLevels, onSubActionClick: this.onSubActionClick.bind(this) }));
  }
  getMaxOrder(items) {
    if (items == undefined || items.length === 0) {
      return -1;
    }
    return Math.max(...items.map((item) => {
      var _a;
      const order = (_a = item.group) === null || _a === void 0 ? void 0 : _a["order"];
      return order != undefined && order >= 0 ? order : -1;
    }));
  }
  hasIcon(items) {
    return items === null || items === void 0 ? void 0 : items.some((item) => (item.iconName || "") !== "");
  }
  hasGroup(items) {
    return items === null || items === void 0 ? void 0 : items.some((item) => (item.group || "") !== "");
  }
  hasChildren(items) {
    return items === null || items === void 0 ? void 0 : items.some((item) => (item.children || []).length > 0);
  }
  isLockedLevels(level) {
    if (!this._levelLimits) {
      return false;
    }
    return level === (this._levelLimits + 1);
  }
  getItemsByGroup(items, level) {
    let itemsByGroup = {};
    const maxOrder = this.getMaxOrder(items);
    items.forEach((item) => {
      const label = item.group && item.group["label"] != undefined ? item.group["label"] || "noGroup" : item.group || "noGroup";
      const order = item.group && item.group["order"] != undefined ? item.group["order"] : item.group ? (maxOrder + 1) : (maxOrder + 2);
      let groupObj = itemsByGroup[label];
      if (groupObj == undefined) {
        groupObj = {
          items: [],
          order
        };
      }
      this.validateItem(item, level);
      groupObj.items.push(item);
      itemsByGroup[label] = groupObj;
    });
    return ObjectUtils.sortByProperty(itemsByGroup, "order");
  }
  validateItem(item, level) {
    if (this._itemList == undefined) {
      this._itemList = {};
    }
    if (item.type == undefined) {
      item.type = "item";
    }
    if (item.id == undefined) {
      const itemId = `level_${level}_${item.type}`;
      const counter = Object.keys(this._itemList).filter((key) => key.includes(itemId)).length;
      item.id = `${itemId}_${counter + 1}`;
    }
    if (item.label == undefined) {
      item.label = "";
    }
    if (item.subAction != undefined) {
      if (item.subAction.id == undefined) {
        const subId = `subAction_${item.id}`;
        item.subAction.id = subId;
      }
      if (item.subAction.label == undefined) {
        item.subAction.label = "";
      }
    }
    if (this._itemList[item.id] == undefined) {
      this._itemList[item.id] = {};
    }
  }
  getContainerItemBuilder(item, level, isLockedLevels, hasIcon, hasChildren) {
    if (this.itemBuilder == undefined) {
      return;
    }
    const customContent = this.itemBuilder(item, level);
    if (customContent == undefined) {
      return this.defaultItemBuilder(item, isLockedLevels, hasIcon, hasChildren);
    }
    if (typeof customContent !== "string") {
      return (h("div", { class: "ez-dropdown__item-builder" }, customContent));
    }
    return (h("div", { class: "ez-dropdown__item-builder", innerHTML: customContent }));
  }
  getItemsRender(groupItems, level, hasIcon, hasChildren) {
    if (groupItems == undefined) {
      return;
    }
    let counterLevel = level;
    let isLockedLevels = false;
    if (hasChildren) {
      counterLevel++;
      isLockedLevels = this.isLockedLevels(counterLevel);
    }
    return groupItems.map((item) => {
      var _a;
      switch (item.type) {
        case "loading":
          return (h("div", { class: "ez-dropdown__item" }, h("ez-skeleton", { width: '200px' })));
        case "divider":
          return (h("hr", Object.assign({ class: "ez-dropdown__divider" }, { [ElementIDUtils.DATA_ELEMENT_ID_ATTRIBUTE_NAME]: ElementIDUtils.getInternalIDInfo(`${item.id}_ezDropdownDivider`) })));
        default:
          return (h("div", Object.assign({ ref: (ref) => this._itemList[item.id] = ref, class: "ez-dropdown__item", "data-level": level }, { [ElementIDUtils.DATA_ELEMENT_ID_ATTRIBUTE_NAME]: ElementIDUtils.getInternalIDInfo(`${item.id}_ezDropdownItem`) }), h("div", { class: "ez-dropdown__item-content", onClick: (evt) => this.onItemClick(evt, item), onMouseOver: (evt) => this.onShowSubmenu(evt, item), onMouseEnter: () => this.ezHover.emit(item) }, this.itemBuilder
            ? this.getContainerItemBuilder(item, level, isLockedLevels, hasIcon, hasChildren)
            : this.defaultItemBuilder(item, isLockedLevels, hasIcon, hasChildren)), ((_a = item.children) === null || _a === void 0 ? void 0 : _a.length) > 0 &&
            !isLockedLevels &&
            hasChildren &&
            h("div", { ref: (ref) => this._submenuList.push(ref), class: "ez-dropdown__submenu ez-dropdown__submenu--hide" }, this.renderDropdown(item.children, counterLevel))));
      }
    });
  }
  renderDropdown(branchItems = this.items, level = 1) {
    if (branchItems == undefined || this.isLockedLevels(level)) {
      return;
    }
    const itemsByGroup = this.getItemsByGroup(branchItems, level);
    const hasGroup = this.hasGroup(branchItems);
    const hasIcon = this.hasIcon(branchItems);
    const hasChildren = this.hasChildren(branchItems);
    return (h("div", { class: "ez-dropdown ez-dropdown__max-height", "data-level": level }, h("div", { class: "ez-dropdown__container" }, Object.keys(itemsByGroup)
      .map((groupLabel) => {
      return (h("div", Object.assign({ class: "ez-dropdown__group" }, { [ElementIDUtils.DATA_ELEMENT_ID_ATTRIBUTE_NAME]: ElementIDUtils.getInternalIDInfo(`${groupLabel}_ezDropdownGroup`) }), groupLabel !== "noGroup" &&
        h("label", { class: "ez-dropdown__group-label", title: groupLabel }, groupLabel), hasGroup &&
        groupLabel === "noGroup" &&
        h("hr", Object.assign({ class: "ez-dropdown__divider" }, { [ElementIDUtils.DATA_ELEMENT_ID_ATTRIBUTE_NAME]: ElementIDUtils.getInternalIDInfo(`${groupLabel}_ezDropdownDivider`) })), this.getItemsRender(itemsByGroup[groupLabel].items, level, hasIcon, hasChildren)));
    }))));
  }
  hasOpenedSubmenu(level) {
    const openedLevels = Object.keys(this._openedMenuList);
    return openedLevels.includes(level.toString())
      || openedLevels.some((openedLevel) => Number(openedLevel) > level);
  }
  hasSubmenuOpened() {
    var _a;
    return (_a = this._submenuList) === null || _a === void 0 ? void 0 : _a.some((submenu) => !submenu.classList.contains("ez-dropdown__submenu--hide"));
  }
  setEvents() {
    document.removeEventListener('click', this.onHideAllSubmenu.bind(this));
    document.addEventListener('click', this.onHideAllSubmenu.bind(this));
    document.removeEventListener('scroll', this.onSubmenuReposition.bind(this));
    document.addEventListener('scroll', this.onSubmenuReposition.bind(this));
  }
  //---------------------------------------------
  // Event handlers
  //---------------------------------------------
  onShowSubmenu(evt, item) {
    var _a;
    if (evt == undefined) {
      return;
    }
    const menu = this._itemList[item.id];
    if (!(menu === null || menu === void 0 ? void 0 : menu.classList.contains("ez-dropdown__item"))) {
      return;
    }
    const level = Number(menu.dataset.level || "0");
    if (this.hasOpenedSubmenu(level)) {
      this._submenuControl.hide(this._openedMenuList[level]);
      delete this._openedMenuList[level];
    }
    if (!((_a = item.children) === null || _a === void 0 ? void 0 : _a.length)) {
      return;
    }
    this._openedMenuList[menu.dataset.level] = menu;
    this._submenuControl.show(menu);
  }
  onItemClick(evt, item) {
    const target = evt === null || evt === void 0 ? void 0 : evt.target;
    if (target === null || target === void 0 ? void 0 : target.classList.contains("ez-dropdown__link")) {
      return;
    }
    this.value = item;
    this.ezClick.emit(item);
  }
  onSubActionClick(item) {
    this.ezSubActionClick.emit(item.subAction);
  }
  onHideAllSubmenu(evt = undefined) {
    const target = evt === null || evt === void 0 ? void 0 : evt.target;
    if (this.hasSubmenuOpened() && (target == undefined || (!target.closest(".ez-dropdown") && target.tagName !== "EZ-DROPDOWN"))) {
      this._openedMenuList = {};
      this._submenuList.forEach(this._submenuControl.reset.bind(this._submenuControl));
    }
  }
  onSubmenuReposition() {
    if (this._openedMenuList != undefined) {
      Object.keys(this._openedMenuList).forEach((key) => {
        const menu = this._openedMenuList[key];
        this._submenuControl.setPosition(menu);
      });
    }
  }
  //---------------------------------------------
  // Lifecycle web component
  //---------------------------------------------
  componentDidLoad() {
    ElementIDUtils.addIDInfo(this._element);
    this._submenuControl = new SubmenuControl();
    this._submenuControl.setMaxHeight(this._element);
  }
  componentDidUpdate() {
    this._submenuControl.setMaxHeight(this._element);
  }
  componentDidRender() {
    this.setEvents();
  }
  render() {
    return (h(Host, null, this.renderDropdown()));
  }
  static get is() { return "ez-dropdown"; }
  static get encapsulation() { return "shadow"; }
  static get originalStyleUrls() {
    return {
      "$": ["ez-dropdown.css"]
    };
  }
  static get styleUrls() {
    return {
      "$": ["ez-dropdown.css"]
    };
  }
  static get properties() {
    return {
      "items": {
        "type": "unknown",
        "mutable": true,
        "complexType": {
          "original": "Array<IDropdownItem>",
          "resolved": "IDropdownItem[]",
          "references": {
            "Array": {
              "location": "global"
            },
            "IDropdownItem": {
              "location": "import",
              "path": "./structure/DropdownItem"
            }
          }
        },
        "required": false,
        "optional": false,
        "docs": {
          "tags": [],
          "text": "Lista de itens que v\u00E3o ser apresentados no dropdown."
        },
        "defaultValue": "[]"
      },
      "value": {
        "type": "unknown",
        "mutable": true,
        "complexType": {
          "original": "IDropdownItem",
          "resolved": "IDropdownItem",
          "references": {
            "IDropdownItem": {
              "location": "import",
              "path": "./structure/DropdownItem"
            }
          }
        },
        "required": false,
        "optional": false,
        "docs": {
          "tags": [],
          "text": "\u00DAltimo item que recebeu o click."
        }
      },
      "itemBuilder": {
        "type": "unknown",
        "mutable": false,
        "complexType": {
          "original": "(item: IDropdownItem, level: number) => HTMLElement | string",
          "resolved": "(item: IDropdownItem, level: number) => string | HTMLElement",
          "references": {
            "IDropdownItem": {
              "location": "import",
              "path": "./structure/DropdownItem"
            },
            "HTMLElement": {
              "location": "global"
            }
          }
        },
        "required": false,
        "optional": false,
        "docs": {
          "tags": [],
          "text": "Fun\u00E7\u00E3o builder que possibilita alterar como o item da lista vai ser apresentado.\nObserva\u00E7\u00E3o: No react ele se transforma em VNode e n\u00E3o como HTMLElement."
        }
      }
    };
  }
  static get events() {
    return [{
        "method": "ezClick",
        "name": "ezClick",
        "bubbles": true,
        "cancelable": true,
        "composed": true,
        "docs": {
          "tags": [],
          "text": "Emitido quando ocorrer um click em um item da lista,\no IDropdownItem que recebeu o click deve ser enviado como data do evento."
        },
        "complexType": {
          "original": "IDropdownItem",
          "resolved": "IDropdownItem",
          "references": {
            "IDropdownItem": {
              "location": "import",
              "path": "./structure/DropdownItem"
            }
          }
        }
      }, {
        "method": "ezSubActionClick",
        "name": "ezSubActionClick",
        "bubbles": true,
        "cancelable": true,
        "composed": true,
        "docs": {
          "tags": [],
          "text": "Emitido quando ocorrer um click em uma a\u00E7\u00E3o secundaria do item, \no IDropdownSubAction deve ser enviado como data do evento."
        },
        "complexType": {
          "original": "IDropdownSubAction",
          "resolved": "IDropdownSubAction",
          "references": {
            "IDropdownSubAction": {
              "location": "import",
              "path": "./structure/DropdownItem"
            }
          }
        }
      }, {
        "method": "ezOutsideClick",
        "name": "ezOutsideClick",
        "bubbles": true,
        "cancelable": true,
        "composed": true,
        "docs": {
          "tags": [],
          "text": "Emitido quando ocorrer um click fora do componente."
        },
        "complexType": {
          "original": "void",
          "resolved": "void",
          "references": {}
        }
      }, {
        "method": "ezHover",
        "name": "ezHover",
        "bubbles": true,
        "cancelable": true,
        "composed": true,
        "docs": {
          "tags": [],
          "text": "Emitido quando ocorrer o ponteiro do mouse \u00E9 colocado sobre um item."
        },
        "complexType": {
          "original": "IDropdownItem",
          "resolved": "IDropdownItem",
          "references": {
            "IDropdownItem": {
              "location": "import",
              "path": "./structure/DropdownItem"
            }
          }
        }
      }];
  }
  static get elementRef() { return "_element"; }
  static get listeners() {
    return [{
        "name": "click",
        "method": "handleClickOutside",
        "target": "document",
        "capture": false,
        "passive": false
      }];
  }
}
