import {
	Overlay,
	OverlayConfig,
	OverlayRef
} from '@angular/cdk/overlay';
import {
	ComponentPortal,
	PortalInjector
} from '@angular/cdk/portal';
import {
	Injectable,
	Injector
} from '@angular/core';

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

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

// Перечисления
import { ConnectionPosition } from '../enums';

// Компоненты
import { CrmContextMenuComponent } from '../components/crm-context-menu/crm-context-menu.component';

// Сервис всплывающих окон контекстного меню
@Injectable()
export class CrmContextMenuOverlayService {

	constructor(
		private readonly injector: Injector,
		private readonly overlay: Overlay
	) {}

	// Конфигурация по умолчанию
	private readonly DEFAULT_CONFIG: IContextMenuConfig = {
		overlayComponent: CrmContextMenuComponent,
		origin: {
			originX: ConnectionPosition.End,
			originY: ConnectionPosition.Top
		},
		overlay: {
			overlayX: ConnectionPosition.Start,
			overlayY: ConnectionPosition.Top
		},
		arrowSize: 12,
		arrowOffset: 12
	};

	// Открыть всплывающее окно
	public open(config: IContextMenuConfig = {}, data?: any): OverlayRef {

		// Слияние конфигураций
		const mergedConfig = { ...this.DEFAULT_CONFIG, ...config };

		// Создание слоя всплывающего окна
		const overlayRef = this.createOverlay(mergedConfig);

		// Создание инжектора
		const injector = this.createInjector(overlayRef, mergedConfig, data);

		// Создание контейнера
		const containerPortal = new ComponentPortal<any>(
			mergedConfig.overlayComponent,
			mergedConfig.viewContainerRef,
			injector
		);
		overlayRef.attach(containerPortal);

		return overlayRef;
	}

	// Создать слой всплывающего окна
	private createOverlay(config: IContextMenuConfig): OverlayRef {
		const strategy = this.overlay.position()
			.connectedTo(
				config.elementRef,
				config.origin,
				config.overlay
			);

		const overlayConfig = new OverlayConfig({
			hasBackdrop: config.hasBackdrop,
			backdropClass: config.backdropClass,
			panelClass: config.panelClass,
			positionStrategy: strategy
		});

		return this.overlay.create(overlayConfig);
	}

	// Создать инжектор
	private createInjector(
		overlayRef: OverlayRef,
		config: IContextMenuConfig,
		data: any = null
	): PortalInjector {
		const injectionTokens = new WeakMap();

		injectionTokens.set(OverlayRef, overlayRef);
		injectionTokens.set(CONTEXT_MENU_CONFIG, config);
		injectionTokens.set(CONTEXT_MENU_DATA, data);

		return new PortalInjector(this.injector, injectionTokens);
	}
}
