import { __decorate, __metadata } from "tslib";
import { Host, h, } from "@stencil/core";
import { BEM } from "../../utils/bem";
import { balBrowser } from "../../utils/browser";
import { balDevice } from "../../utils/device";
import { balFloatingUi } from "../../utils/floating-ui";
import { Logger } from "../../utils/log";
import { hideArrowElement, hideContainerElement, showArrowElement, showContainerElement } from "./bal-tooltip.util";
export class Tooltip {
    constructor() {
        this.tooltipId = `bal-to-${tooltipIds++}`;
        /**
         * PUBLIC PROPERTY API
         * ------------------------------------------------------
         */
        /**
         * Id of the reference element default is the trigger element.
         */
        this.reference = '';
        /**
         * If set it turns a tooltip into a fullscreen or a drawer on touch devices
         */
        this.placement = 'bottom';
        /**
         * Offset form trigger to tooltip.
         */
        this.offset = 0;
        /**
         * @internal
         */
        this.demo = false;
        /**
         * Internal active state
         */
        this.presented = false;
    }
    createLogger(log) {
        this.log = log;
    }
    contentWidthChanged(newValue, oldValue) {
        if (newValue !== oldValue) {
            if (newValue === undefined) {
                this.el.style.removeProperty('--bal-tooltip-max-width');
            }
            else {
                this.el.style.setProperty('--bal-tooltip-max-width', `${this.contentWidth}px`);
            }
        }
    }
    /**
     * LIFECYCLE
     * ------------------------------------------------------
     */
    // componentDidRender() {
    //   if (this.demo) {
    //     this.present()
    //   }
    // }
    componentDidLoad() {
        this.contentWidthChanged(this.contentWidth, 0);
        if (!balDevice.hasTouchScreen) {
            let showEvents = [];
            let hideEvents = [];
            showEvents = ['mouseenter', 'focus'];
            hideEvents = ['mouseleave', 'blur'];
            showEvents.forEach(event => {
                if (this.triggerElement) {
                    this.triggerElement.addEventListener(event, () => this.present());
                }
            });
            hideEvents.forEach(event => {
                if (this.triggerElement) {
                    this.triggerElement.addEventListener(event, () => this.dismiss());
                }
            });
        }
        if (this.demo) {
            this.present();
        }
    }
    /**
     * INTERNAL METHODS
     * ------------------------------------------------------
     */
    /**
     * @internal
     */
    async present() {
        //
        // identify trigger element or the the closest trigger available
        if (!this.trigger && balBrowser.hasDocument) {
            const firstTrigger = Array.from(document.querySelectorAll(`[id="${this.reference}"]`))[0];
            this.trigger = firstTrigger;
        }
        if (this.trigger && this.containerEl && this.arrowEl) {
            this.balWillAnimate.emit();
            //
            // get placement type of the trigger
            const triggerVariantAttr = this.trigger.attributes.getNamedItem('bal-tooltip-placement');
            if (triggerVariantAttr) {
                this.placement = triggerVariantAttr.value;
            }
            else {
                this.placement = this.placement;
            }
            //
            // show all required elements
            showContainerElement(this.containerEl);
            showArrowElement(this.arrowEl);
            this.trigger.classList.add('bal-tooltip-trigger');
            this.presented = true;
            const lib = await balFloatingUi.load();
            this.cleanup = lib.autoUpdate(this.trigger, this.containerEl, () => {
                this.update();
            }, {
                ancestorScroll: true,
                ancestorResize: true,
                elementResize: false,
                layoutShift: true,
                animationFrame: true,
            });
            this.balDidAnimate.emit();
            return true;
        }
        return false;
    }
    /**
     * @internal
     */
    async dismiss() {
        if (this.containerEl && this.arrowEl && this.trigger) {
            this.balWillAnimate.emit();
            if (this.cleanup) {
                this.cleanup();
            }
            this.trigger.classList.remove('bal-tooltip-trigger');
            hideContainerElement(this.containerEl);
            hideArrowElement(this.arrowEl);
            this.presented = false;
            this.balDidAnimate.emit();
            return true;
        }
        return false;
    }
    /**
     * @internal
     */
    async update() {
        if (this.trigger && this.containerEl && this.arrowEl) {
            this.balWillAnimate.emit();
            let isInFrame = false;
            if (balBrowser.hasWindow) {
                isInFrame = !!window.frameElement;
            }
            const lib = await balFloatingUi.load();
            lib
                .computePosition(this.trigger, this.containerEl, {
                placement: this.placement,
                middleware: [
                    isInFrame ? undefined : lib.shift(),
                    lib.flip(),
                    lib.offset(8),
                    lib.arrow({
                        element: this.arrowEl,
                        padding: 4,
                    }),
                ],
            })
                .then(({ x, y, middlewareData, placement }) => {
                const side = placement.split('-')[0];
                const staticSide = {
                    top: 'bottom',
                    right: 'left',
                    bottom: 'top',
                    left: 'right',
                }[side];
                if (this.containerEl) {
                    Object.assign(this.containerEl.style, {
                        left: `${x}px`,
                        top: `${y}px`,
                    });
                }
                if (middlewareData.arrow && this.arrowEl) {
                    const arrowPosition = middlewareData.arrow;
                    Object.assign(this.arrowEl.style, {
                        left: x != null && arrowPosition.x != null ? `${arrowPosition.x}px` : '',
                        top: y != null && arrowPosition.y != null ? `${arrowPosition.y}px` : '',
                        right: '',
                        bottom: '',
                        [staticSide]: `${-4}px`,
                    });
                }
            });
            this.balDidAnimate.emit();
            return true;
        }
        return false;
    }
    /**
     * GETTERS
     * ------------------------------------------------------
     */
    get triggerElement() {
        return document.querySelector(`[id="${this.reference}"]`);
    }
    /**
     * RENDER
     * ------------------------------------------------------
     */
    render() {
        const block = BEM.block('tooltip');
        const containerBlock = block.element('container');
        const arrowBlock = block.element('arrow');
        const innerBlock = block.element('inner');
        const innerContentBlock = innerBlock.element('content');
        return (h(Host, { key: '44b979f559f36ccc63896081b14dab984057af90', class: Object.assign({}, block.class()), role: "dialog", "aria-hidden": `${this.presented !== true}`, "aria-modal": `${this.presented === true}`, "aria-presented": `${this.presented === true}` }, h("div", { key: '4e96b8f99b20385490151f810f4b336af692f968', class: Object.assign({}, containerBlock.class()), ref: containerEl => (this.containerEl = containerEl) }, h("div", { key: 'f1f7e3f48c22e5c5187ae1c60e5fad5e95077397', class: Object.assign({}, arrowBlock.class()), ref: arrowEl => (this.arrowEl = arrowEl) }), h("bal-stack", { key: '69727e19f5dc28bb04e7e5354ea7824b748c3fe9', layout: "vertical", class: Object.assign({}, innerBlock.class()) }, h("div", { key: 'e9ee7d561604fd046b102ef895f98c385f66cb69', class: Object.assign({}, innerContentBlock.class()), ref: contentEl => (this.contentEl = contentEl), "data-testid": "bal-tooltip-content" }, h("slot", { key: '4a317667331f69961a438d74d9eb07816c444153' }))))));
    }
    static get is() { return "bal-tooltip"; }
    static get encapsulation() { return "shadow"; }
    static get originalStyleUrls() {
        return {
            "$": ["bal-tooltip.sass"]
        };
    }
    static get styleUrls() {
        return {
            "$": ["bal-tooltip.css"]
        };
    }
    static get properties() {
        return {
            "reference": {
                "type": "string",
                "mutable": false,
                "complexType": {
                    "original": "string",
                    "resolved": "string",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Id of the reference element default is the trigger element."
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "attribute": "reference",
                "defaultValue": "''"
            },
            "placement": {
                "type": "string",
                "mutable": false,
                "complexType": {
                    "original": "BalProps.BalTooltipPlacement",
                    "resolved": "\"bottom\" | \"left\" | \"right\" | \"top\"",
                    "references": {
                        "BalProps": {
                            "location": "global",
                            "id": "global::BalProps"
                        }
                    }
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "If set it turns a tooltip into a fullscreen or a drawer on touch devices"
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "attribute": "placement",
                "defaultValue": "'bottom'"
            },
            "offset": {
                "type": "number",
                "mutable": false,
                "complexType": {
                    "original": "number",
                    "resolved": "number",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Offset form trigger to tooltip."
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "attribute": "offset",
                "defaultValue": "0"
            },
            "demo": {
                "type": "boolean",
                "mutable": false,
                "complexType": {
                    "original": "boolean",
                    "resolved": "boolean",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [{
                            "name": "internal",
                            "text": undefined
                        }],
                    "text": ""
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "attribute": "demo",
                "defaultValue": "false"
            },
            "contentWidth": {
                "type": "number",
                "mutable": false,
                "complexType": {
                    "original": "number",
                    "resolved": "number",
                    "references": {}
                },
                "required": false,
                "optional": true,
                "docs": {
                    "tags": [],
                    "text": "Defines the width of the content"
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "attribute": "content-width"
            }
        };
    }
    static get states() {
        return {
            "presented": {}
        };
    }
    static get events() {
        return [{
                "method": "balWillAnimate",
                "name": "balWillAnimate",
                "bubbles": true,
                "cancelable": true,
                "composed": true,
                "docs": {
                    "tags": [],
                    "text": "Emitted before the animation starts"
                },
                "complexType": {
                    "original": "BalEvents.BalTooltipWillAnimateDetail",
                    "resolved": "boolean",
                    "references": {
                        "BalEvents": {
                            "location": "global",
                            "id": "global::BalEvents"
                        }
                    }
                }
            }, {
                "method": "balDidAnimate",
                "name": "balDidAnimate",
                "bubbles": true,
                "cancelable": true,
                "composed": true,
                "docs": {
                    "tags": [],
                    "text": "Emitted after the animation has finished"
                },
                "complexType": {
                    "original": "BalEvents.BalTooltipDidAnimateDetail",
                    "resolved": "boolean",
                    "references": {
                        "BalEvents": {
                            "location": "global",
                            "id": "global::BalEvents"
                        }
                    }
                }
            }];
    }
    static get methods() {
        return {
            "present": {
                "complexType": {
                    "signature": "() => Promise<boolean>",
                    "parameters": [],
                    "references": {
                        "Promise": {
                            "location": "global",
                            "id": "global::Promise"
                        },
                        "BalProps": {
                            "location": "global",
                            "id": "global::BalProps"
                        }
                    },
                    "return": "Promise<boolean>"
                },
                "docs": {
                    "text": "",
                    "tags": [{
                            "name": "internal",
                            "text": undefined
                        }]
                }
            },
            "dismiss": {
                "complexType": {
                    "signature": "() => Promise<boolean>",
                    "parameters": [],
                    "references": {
                        "Promise": {
                            "location": "global",
                            "id": "global::Promise"
                        }
                    },
                    "return": "Promise<boolean>"
                },
                "docs": {
                    "text": "",
                    "tags": [{
                            "name": "internal",
                            "text": undefined
                        }]
                }
            },
            "update": {
                "complexType": {
                    "signature": "() => Promise<boolean>",
                    "parameters": [],
                    "references": {
                        "Promise": {
                            "location": "global",
                            "id": "global::Promise"
                        }
                    },
                    "return": "Promise<boolean>"
                },
                "docs": {
                    "text": "",
                    "tags": [{
                            "name": "internal",
                            "text": undefined
                        }]
                }
            }
        };
    }
    static get elementRef() { return "el"; }
    static get watchers() {
        return [{
                "propName": "contentWidth",
                "methodName": "contentWidthChanged"
            }];
    }
}
__decorate([
    Logger('bal-tooltip'),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Function]),
    __metadata("design:returntype", void 0)
], Tooltip.prototype, "createLogger", null);
let tooltipIds = 0;
