import * as i0 from '@angular/core';
import { Injectable, InjectionToken, TemplateRef, Directive, Inject, Input, NgModule } from '@angular/core';
import { isString, generateQuickGuid } from '@angular-ru/cdk/string';
import * as i1 from '@ngx-translate/core';
import { isNotNil, isFalsy, checkValueIsEmpty } from '@angular-ru/cdk/utils';
import { Subject, fromEvent } from 'rxjs';
import { debounceTime } from 'rxjs/operators';
import { CommonModule } from '@angular/common';

class NgxTooltipTextInterceptor {
    constructor(translate) {
        this.translate = translate;
    }
    instant(value) {
        return isString(value) ? this.translate.instant(value) : value;
    }
}
/** @nocollapse */ NgxTooltipTextInterceptor.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.2", ngImport: i0, type: NgxTooltipTextInterceptor, deps: [{ token: i1.TranslateService }], target: i0.ɵɵFactoryTarget.Injectable });
/** @nocollapse */ NgxTooltipTextInterceptor.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "13.3.2", ngImport: i0, type: NgxTooltipTextInterceptor });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.2", ngImport: i0, type: NgxTooltipTextInterceptor, decorators: [{
            type: Injectable
        }], ctorParameters: function () { return [{ type: i1.TranslateService }]; } });

class TooltipDefaultTextInterceptor {
}
/** @nocollapse */ TooltipDefaultTextInterceptor.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.2", ngImport: i0, type: TooltipDefaultTextInterceptor, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
/** @nocollapse */ TooltipDefaultTextInterceptor.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "13.3.2", ngImport: i0, type: TooltipDefaultTextInterceptor });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.2", ngImport: i0, type: TooltipDefaultTextInterceptor, decorators: [{
            type: Injectable
        }] });

class TooltipDomLeakService {
    constructor() {
        this.domMemoryLeakTicker$ = new Subject();
        this.timeoutCheck = 500;
        this.actualContainsInDomUidCollections = new Set();
        this.domMemoryLeakTicker$.pipe(debounceTime(this.timeoutCheck)).subscribe(() => {
            const collection = Array.from(new Set(this.actualContainsInDomUidCollections));
            for (const uid of collection) {
                const notExistParent = !document.querySelector(`[data-tooltip-uid="${uid}"]`);
                if (notExistParent) {
                    document.getElementById(uid)?.remove();
                }
            }
        });
    }
    invalidationOfIrrelevantNodes() {
        this.domMemoryLeakTicker$.next();
    }
}
/** @nocollapse */ TooltipDomLeakService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.2", ngImport: i0, type: TooltipDomLeakService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
/** @nocollapse */ TooltipDomLeakService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "13.3.2", ngImport: i0, type: TooltipDomLeakService });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.2", ngImport: i0, type: TooltipDomLeakService, decorators: [{
            type: Injectable
        }], ctorParameters: function () { return []; } });

const TOOLTIP_TEXT_INTERCEPTOR_TOKEN = new InjectionToken('TOOLTIP_TEXT_INTERCEPTOR_TOKEN');
const TOOLTIP_OPTIONS_TOKEN = new InjectionToken('TOOLTIP_OPTIONS_TOKEN');

