import { CommonModule } from '@angular/common';
import * as i0 from '@angular/core';
import { Directive, Input, NgModule } from '@angular/core';
import { Destroy, subscribeWith } from '@deja-js/component/core';
import { fromEvent, switchMap, timer, take, filter, takeUntil, Subject, shareReplay, EMPTY, mergeWith, map, debounceTime, withLatestFrom, tap, delay } from 'rxjs';
import { MatDialogConfig } from '@angular/material/dialog';
import { merge } from 'lodash-es';

/*
 *  @license
 *  Copyright Hôpitaux Universitaires de Genève. All Rights Reserved.
 *
 *  Use of this source code is governed by an Apache-2.0 license that can be
 *  found in the LICENSE file at https://github.com/DSI-HUG/dejajs-components/blob/master/LICENSE
 */
class TooltipDirective extends Destroy {
    constructor(elementRef) {
        super();
        // eslint-disable-next-line @angular-eslint/no-input-rename
        this.delay = 300;
        const triggerElement = elementRef.nativeElement;
        const leave$ = fromEvent(triggerElement, 'mouseleave');
        fromEvent(triggerElement, 'mouseenter').pipe(switchMap(() => timer(this.delay).pipe(take(1), filter(() => !!this.openTooltip$), switchMap(() => this.openTooltip$(triggerElement)), takeUntil(leave$))), takeUntil(this.destroyed$)).subscribe();
    }
}
TooltipDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.1", ngImport: i0, type: TooltipDirective, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Directive });
TooltipDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "13.3.1", type: TooltipDirective, selector: "[app-tooltip]", inputs: { delay: ["tooltip-delay", "delay"], openTooltip$: ["app-tooltip", "openTooltip$"] }, usesInheritance: true, ngImport: i0 });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.1", ngImport: i0, type: TooltipDirective, decorators: [{
            type: Directive,
            args: [{
                    selector: '[app-tooltip]'
                }]
        }], ctorParameters: function () { return [{ type: i0.ElementRef }]; }, propDecorators: { delay: [{
                type: Input,
                args: ['tooltip-delay']
            }], openTooltip$: [{
                type: Input,
                args: ['app-tooltip']
            }] } });

/*
 *  @license
 *  Copyright Hôpitaux Universitaires de Genève. All Rights Reserved.
 *
 *  Use of this source code is governed by an Apache-2.0 license that can be
 *  found in the LICENSE file at https://github.com/DSI-HUG/dejajs-components/blob/master/LICENSE
 */
class TooltipConfig extends MatDialogConfig {
}

/*
 *  @license
 *  Copyright Hôpitaux Universitaires de Genève. All Rights Reserved.
 *
 *  Use of this source code is governed by an Apache-2.0 license that can be
 *  found in the LICENSE file at https://github.com/DSI-HUG/dejajs-components/blob/master/LICENSE
 */

/*
 *  @license
 *  Copyright Hôpitaux Universitaires de Genève. All Rights Reserved.
 *
 *  Use of this source code is governed by an Apache-2.0 license that can be
 *  found in the LICENSE file at https://github.com/DSI-HUG/dejajs-components/blob/master/LICENSE
 */
