/**
 * @license
 * Scale https://github.com/telekom/scale
 *
 * Copyright (c) 2021 Egor Kirpichev and contributors, Deutsche Telekom AG
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/.
 */
import { Component, Element, Event, Host, Method, Prop, Watch, h, State, Listen, } from '@stencil/core';
import { computePosition, offset, flip, shift, arrow } from '@floating-ui/dom';
import { isClickOutside } from '../../utils/utils';
let id = 0;
export class Tooltip {
  constructor() {
    this.componentId = `tooltip-${++id}`;
    /** (optional) The content of the Tooltip supporting Text only */
    this.content = '';
    /** (optional) Position of the Tooltip on the Object */
    this.placement = 'top';
    /** (optional) Disable Tooltip */
    this.disabled = false;
    /** (optional) Distance of the Tooltip from the Target Object (related to the `placement`) */
    this.distance = 5;
    /** (optional) Set the Tooltip to open per default (will still be closed on closing Events) */
    this.open = false;
    /** (optional) Set custom trigger Event selection */
    this.trigger = 'hover focus';
    /** (optional) Switching the flip option of the tooltip on and off */
    this.flip = true;
    this.mouseOverTooltip = false;
    this.update = () => {
      if (!this.disabled) {
        computePosition(Array.from(this.hostEl.children).find((x) => !x.hasAttribute('slot')), this.tooltipEl, {
          placement: this.placement,
          middleware: [
            offset(this.distance),
            ...(this.flip ? [flip()] : []),
            arrow({ element: this.arrowEl }),
            shift({ crossAxis: true }),
          ],
        }).then(({ x, y, placement, middlewareData }) => {
          Object.assign(this.tooltipEl.style, {
            left: `${x}px`,
            top: `${y}px`,
          });
          // Accessing the data
          const { x: arrowX, y: arrowY } = middlewareData.arrow;
          const staticSide = {
            top: 'bottom',
            right: 'left',
            bottom: 'top',
            left: 'right',
          }[placement.split('-')[0]];
          Object.assign(this.arrowEl.style, {
            left: arrowX != null ? `${arrowX}px` : '',
            top: arrowY != null ? `${arrowY}px` : '',
            right: '',
            bottom: '',
            [staticSide]: '-2.79px',
          });
        });
      }
    };
    this.handleBlur = () => {
      if (this.hasTrigger('focus')) {
        this.hideTooltip();
      }
    };
    this.handleClick = () => {
      if (this.hasTrigger('click')) {
        this.open && !this.hasTrigger('focus')
          ? this.hideTooltip()
          : this.showTooltip();
      }
    };
    this.handleFocus = () => {
      if (this.hasTrigger('focus')) {
        this.showTooltip();
      }
    };
    this.handleKeyDown = (event) => {
      if (this.open && event.key === 'Escape') {
        event.stopPropagation();
        this.hideTooltip();
      }
    };
    this.handleMouseOver = () => {
      if (this.hasTrigger('hover')) {
        this.showTooltip();
      }
    };
    this.handleMouseOut = () => {
      if (!this.mouseOverTooltip) {
        if (this.hasTrigger('hover')) {
          this.hideTooltip();
        }
      }
    };
    this.handleTooltipMouseOver = () => {
      this.mouseOverTooltip = true;
    };
    this.handleTooltipBlur = () => {
      this.mouseOverTooltip = false;
      this.handleMouseOut();
    };
    this.hasTrigger = (triggerType) => {
      const triggers = this.trigger.split(' ');
      return triggers.includes(triggerType);
    };
  }
  handleOpenChange() {
    this.open ? this.showTooltip() : this.hideTooltip();
  }
  componentDidLoad() {
    this.hostEl.addEventListener('blur', this.handleBlur, true);
    this.hostEl.addEventListener('click', this.handleClick, true);
    this.hostEl.addEventListener('focus', this.handleFocus, true);
  }
  disconnectedCallback() {
    this.hostEl.removeEventListener('blur', this.handleBlur, true);
    this.hostEl.removeEventListener('click', this.handleClick, true);
    this.hostEl.removeEventListener('focus', this.handleFocus, true);
  }
  handleOutsideClick(event) {
    if (isClickOutside(event, this.hostEl)) {
      this.hideTooltip();
    }
  }
  componentDidUpdate() {
    this.update();
    if (this.open) {
      this.showTooltip();
    }
  }
  componentDidRender() {
    this.update();
  }
  async showTooltip() {
    if (this.open) {
      return;
    }
    const scaleShow = this.tooltipBeforeShow.emit();
    if (scaleShow.defaultPrevented) {
      this.open = false;
      return;
    }
    this.open = true;
    this.update();
  }
  async hideTooltip() {
    if (!this.open) {
      return;
    }
    const tooltipBeforeHide = this.tooltipBeforeHide.emit();
    if (tooltipBeforeHide.defaultPrevented) {
      this.open = true;
      return;
    }
    this.open = false;
    this.update();
  }
  render() {
    return (h(Host, { onKeyDown: this.handleKeyDown, onMouseOver: this.handleMouseOver, onMouseOut: this.handleMouseOut },
      this.styles && h("style", null, this.styles),
      h("div", { part: "trigger", "aria-describedby": this.componentId },
        h("slot", null)),
      !this.disabled && (h("div", { part: "tooltip", role: "tooltip", "aria-hidden": this.open ? 'false' : 'true', ref: (el) => (this.tooltipEl = el), id: this.componentId, tabIndex: 0, onMouseOver: this.handleTooltipMouseOver, onMouseLeave: this.handleTooltipBlur },
        h("slot", { name: "content" }, this.content),
        h("div", { part: "arrow", ref: (el) => (this.arrowEl = el) })))));
  }
  static get is() { return "scale-tooltip"; }
  static get encapsulation() { return "shadow"; }
  static get originalStyleUrls() { return {
    "$": ["tooltip.css"]
  }; }
  static get styleUrls() { return {
    "$": ["tooltip.css"]
  }; }
  static get properties() { return {
    "content": {
      "type": "string",
      "mutable": false,
      "complexType": {
        "original": "string",
        "resolved": "string",
        "references": {}
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [],
        "text": "(optional) The content of the Tooltip supporting Text only"
      },
      "attribute": "content",
      "reflect": false,
      "defaultValue": "''"
    },
    "placement": {
      "type": "string",
      "mutable": false,
      "complexType": {
        "original": "| 'top'\n    | 'top-start'\n    | 'top-end'\n    | 'right'\n    | 'right-start'\n    | 'right-end'\n    | 'bottom'\n    | 'bottom-start'\n    | 'bottom-end'\n    | 'left'\n    | 'left-start'\n    | 'left-end'",
        "resolved": "\"bottom\" | \"bottom-end\" | \"bottom-start\" | \"left\" | \"left-end\" | \"left-start\" | \"right\" | \"right-end\" | \"right-start\" | \"top\" | \"top-end\" | \"top-start\"",
        "references": {}
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [],
        "text": "(optional) Position of the Tooltip on the Object"
      },
      "attribute": "placement",
      "reflect": false,
      "defaultValue": "'top'"
    },
    "disabled": {
      "type": "boolean",
      "mutable": false,
      "complexType": {
        "original": "boolean",
        "resolved": "boolean",
        "references": {}
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [],
        "text": "(optional) Disable Tooltip"
      },
      "attribute": "disabled",
      "reflect": false,
      "defaultValue": "false"
    },
    "distance": {
      "type": "number",
      "mutable": false,
      "complexType": {
        "original": "number",
        "resolved": "number",
        "references": {}
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [],
        "text": "(optional) Distance of the Tooltip from the Target Object (related to the `placement`)"
      },
      "attribute": "distance",
      "reflect": false,
      "defaultValue": "5"
    },
    "open": {
      "type": "boolean",
      "mutable": true,
      "complexType": {
        "original": "boolean",
        "resolved": "boolean",
        "references": {}
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [],
        "text": "(optional) Set the Tooltip to open per default (will still be closed on closing Events)"
      },
      "attribute": "open",
      "reflect": true,
      "defaultValue": "false"
    },
    "trigger": {
      "type": "string",
      "mutable": false,
      "complexType": {
        "original": "string",
        "resolved": "string",
        "references": {}
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [],
        "text": "(optional) Set custom trigger Event selection"
      },
      "attribute": "trigger",
      "reflect": false,
      "defaultValue": "'hover focus'"
    },
    "flip": {
      "type": "boolean",
      "mutable": false,
      "complexType": {
        "original": "boolean",
        "resolved": "boolean",
        "references": {}
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [],
        "text": "(optional) Switching the flip option of the tooltip on and off"
      },
      "attribute": "flip",
      "reflect": false,
      "defaultValue": "true"
    },
    "styles": {
      "type": "string",
      "mutable": false,
      "complexType": {
        "original": "string",
        "resolved": "string",
        "references": {}
      },
      "required": false,
      "optional": true,
      "docs": {
        "tags": [],
        "text": "(optional) Injected CSS styles"
      },
      "attribute": "styles",
      "reflect": false
    }
  }; }
  static get states() { return {
    "mouseOverTooltip": {}
  }; }
  static get events() { return [{
      "method": "tooltipBeforeShow",
      "name": "scale-before-show",
      "bubbles": true,
      "cancelable": true,
      "composed": true,
      "docs": {
        "tags": [],
        "text": ""
      },
      "complexType": {
        "original": "any",
        "resolved": "any",
        "references": {}
      }
    }, {
      "method": "tooltipShow",
      "name": "scale-show",
      "bubbles": true,
      "cancelable": true,
      "composed": true,
      "docs": {
        "tags": [],
        "text": ""
      },
      "complexType": {
        "original": "any",
        "resolved": "any",
        "references": {}
      }
    }, {
      "method": "tooltipBeforeHide",
      "name": "scale-before-hide",
      "bubbles": true,
      "cancelable": true,
      "composed": true,
      "docs": {
        "tags": [],
        "text": ""
      },
      "complexType": {
        "original": "any",
        "resolved": "any",
        "references": {}
      }
    }, {
      "method": "tooltipHide",
      "name": "scale-hide",
      "bubbles": true,
      "cancelable": true,
      "composed": true,
      "docs": {
        "tags": [],
        "text": ""
      },
      "complexType": {
        "original": "any",
        "resolved": "any",
        "references": {}
      }
    }]; }
  static get methods() { return {
    "showTooltip": {
      "complexType": {
        "signature": "() => Promise<void>",
        "parameters": [],
        "references": {
          "Promise": {
            "location": "global"
          }
        },
        "return": "Promise<void>"
      },
      "docs": {
        "text": "",
        "tags": []
      }
    },
    "hideTooltip": {
      "complexType": {
        "signature": "() => Promise<void>",
        "parameters": [],
        "references": {
          "Promise": {
            "location": "global"
          }
        },
        "return": "Promise<void>"
      },
      "docs": {
        "text": "",
        "tags": []
      }
    }
  }; }
  static get elementRef() { return "hostEl"; }
  static get watchers() { return [{
      "propName": "open",
      "methodName": "handleOpenChange"
    }]; }
  static get listeners() { return [{
      "name": "click",
      "method": "handleOutsideClick",
      "target": "document",
      "capture": false,
      "passive": false
    }]; }
}