/* eslint-disable @angular-eslint/no-input-rename */
class TooltipDirective {
    constructor(elementRef, renderer, ngZone, options, interceptor, domLeak) {
        this.elementRef = elementRef;
        this.renderer = renderer;
        this.ngZone = ngZone;
        this.options = options;
        this.interceptor = interceptor;
        this.domLeak = domLeak;
        this.delta = 2;
        this.layoutMinDuration = 100;
        this.tooltipDomElement = null;
        this.tooltipMouseenter = null;
        this.tooltipMouseleave = null;
        this.handlerOptions = { passive: true };
        this.internalTooltipValue = null;
        this.internalContext = null;
        this.placement = 'top';
        this.localCssStyle = null;
        this.size = 'small';
        this.uid = generateQuickGuid();
        this.addUidToElement();
        this.connectMouseEvents();
    }
    set context(contextValue) {
        this.internalContext = contextValue;
        this.refreshTooltipContent();
    }
    set tooltip(tooltipValue) {
        this.internalTooltipValue = tooltipValue;
        this.refreshTooltipContent();
    }
    get offsetElementHeight() {
        return this.tooltipDomElement?.clientHeight ?? 0;
    }
    get offsetElementWidth() {
        return this.tooltipDomElement?.clientWidth ?? 0;
    }
    static getScrollPos() {
        return window.scrollY || document.documentElement.scrollTop || document.body.scrollTop || 0;
    }
    onMouseenterHandler() {
        if (this.tooltipDisabled) {
            return;
        }
        this.domLeak.invalidationOfIrrelevantNodes();
        this.showTooltip();
    }
    onMouseleaveHandler() {
        if (this.tooltipDisabled) {
            return;
        }
        this.destroyAllTimeouts();
        this.hideTooltip();
    }
    ngOnDestroy() {
        this.disconnectMouseEvents();
        this.destroyAllTimeouts();
        this.removeOldNodes();
    }
    showTooltip() {
        this.destroyAllTimeouts();
        if (isNotNil(this.tooltipDomElement)) {
            this.addTooltipShowClass();
            return;
        }
        this.addTooltipToBodyWithAnimation();
    }
    hideTooltip() {
        this.ngZone.runOutsideAngular(() => {
            window.clearTimeout(this.hideId);
            // eslint-disable-next-line no-restricted-properties
            this.hideId = window.setTimeout(() => {
                this.removeTooltipShowClass();
                // eslint-disable-next-line no-restricted-properties
                this.timeoutId = window.setTimeout(() => this.removeOldNodes(), this.options.durationAfterDestroy);
            }, this.layoutMinDuration);
        });
    }
    addTooltipElementToBody() {
        this.tooltipDomElement = this.createTooltipElement();
        if (isNotNil(this.tooltipDomElement)) {
            this.renderer.appendChild(document.body, this.tooltipDomElement);
            this.renderer.setAttribute(this.tooltipDomElement, 'id', this.uid);
            this.renderer.addClass(this.tooltipDomElement, 'ng-tooltip');
            this.renderer.addClass(this.tooltipDomElement, `ng-tooltip-${this.placement}`);
            this.renderer.addClass(this.tooltipDomElement, `ng-tooltip-${this.size}`);
        }
    }
    setPosition() {
        const hostPos = this.elementRef.nativeElement.getBoundingClientRect();
        const tooltipPos = this.tooltipDomElement?.getBoundingClientRect();
        const scrollPos = TooltipDirective.getScrollPos();
        if (this.placement === 'top') {
            const { top, left } = this.calculateByTop(hostPos, tooltipPos);
            this.setStyle(top, left, scrollPos);
        }
        else if (this.placement === 'bottom') {
            const { top, left } = this.calculateByBottom(hostPos, tooltipPos);
            this.setStyle(top, left, scrollPos);
        }
        else if (this.placement === 'left') {
            const { top, left } = this.calculateByLeft(hostPos, tooltipPos);
            this.setStyle(top, left, scrollPos);
        }
        else if (this.placement === 'right') {
            const { top, left } = this.calculateByRight(hostPos, tooltipPos);
            this.setStyle(top, left, scrollPos);
        }
    }
    addTooltipToBodyWithAnimation() {
        this.ngZone.runOutsideAngular(() => {
            // eslint-disable-next-line no-restricted-properties
            this.frameId = window.setTimeout(() => {
                this.addTooltipElementToBody();
                if (isNotNil(this.tooltipDomElement)) {
                    this.tooltipListenOnHoverEvent();
                    // eslint-disable-next-line no-restricted-properties
                    this.createLayoutId = window.setTimeout(() => {
                        this.setPosition();
                        this.addTooltipShowClass();
                        this.markElementAddInDom();
                    }, this.layoutMinDuration);
                }
            }, this.options.durationBeforeCreate);
        });
    }
    refreshTooltipContent() {
        if (isNotNil(this.tooltipDomElement)) {
            const contentDomElement = this.createTooltipContent();
            if (isNotNil(contentDomElement)) {
                const childElements = this.tooltipDomElement?.children ?? [];
                for (const child of Array.from(childElements)) {
                    this.renderer.removeChild(this.tooltipDomElement, child);
                }
                this.renderer.appendChild(this.tooltipDomElement, contentDomElement);
            }
        }
    }
    markElementAddInDom() {
        if (isNotNil(this.tooltipDomElement)) {
            this.domLeak.actualContainsInDomUidCollections.add(this.uid);
        }
    }
    markElementRemoveFromDom() {
        if (isFalsy(this.tooltipDomElement)) {
            this.domLeak.actualContainsInDomUidCollections.delete(this.uid);
        }
    }
    connectMouseEvents() {
        this.mouseenterListener = () => this.onMouseenterHandler();
        this.mouseleaveListener = () => this.onMouseleaveHandler();
        this.ngZone.runOutsideAngular(() => {
            this.elementRef.nativeElement.addEventListener('mouseenter', this.mouseenterListener, this.handlerOptions);
            this.elementRef.nativeElement.addEventListener('mouseleave', this.mouseleaveListener, this.handlerOptions);
        });
    }
    disconnectMouseEvents() {
        this.elementRef.nativeElement.removeEventListener('mouseenter', this.mouseenterListener, this.handlerOptions);
        this.elementRef.nativeElement.removeEventListener('mouseleave', this.mouseleaveListener, this.handlerOptions);
    }
    addUidToElement() {
        this.elementRef.nativeElement.setAttribute('data-tooltip-uid', this.uid);
    }
    addTooltipShowClass() {
        if (isNotNil(this.tooltipDomElement)) {
            this.renderer.addClass(this.tooltipDomElement, 'ng-tooltip-show');
        }
    }
    removeTooltipShowClass() {
        if (isNotNil(this.tooltipDomElement)) {
            this.renderer.removeClass(this.tooltipDomElement, 'ng-tooltip-show');
        }
    }
    tooltipListenOnHoverEvent() {
        window.clearTimeout(this.mouseLeaveTooltipId);
        if (isNotNil(this.tooltipDomElement)) {
            this.tooltipMouseenter?.unsubscribe();
            this.tooltipMouseleave?.unsubscribe();
            this.tooltipMouseenter = fromEvent(this.tooltipDomElement ?? [], 'mouseenter').subscribe(() => {
                window.clearTimeout(this.hideId);
                window.clearTimeout(this.mouseLeaveTooltipId);
            });
            this.tooltipMouseleave = fromEvent(this.tooltipDomElement ?? [], 'mouseleave').subscribe(() => {
                window.clearTimeout(this.mouseLeaveTooltipId);
                // eslint-disable-next-line no-restricted-properties
                this.mouseLeaveTooltipId = window.setTimeout(() => this.hideTooltip(), this.options.timeoutForWaitAfterBlurTooltip);
            });
        }
    }
    // eslint-disable-next-line complexity
    createTooltipContent() {
        const content = document.createElement('div');
        if (this.internalTooltipValue instanceof TemplateRef) {
            const view = this.internalTooltipValue.createEmbeddedView({
                $implicit: this.internalContext
            });
            view.detectChanges();
            content.append(...view.rootNodes);
        }
        else if (checkValueIsEmpty(this.internalTooltipValue)) {
            return null;
        }
        else if (isNotNil(this.internalTooltipValue)) {
            const value = this.internalTooltipValue?.toString() ?? '';
            content.innerHTML = this.interceptor.instant?.(value) ?? value;
        }
        content.style.cssText = this.localCssStyle ?? this.options.cssStyle;
        return content;
    }
    createTooltipElement() {
        const contentDomElement = this.createTooltipContent();
        if (isNotNil(contentDomElement)) {
            const tooltipDomElement = this.renderer.createElement('div');
            this.renderer.appendChild(tooltipDomElement, contentDomElement);
            return tooltipDomElement;
        }
        return null;
    }
    destroyAllTimeouts() {
        window.clearTimeout(this.frameId);
        window.clearTimeout(this.createLayoutId);
        window.clearTimeout(this.mouseLeaveTooltipId);
        window.clearTimeout(this.timeoutId);
        window.clearTimeout(this.hideId);
    }
    removeOldNodes() {
        if (isNotNil(this.tooltipDomElement)) {
            const element = document.getElementById(this.uid);
            element?.remove();
            this.tooltipDomElement = null;
        }
        this.markElementRemoveFromDom();
    }
    setStyle(top, left, scrollPos) {
        this.renderer.setStyle(this.tooltipDomElement, 'top', `${top + scrollPos}px`);
        this.renderer.setStyle(this.tooltipDomElement, 'left', `${left}px`);
    }
    calculateByTop(hostPos, tooltipPos) {
        const top = hostPos.top - this.offsetElementHeight;
        const left = hostPos.left + (hostPos.width - (tooltipPos?.width ?? 0)) / this.delta;
        return { top, left };
    }
    calculateByBottom(hostPos, tooltipPos) {
        const top = hostPos.bottom;
        const left = hostPos.left + (hostPos.width - (tooltipPos?.width ?? 0)) / this.delta;
        return { top, left };
    }
    calculateByLeft(hostPos, tooltipPos) {
        const top = hostPos.top + (hostPos.height - (tooltipPos?.height ?? 0)) / this.delta;
        const left = hostPos.left - this.offsetElementWidth;
        return { top, left };
    }
    calculateByRight(hostPos, tooltipPos) {
        const top = hostPos.top + (hostPos.height - (tooltipPos?.height ?? 0)) / this.delta;
        const left = hostPos.right;
        return { top, left };
    }
}
/** @nocollapse */ TooltipDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.2", ngImport: i0, type: TooltipDirective, deps: [{ token: i0.ElementRef }, { token: i0.Renderer2 }, { token: i0.NgZone }, { token: TOOLTIP_OPTIONS_TOKEN }, { token: TOOLTIP_TEXT_INTERCEPTOR_TOKEN }, { token: TooltipDomLeakService }], target: i0.ɵɵFactoryTarget.Directive });
/** @nocollapse */ TooltipDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "13.3.2", type: TooltipDirective, selector: "[tooltip]", inputs: { tooltipDisabled: ["tooltip-disabled", "tooltipDisabled"], placement: ["tooltip-placement", "placement"], localCssStyle: ["tooltip-css-style", "localCssStyle"], size: ["tooltip-size", "size"], context: ["tooltip-context", "context"], tooltip: "tooltip" }, ngImport: i0 });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.2", ngImport: i0, type: TooltipDirective, decorators: [{
            type: Directive,
            args: [{ selector: '[tooltip]' }]
        }], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: i0.Renderer2 }, { type: i0.NgZone }, { type: undefined, decorators: [{
                    type: Inject,
                    args: [TOOLTIP_OPTIONS_TOKEN]
                }] }, { type: undefined, decorators: [{
                    type: Inject,
                    args: [TOOLTIP_TEXT_INTERCEPTOR_TOKEN]
                }] }, { type: TooltipDomLeakService }]; }, propDecorators: { tooltipDisabled: [{
                type: Input,
                args: ['tooltip-disabled']
            }], placement: [{
                type: Input,
                args: ['tooltip-placement']
            }], localCssStyle: [{
                type: Input,
                args: ['tooltip-css-style']
            }], size: [{
                type: Input,
                args: ['tooltip-size']
            }], context: [{
                type: Input,
                args: ['tooltip-context']
            }], tooltip: [{
                type: Input
            }] } });

