import { OverlayRef } from '@angular/cdk/overlay';
import {
	Component,
	ElementRef,
	Inject,
	OnDestroy,
	Renderer2
} from '@angular/core';

// Токены
import {
	CONTEXT_MENU_CONFIG,
	CONTEXT_MENU_DATA
} from '../../tokens';

// Интерфейсы
import { IContextMenuConfig } from '../../interfaces';

// Сервисы
import { CrmHelperService } from '../../services/crm-helper.service';

// Контекстное меню
@Component({
	selector: 'crm-context-menu',
	templateUrl: './crm-context-menu.component.html',
	styleUrls: ['./crm-context-menu.component.scss']
})
export class CrmContextMenuComponent implements OnDestroy {

	constructor(
		private readonly renderer: Renderer2,
		private readonly el: ElementRef,
		private readonly overlayRef: OverlayRef,
		@Inject(CONTEXT_MENU_CONFIG) public readonly config: IContextMenuConfig,
		@Inject(CONTEXT_MENU_DATA) public readonly data: any
	) {
		this.setArrowParams();
		this.addListener();
	}

	// Функция для отключения прослушивания события
	private clickListen: () => void;

	// Оси для overlay
	private readonly OVERLAY_X: string = 'overlay-x';
	private readonly OVERLAY_Y: string = 'overlay-y';

	// Оси для origin
	private readonly ORIGIN_X: string = 'origin-x';
	private readonly ORIGIN_Y: string = 'origin-y';

	// Переменные css для стрелки
	private readonly ARROW_SIZE: string = '--arrow-size';
	private readonly ARROW_OFFSET: string = '--arrow-offset';

	// Закрыть всплывающее окно
	public close(): void {
		this.overlayRef.dispose();
	}

	// Установка параметров для стрелки
	private setArrowParams(): void {
		const el = this.el && this.el.nativeElement;
		if (el) {
			el.style.setProperty(this.ARROW_SIZE, `${this.config.arrowSize}px`);
			el.style.setProperty(this.ARROW_OFFSET, `${this.config.arrowOffset}px`);
			el.setAttribute(this.OVERLAY_X, this.config.overlay.overlayX);
			el.setAttribute(this.OVERLAY_Y, this.config.overlay.overlayY);
			el.setAttribute(this.ORIGIN_X, this.config.origin.originX);
			el.setAttribute(this.ORIGIN_Y, this.config.origin.originY);
		}
	}

	// Добавить слушателя
	private addListener(): void {
		// Игнорируем нажатие которое вызвало всплывающее окно
		setTimeout(() => {
			this.clickListen = this.renderer.listen(
				document,
				'click',
				this.onClick.bind(this)
			);
		});
	}

	// Удалить слушателя
	private removeListener(): void {
		if (this.clickListen) { this.clickListen(); }
	}

	// Обработчик клика
	private onClick(event: MouseEvent): void {
		const overlayEl = this.el && this.el.nativeElement;
		const originEl = this.config.elementRef && this.config.elementRef.nativeElement;
		const path = CrmHelperService.eventPath(event);
		const isOverlayEl = path.some((node: Node) => node === overlayEl);
		const isOriginEl = path.some((node: Node) => node === originEl);

		if (!isOverlayEl && !isOriginEl) {
			this.close();
		}
	}

	// Обработчик выбора
	public onSelect(item: any): void {
		this.data.select.emit(item);
		this.close();
	}

	// --------------------------------------------------------------------------
	// HOOKS
	// Уничтожение
	public ngOnDestroy(): void {
		this.removeListener();
	}
}