class TooltipService {
    constructor(lazyLoaderService, dialog, tooltipConfig) {
        this.lazyLoaderService = lazyLoaderService;
        this.dialog = dialog;
        this.tooltipConfig = tooltipConfig;
        this.close$ = new Subject();
        this.positions = [
            {
                originX: 'center',
                originY: 'bottom',
                overlayX: 'center',
                overlayY: 'top',
                offsetY: 20
            },
            {
                originX: 'center',
                originY: 'top',
                overlayX: 'center',
                overlayY: 'bottom',
                offsetY: -20
            },
            {
                originX: 'start',
                originY: 'center',
                overlayX: 'end',
                overlayY: 'center',
                offsetX: -20
            },
            {
                originX: 'end',
                originY: 'center',
                overlayX: 'start',
                overlayY: 'top',
                offsetX: 20
            },
            {
                originX: 'start',
                originY: 'bottom',
                overlayX: 'start',
                overlayY: 'top',
                offsetY: 20
            },
            {
                originX: 'start',
                originY: 'top',
                overlayX: 'start',
                overlayY: 'bottom',
                offsetY: -20
            },
            {
                originX: 'end',
                originY: 'bottom',
                overlayX: 'end',
                overlayY: 'top',
                offsetY: 20
            },
            {
                originX: 'end',
                originY: 'top',
                overlayX: 'end',
                overlayY: 'bottom',
                offsetY: -20
            },
            {
                originX: 'start',
                originY: 'top',
                overlayX: 'start',
                overlayY: 'top'
            }
        ];
        if (!this.tooltipConfig) {
            this.tooltipConfig = new MatDialogConfig();
        }
    }
    open$(triggerElement, tooltipData, tooltipConfig) {
        this.close();
        const additionalPanelClass = (tooltipConfig?.panelClass && tooltipConfig.panelClass instanceof Array && tooltipConfig.panelClass)
            || (tooltipConfig?.panelClass && typeof tooltipConfig?.panelClass === 'string' && [tooltipConfig?.panelClass])
            || new Array();
        const config = merge(tooltipConfig, {
            hasBackdrop: false,
            panelClass: ['tooltip-overlay', 'no-padding-dialog', 'tooltip-opening', ...additionalPanelClass]
        });
        const dialogRef$ = this.openRef$(tooltipData, triggerElement, config).pipe(shareReplay({ bufferSize: 1, refCount: false }));
        const checkClose$ = dialogRef$.pipe(switchMap(dialogRef => {
            const tooltipElement = dialogRef.componentInstance.elementRef?.nativeElement.parentElement;
            const mouseEnterTooltip$ = tooltipElement ? fromEvent(tooltipElement, 'mouseenter') : EMPTY;
            const mouseEnterTrigger$ = triggerElement ? fromEvent(triggerElement, 'mouseenter') : EMPTY;
            const mouseLeaveTooltip$ = tooltipElement ? fromEvent(tooltipElement, 'mouseleave') : EMPTY;
            const mouseLeaveTrigger$ = triggerElement ? fromEvent(triggerElement, 'mouseleave') : EMPTY;
            const set$ = mouseEnterTooltip$.pipe(mergeWith(mouseEnterTrigger$), map(() => false));
            const reset$ = mouseLeaveTooltip$.pipe(mergeWith(mouseLeaveTrigger$), map(() => true));
            return set$.pipe(mergeWith(reset$), debounceTime(config.hideDelay || 10), filter(Boolean), map(() => undefined));
        }));
        const close$ = checkClose$.pipe(mergeWith(this.close$), withLatestFrom(dialogRef$), tap(([_, dialogRef]) => dialogRef.removePanelClass('tooltip-opened')), delay(300), tap(([response, dialogRef]) => dialogRef.close(response)));
        return dialogRef$.pipe(switchMap(dialogRef => dialogRef.afterClosed()), subscribeWith(close$), shareReplay({ bufferSize: 1, refCount: false }));
    }
    close() {
        this.close$.next();
    }
    openRef$(tooltipData, triggerElement, tooltipConfig) {
        return this.lazyLoaderService.loadModule$(this.getModule()).pipe(switchMap(moduleInfos => {
            const config = merge({}, this.tooltipConfig, tooltipConfig || {});
            config.data = tooltipData || {};
            config.minWidth = config.minWidth || '100px';
            // injector is private in MatDialog
            // eslint-disable-next-line @typescript-eslint/dot-notation
            this.dialog['_injector'] = moduleInfos.injector;
            const dialogRef = this.dialog.open(moduleInfos.module.componentType, config);
            return dialogRef.afterOpened().pipe(map(() => dialogRef));
        }), tap(dialogRef => {
            const componentInstance = dialogRef.componentInstance;
            const tooltipBounds = componentInstance.elementRef?.nativeElement.parentElement.getBoundingClientRect();
            const triggerBounds = triggerElement?.getBoundingClientRect();
            const bodyBounds = document.body.getBoundingClientRect();
            if (tooltipBounds && triggerBounds) {
                this.positions.find((position, index) => {
                    // Calc trigger alignment
                    let left = position.offsetX || 0;
                    switch (position.originX) {
                        case 'start':
                            left += triggerBounds.left;
                            break;
                        case 'end':
                            left += triggerBounds.right;
                            break;
                        default:
                            left += triggerBounds.left + triggerBounds.width / 2;
                            break;
                    }
                    let top = position.offsetY || 0;
                    switch (position.originY) {
                        case 'top':
                            top += triggerBounds.top;
                            break;
                        case 'bottom':
                            top += triggerBounds.bottom;
                            break;
                        default:
                            top += triggerBounds.top + triggerBounds.height / 2;
                            break;
                    }
                    // Calc overlay position
                    switch (position.overlayX) {
                        case 'center':
                            left -= tooltipBounds.width / 2;
                            break;
                        case 'end':
                            left -= tooltipBounds.width;
                            break;
                        default:
                            break;
                    }
                    switch (position.overlayY) {
                        case 'center':
                            top -= tooltipBounds.height / 2;
                            break;
                        case 'bottom':
                            top -= tooltipBounds.height;
                            break;
                        default:
                            break;
                    }
                    if ((index < this.positions.length - 1) && (left < bodyBounds.left || top < bodyBounds.top || (left + tooltipBounds.width) > bodyBounds.right || (top + tooltipBounds.height) > bodyBounds.bottom)) {
                        // Try another psoition
                        return false;
                    }
                    if ((left + tooltipBounds.width) > bodyBounds.right) {
                        left = bodyBounds.right - tooltipBounds.width;
                    }
                    if ((top + tooltipBounds.height) > bodyBounds.bottom) {
                        top = bodyBounds.bottom - tooltipBounds.height;
                    }
                    if (top < bodyBounds.top) {
                        top = bodyBounds.top;
                    }
                    if (left < bodyBounds.left) {
                        left = bodyBounds.left;
                    }
                    dialogRef.updatePosition({
                        left: `${left}px`,
                        top: `${top}px`
                    });
                    dialogRef.addPanelClass('tooltip-opened');
                    return true;
                });
            }
            else {
                console.error('A tooltip component must inherits from TooltipComponent directive. Position can\'t be updated');
            }
        }));
    }
}

/*
 *  @license
 *  Copyright Hôpitaux Universitaires de Genève. All Rights Reserved.
 *
 *  Use of this source code is governed by an Apache-2.0 license that can be
 *  found in the LICENSE file at https://github.com/DSI-HUG/dejajs-components/blob/master/LICENSE
 */
class TooltipModule {
}
TooltipModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.1", ngImport: i0, type: TooltipModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
TooltipModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "13.3.1", ngImport: i0, type: TooltipModule, declarations: [TooltipDirective], imports: [CommonModule], exports: [TooltipDirective] });
TooltipModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "13.3.1", ngImport: i0, type: TooltipModule, imports: [[
            CommonModule
        ]] });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.1", ngImport: i0, type: TooltipModule, decorators: [{
            type: NgModule,
            args: [{
                    declarations: [
                        TooltipDirective
                    ],
                    exports: [
                        TooltipDirective
                    ],
                    imports: [
                        CommonModule
                    ]
                }]
        }] });

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

export { TooltipConfig, TooltipDirective, TooltipModule, TooltipService };
//# sourceMappingURL=deja-js-component-v2-tooltip.mjs.map