const TOOLTIP_DEFAULT_OPTIONS = {
    cssStyle: '',
    durationBeforeCreate: 200,
    durationAfterDestroy: 1500,
    timeoutForWaitAfterBlurTooltip: 400
};
const NGX_TOOLTIP_FALLBACK_PROVIDER = {
    provide: TOOLTIP_TEXT_INTERCEPTOR_TOKEN,
    useClass: NgxTooltipTextInterceptor
};

class TooltipModule {
    static forRoot(options = {}) {
        return {
            ngModule: TooltipModule,
            providers: [
                { provide: TOOLTIP_OPTIONS_TOKEN, useValue: { ...TOOLTIP_DEFAULT_OPTIONS, ...options } },
                { provide: TOOLTIP_TEXT_INTERCEPTOR_TOKEN, useClass: TooltipDefaultTextInterceptor }
            ]
        };
    }
}
/** @nocollapse */ TooltipModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.2", ngImport: i0, type: TooltipModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
/** @nocollapse */ TooltipModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "13.3.2", ngImport: i0, type: TooltipModule, declarations: [TooltipDirective], imports: [CommonModule], exports: [TooltipDirective] });
/** @nocollapse */ TooltipModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "13.3.2", ngImport: i0, type: TooltipModule, providers: [TooltipDomLeakService], imports: [[CommonModule]] });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.2", ngImport: i0, type: TooltipModule, decorators: [{
            type: NgModule,
            args: [{
                    imports: [CommonModule],
                    exports: [TooltipDirective],
                    declarations: [TooltipDirective],
                    providers: [TooltipDomLeakService]
                }]
        }] });

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

export { NGX_TOOLTIP_FALLBACK_PROVIDER, NgxTooltipTextInterceptor, TOOLTIP_DEFAULT_OPTIONS, TOOLTIP_OPTIONS_TOKEN, TOOLTIP_TEXT_INTERCEPTOR_TOKEN, TooltipDefaultTextInterceptor, TooltipDirective, TooltipModule };
//# sourceMappingURL=angular-ru-cdk-tooltip.mjs.map
