import { Overlay } from '@angular/cdk/overlay';
import { ComponentPortal } from '@angular/cdk/portal';
import * as i0 from '@angular/core';
import { input, Component, inject, ElementRef, Renderer2, Directive, HostListener, NgModule } from '@angular/core';
import { DebounceUtils } from '@seniorsistemas/angular-components/common';
import { NgClass } from '@angular/common';

/**
 * @description Componente de apresentação do tooltip. Utilizado internamente pela diretiva `TooltipDirective`.
 * O posicionamento é gerenciado pelo CDK Overlay via `TooltipDirective`.
 */
class TooltipComponent {
    /** @description Texto ou HTML a ser exibido no tooltip. */
    tooltip = input('');
    /** @description Posição do tooltip — usada para renderizar a seta no lado correto. */
    position = input('top');
    /** @description Controla a visibilidade (opacidade) do tooltip via transição CSS. */
    visible = input(false);
    /** @description Quando `true`, o conteúdo é renderizado como texto puro (escapa HTML). */
    escape = input(false);
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: TooltipComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
    static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: TooltipComponent, isStandalone: true, selector: "s-tooltip", inputs: { tooltip: { classPropertyName: "tooltip", publicName: "tooltip", isSignal: true, isRequired: false, transformFunction: null }, position: { classPropertyName: "position", publicName: "position", isSignal: true, isRequired: false, transformFunction: null }, visible: { classPropertyName: "visible", publicName: "visible", isSignal: true, isRequired: false, transformFunction: null }, escape: { classPropertyName: "escape", publicName: "escape", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div\n    class=\"tooltip relative max-w-[220px] break-words rounded-xsmall bg-grayscale-100 p-2 text-center font-open-sans text-sm font-normal leading-normal text-grayscale-0 transition-opacity duration-300\"\n    [class.opacity-0]=\"!visible()\"\n    [class.opacity-100]=\"visible()\"\n    [class.tooltip--visible]=\"visible()\"\n    [ngClass]=\"'tooltip--' + position()\"\n>\n    @if (escape()) {\n        <span class=\"tooltip__content\">\n            {{ tooltip() }}\n        </span>\n    } @else {\n        <span\n            class=\"tooltip__content\"\n            [innerHTML]=\"tooltip()\"\n        >\n        </span>\n    }\n</div>\n\n", styles: [".tooltip--top:before,.tooltip--bottom:before,.tooltip--left:before,.tooltip--right:before{content:\"\";height:0;position:absolute;width:0}.tooltip--bottom:before{border:5px solid transparent;border-bottom:5px solid #0E1119;left:calc(50% - 5px);top:-10px}.tooltip--top:before{border:5px solid transparent;border-top:5px solid #0E1119;left:calc(50% - 5px);bottom:-10px}.tooltip--left:before{border:5px solid transparent;border-left:5px solid #0E1119;right:-10px;bottom:calc(50% - 5px)}.tooltip--right:before{border:5px solid transparent;border-right:5px solid #0E1119;left:-10px;bottom:calc(50% - 5px)}\n"], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: TooltipComponent, decorators: [{
            type: Component,
            args: [{ selector: 's-tooltip', standalone: true, imports: [NgClass], template: "<div\n    class=\"tooltip relative max-w-[220px] break-words rounded-xsmall bg-grayscale-100 p-2 text-center font-open-sans text-sm font-normal leading-normal text-grayscale-0 transition-opacity duration-300\"\n    [class.opacity-0]=\"!visible()\"\n    [class.opacity-100]=\"visible()\"\n    [class.tooltip--visible]=\"visible()\"\n    [ngClass]=\"'tooltip--' + position()\"\n>\n    @if (escape()) {\n        <span class=\"tooltip__content\">\n            {{ tooltip() }}\n        </span>\n    } @else {\n        <span\n            class=\"tooltip__content\"\n            [innerHTML]=\"tooltip()\"\n        >\n        </span>\n    }\n</div>\n\n", styles: [".tooltip--top:before,.tooltip--bottom:before,.tooltip--left:before,.tooltip--right:before{content:\"\";height:0;position:absolute;width:0}.tooltip--bottom:before{border:5px solid transparent;border-bottom:5px solid #0E1119;left:calc(50% - 5px);top:-10px}.tooltip--top:before{border:5px solid transparent;border-top:5px solid #0E1119;left:calc(50% - 5px);bottom:-10px}.tooltip--left:before{border:5px solid transparent;border-left:5px solid #0E1119;right:-10px;bottom:calc(50% - 5px)}.tooltip--right:before{border:5px solid transparent;border-right:5px solid #0E1119;left:-10px;bottom:calc(50% - 5px)}\n"] }]
        }] });

/**
 * @description Diretiva que exibe um tooltip (dica de ferramenta) flutuante ao interagir com o elemento hospedeiro.
 * Posiciona-se automaticamente considerando o espaço disponível na tela, utilizando o CDK Overlay.
 * Suporta eventos de hover, click e focus, além de comportamentos customizados para mobile.
 *
 * @example
 * ```html
 * <button sTooltip="Clique aqui" tooltipPosition="top">Ação</button>
 * ```
 *
 * @category Overlay
 */
class TooltipDirective {
    /**
     * @description Texto exibido no tooltip. Quando vazio ou `undefined`, o tooltip não é renderizado.
     */
    tooltip = input(undefined, { alias: 'sTooltip' });
    /**
     * @description Posição preferencial do tooltip em relação ao elemento hospedeiro.
     * O tooltip se reposiciona automaticamente se não houver espaço suficiente.
     *
     * @default 'top'
     */
    tooltipPosition = input('top');
    /**
     * @description Tempo em milissegundos antes do tooltip aparecer após o evento de ativação.
     *
     * @default 500
     */
    showDelay = input(500);
    /**
     * @description Tempo em milissegundos que o tooltip permanece visível após aparecer.
     * Quando não informado, o tooltip permanece até o usuário sair do elemento.
     */
    displayTime = input(undefined);
    /**
     * @description Evento do elemento hospedeiro que dispara a exibição do tooltip.
     * - `'hover'`: exibe ao passar o mouse (padrão).
     * - `'click'`: exibe ao clicar.
     * - `'focus'`: exibe ao focar no elemento.
     *
     * @default 'hover'
     */
    tooltipEvent = input('hover');
    /**
     * @description Quando `true`, o conteúdo HTML do tooltip é escapado antes de ser renderizado.
     *
     * @default false
     */
    escape = input(false);
    /**
     * @description Quando `false`, o tooltip nunca é exibido, mesmo que haja interação do usuário.
     * Útil para desabilitar tooltips dinamicamente.
     *
     * @default true
     */
    visible = input(true);
    /**
     * @description Comportamento do tooltip em dispositivos móveis (touch).
     * - `'pressing'`: exibe ao pressionar e manter o toque (padrão).
     * - `'none'`: desabilita o tooltip em dispositivos táteis.
     *
     * @default 'pressing'
     */
    mobileBehavior = input('pressing');
    /**
     * @description Referência a um input HTML para sincronizar a exibição do tooltip com o foco no campo.
     */
    focusedInputRef = input(null);
    /**
     * @description Quando `true`, o tooltip só é exibido se o texto do elemento estiver truncado (overflow).
     * Útil para cells de tabela ou elementos com `text-overflow: ellipsis`.
     *
     * @default false
     */
    checkTruncatedText = input(false);
    elementRef = inject(ElementRef);
    overlay = inject(Overlay);
    debounceUtils = inject(DebounceUtils);
    renderer = inject(Renderer2);
    overlayRef = null;
    componentRef = null;
    positionChangeSubscription = null;
    showTimeout;
    touchTimeout;
    tooltipCreatedByFocus = false;
    debounceCreateTooltipFunction = this.debounceUtils.debounceLeading(() => this._createTooltip(true, true));
    ngOnInit() {
        this.validatePosition();
        this.updateTooltipVisibilityWhenFocusOnInput();
    }
    ngOnDestroy() {
        this.destroy();
    }
    // whenever the component with the tooltip is clicked I destroy the tooltip.
    // whenever a key is pressed on the component with the tooltip I destroy the tooltip.
    onClick() {
        if (this.tooltipEvent() === 'hover' &&
            !navigator.userAgent.match(/Android/i) &&
            !navigator.userAgent.match(/iPhone/i)) {
            this.destroy();
        }
    }
    onFocus() {
        if (this.tooltipEvent() === 'focus') {
            this._createTooltip(true, true);
        }
    }
    onBlur() {
        if (this.tooltipEvent() === 'focus') {
            this.destroy();
        }
    }
    onMouseEnter() {
        if (this.tooltipEvent() === 'hover' || this.focusedInputRef()) {
            this.debounceCreateTooltipFunction();
        }
    }
    onMouseLeave() {
        if ((this.tooltipEvent() === 'hover' || this.focusedInputRef()) && !this.tooltipCreatedByFocus) {
            this.destroy();
        }
    }
    onTouchStart() {
        if (this.tooltipEvent() === 'hover') {
            window.clearTimeout(this.touchTimeout);
            const delay = this.mobileBehavior() === 'pressing' ? this.showDelay() : 0;
            this.touchTimeout = window.setTimeout(() => {
                this._createTooltip(true, true);
            }, delay);
        }
    }
    onTouchEnd() {
        if (this.tooltipEvent() === 'hover' && this.mobileBehavior() === 'pressing') {
            window.clearTimeout(this.touchTimeout);
            this.destroy();
        }
    }
    validatePosition() {
        const containsPosition = ['top', 'right', 'bottom', 'left'].includes(this.tooltipPosition());
        if (!containsPosition) {
            throw new Error(`Tooltip position "${this.tooltipPosition()}" is unexpected`);
        }
    }
    /**
     * Manipula a visibilidade do tooltip quando houver uma referência de input.
     */
    updateTooltipVisibilityWhenFocusOnInput() {
        const inputRef = this.focusedInputRef();
        if (!inputRef)
            return;
        this.renderer.listen(inputRef, 'focus', () => {
            this._createTooltip(false, false);
            this.tooltipCreatedByFocus = true;
        });
        this.renderer.listen(inputRef, 'blur', () => {
            this.destroy();
            this.tooltipCreatedByFocus = false;
        });
    }
    _createTooltip(useShowDelay = false, autoDestroy = true) {
        const tooltipText = this.tooltip() ?? '';
        if (!tooltipText.length || this.overlayRef !== null)
            return;
        if (this.checkTruncatedText() && !this.contentIsTruncated)
            return;
        const positionStrategy = this.buildPositionStrategy();
        const scrollStrategy = this.overlay.scrollStrategies.reposition();
        this.overlayRef = this.overlay.create({ positionStrategy, scrollStrategy });
        const portal = new ComponentPortal(TooltipComponent);
        this.componentRef = this.overlayRef.attach(portal);
        this.componentRef.setInput('tooltip', tooltipText);
        this.componentRef.setInput('escape', this.escape());
        this.componentRef.setInput('position', this.tooltipPosition());
        this.positionChangeSubscription = positionStrategy.positionChanges.subscribe((change) => {
            const mappedPosition = this.mapCdkPositionToTooltipPosition(change.connectionPair);
            this.componentRef?.setInput('position', mappedPosition);
        });
        const delay = useShowDelay ? this.showDelay() : 0;
        this.showTimeout = window.setTimeout(() => {
            this.componentRef?.setInput('visible', this.visible());
        }, delay);
        if (autoDestroy && this.displayTime()) {
            window.setTimeout(() => {
                this.destroy();
            }, this.displayTime());
        }
    }
    buildPositionStrategy() {
        const preferred = this.tooltipPosition();
        const allPositions = ['top', 'bottom', 'left', 'right'];
        const orderedPositions = [preferred, ...allPositions.filter((p) => p !== preferred)];
        return this.overlay
            .position()
            .flexibleConnectedTo(this.elementRef)
            .withPositions(orderedPositions.map((p) => this.getConnectedPosition(p)))
            .withFlexibleDimensions(false)
            .withPush(false);
    }
    getConnectedPosition(pos) {
        const offset = 10;
        const positionMap = {
            top: { originX: 'center', originY: 'top', overlayX: 'center', overlayY: 'bottom', offsetY: -offset },
            bottom: { originX: 'center', originY: 'bottom', overlayX: 'center', overlayY: 'top', offsetY: offset },
            left: { originX: 'start', originY: 'center', overlayX: 'end', overlayY: 'center', offsetX: -offset },
            right: { originX: 'end', originY: 'center', overlayX: 'start', overlayY: 'center', offsetX: offset },
        };
        return positionMap[pos];
    }
    mapCdkPositionToTooltipPosition(pair) {
        if (pair.overlayY === 'bottom')
            return 'top';
        if (pair.overlayY === 'top')
            return 'bottom';
        if (pair.overlayX === 'end')
            return 'left';
        return 'right';
    }
    destroy() {
        window.clearTimeout(this.showTimeout);
        window.clearTimeout(this.touchTimeout);
        this.positionChangeSubscription?.unsubscribe();
        this.positionChangeSubscription = null;
        if (this.overlayRef) {
            this.overlayRef.dispose();
            this.overlayRef = null;
            this.componentRef = null;
        }
    }
    get contentIsTruncated() {
        const element = this.elementRef.nativeElement;
        return element.scrollHeight > element.clientHeight || element.scrollWidth > element.clientWidth;
    }
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: TooltipDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
    static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "18.2.14", type: TooltipDirective, isStandalone: true, selector: "[sTooltip]", inputs: { tooltip: { classPropertyName: "tooltip", publicName: "sTooltip", isSignal: true, isRequired: false, transformFunction: null }, tooltipPosition: { classPropertyName: "tooltipPosition", publicName: "tooltipPosition", isSignal: true, isRequired: false, transformFunction: null }, showDelay: { classPropertyName: "showDelay", publicName: "showDelay", isSignal: true, isRequired: false, transformFunction: null }, displayTime: { classPropertyName: "displayTime", publicName: "displayTime", isSignal: true, isRequired: false, transformFunction: null }, tooltipEvent: { classPropertyName: "tooltipEvent", publicName: "tooltipEvent", isSignal: true, isRequired: false, transformFunction: null }, escape: { classPropertyName: "escape", publicName: "escape", isSignal: true, isRequired: false, transformFunction: null }, visible: { classPropertyName: "visible", publicName: "visible", isSignal: true, isRequired: false, transformFunction: null }, mobileBehavior: { classPropertyName: "mobileBehavior", publicName: "mobileBehavior", isSignal: true, isRequired: false, transformFunction: null }, focusedInputRef: { classPropertyName: "focusedInputRef", publicName: "focusedInputRef", isSignal: true, isRequired: false, transformFunction: null }, checkTruncatedText: { classPropertyName: "checkTruncatedText", publicName: "checkTruncatedText", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "click": "onClick()", "keydown": "onClick()", "focus": "onFocus()", "blur": "onBlur()", "mouseenter": "onMouseEnter()", "mouseleave": "onMouseLeave()", "wheel": "onMouseLeave()", "touchstart": "onTouchStart()", "touchend": "onTouchEnd()" } }, ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: TooltipDirective, decorators: [{
            type: Directive,
            args: [{
                    selector: '[sTooltip]',
                    standalone: true,
                }]
        }], propDecorators: { onClick: [{
                type: HostListener,
                args: ['click']
            }, {
                type: HostListener,
                args: ['keydown']
            }], onFocus: [{
                type: HostListener,
                args: ['focus']
            }], onBlur: [{
                type: HostListener,
                args: ['blur']
            }], onMouseEnter: [{
                type: HostListener,
                args: ['mouseenter']
            }], onMouseLeave: [{
                type: HostListener,
                args: ['mouseleave']
            }, {
                type: HostListener,
                args: ['wheel']
            }], onTouchStart: [{
                type: HostListener,
                args: ['touchstart']
            }], onTouchEnd: [{
                type: HostListener,
                args: ['touchend']
            }] } });

class TooltipModule {
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: TooltipModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
    static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "18.2.14", ngImport: i0, type: TooltipModule, imports: [TooltipDirective], exports: [TooltipDirective] });
    static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: TooltipModule });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: TooltipModule, decorators: [{
            type: NgModule,
            args: [{
                    imports: [TooltipDirective],
                    exports: [TooltipDirective],
                }]
        }] });

/**
 * Generated bundle index. Do not edit.
 */

export { TooltipDirective, TooltipModule };
//# sourceMappingURL=seniorsistemas-angular-components-tooltip.mjs.map
