import {
	OverlayOrigin,
	OverlayRef
} from '@angular/cdk/overlay';
import {
	Component,
	EventEmitter,
	forwardRef,
	HostBinding,
	HostListener,
	Input,
	OnDestroy,
	OnInit,
	ViewChild
} from '@angular/core';
import {
	ControlValueAccessor,
	NG_VALUE_ACCESSOR
} from '@angular/forms';
import {
	format,
	parse
} from 'date-fns';
import * as ru from 'date-fns/locale/ru';

// Компоненты
import { CrmDatepickerPopupComponent } from '../../components/crm-datepicker-popup/crm-datepicker-popup.component';

// Сервисы
import { CrmContextMenuOverlayService } from '../../services';

// Выбор даты
@Component({
	selector: 'crm-datepicker',
	templateUrl: './crm-datepicker.component.html',
	styleUrls: ['./crm-datepicker.component.scss'],
	providers: [{
		provide: NG_VALUE_ACCESSOR,
		useExisting: forwardRef(() => CrmDatepickerComponent),
		multi: true
	}]
})
export class CrmDatepickerComponent implements
	OnInit, OnDestroy, ControlValueAccessor {

	constructor(private readonly contextMenuOverlay: CrmContextMenuOverlayService) {
		this.DATA.select.subscribe((date: Date) => {
			this.date = date;
		});
	}

	// Флаг наличия ошибки
	@HostBinding('attr.has-error')
	@Input() public hasError: boolean;

	// Заглушка поля
	@Input() public placeholder: string;

	// Ссылка на поле ввода
	@ViewChild('popupOrigin') private readonly popupOrigin: OverlayOrigin;

	// Конфигурация всплывающего окна
	private readonly CONFIG = {
		elementRef: null,
		overlayComponent: CrmDatepickerPopupComponent,
		origin: { originX: 'start', originY: 'bottom' },
		overlay: { overlayX: 'start', overlayY: 'top' }
	};

	// Данные календаря
	private readonly DATA = {
		selected: null,
		select: new EventEmitter<Date>()
	};

	// Вызовем когда значение изменится
	private onChange: (value: Date) => void;

	// Вызовем при любом дествии пользователя с контроллом
	private onTouched: () => void;

	// Дата
	public _date: Date;
	public get date(): Date {
		return this._date;
	}
	public set date(value: Date) {
		this._date = value;
		this.DATA.selected = value;
		this.text = value && format(value, 'DD.MM.YYYY', { locale: ru });

		if (this.onChange) {
			this.onChange(value);
		}
	}

	// Поле ввода
	public text: string;

	// Флаг, отключено
	public disabled: boolean = false;

	// Ссылка на календарь
	private overlayRef: OverlayRef;

	// Открыть окно
	private open(): void {
		if (
			!(this.overlayRef && this.overlayRef.hasAttached()) &&
			!this.disabled
		) {
			this.overlayRef = this.contextMenuOverlay.open(this.CONFIG, this.DATA);
		}
	}

	// Закрыть окно
	private close(): void {
		if (this.overlayRef) { this.overlayRef.dispose(); }
		this.overlayRef = null;
	}

	// Реакция на клик хост-элемента
	@HostListener('click') public onClick(): void {
		if (this.onTouched) {
			this.onTouched();
		}
	}

	// Открыть/скрыть календаь
	public onToggle(): void {
		if (this.overlayRef && this.overlayRef.hasAttached()) {
			this.close();
		} else {
			this.open();
		}
	}

	// Обработчик заполнености маски
	public onCompleteMask(isCompleted: boolean): void {
		this.date = isCompleted
			? parse(
					this.text
						.split('.')
						.reverse()
						.join('-')
				)
			: null;
	}

	// --------------------------------------------------------------------------
	// Вызовет форма, если значение изменилось извне
	public writeValue(date: Date): void {
		this.date = date;
	}

	// Сохраняем обратный вызов для изменений
	public registerOnChange(fn: any): void {
		this.onChange = fn;
	}

	// Сохраняем обратный вызов для "касаний"
	public registerOnTouched(fn: any): void {
		this.onTouched = fn;
	}

	// Установка состояния disabled
	public setDisabledState(isDisabled: boolean): void {
		this.disabled = isDisabled;
	}

	// --------------------------------------------------------------------------
	// HOOKS
	// Инициализация
	public ngOnInit(): void {
		this.CONFIG.elementRef = this.popupOrigin.elementRef;
	}

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