import {
    AfterViewInit, Component, ContentChildren, ElementRef,
    OnDestroy, QueryList, ViewChild, ViewContainerRef
} from '@angular/core';
import { AppState } from '../../../app.service';
import { fromEvent } from 'rxjs/observable/fromEvent';
import { Subject } from 'rxjs/Subject';
import { takeUntil } from 'rxjs/operators/takeUntil';
import { debounceTime } from 'rxjs/operators/debounceTime';
import { merge } from 'rxjs/operators/merge';
import { IntervalService } from '../../../services/interval';
import { TemplateDirective } from '../../template.directive';
import { FromEventObservable } from 'rxjs/observable/FromEventObservable';
import { WindowRef } from '../../../services/window.service';
import { EventService } from '../ui-news/event.service';


@Component({
    selector: '[ui-navigation]',
    styleUrls: ['./navigation.component.less'],
    templateUrl : './navigation.component.html',
    providers: [ EventService ]
})
export class NavigationComponent implements AfterViewInit, OnDestroy {
    @ContentChildren(TemplateDirective) items: QueryList<TemplateDirective>;
    @ViewChild('mainNav') mainNav: ElementRef;
    @ViewChild('mainContainer', {read: ViewContainerRef}) mainContainer: ViewContainerRef;
    @ViewChild('dropContainer', {read: ViewContainerRef}) dropContainer: ViewContainerRef;
    showDropButton; // can not bind to dropContainer.length
    destroyed = new Subject;

    constructor(
        public appState: AppState,
        private interval: IntervalService,
        public winRef: WindowRef
    ) {}

    viewWidth(view, update?) {
        if (update) {
            view._view.width = view.rootNodes[0].offsetWidth;
        }
        return view._view.width;
    }

    getMainItemsWidth() {
        let res = 0;
        for (let i = 0; i < this.mainContainer.length; i++) {
            let view = this.mainContainer.get(i);
            res += this.viewWidth(view, true);
        }
        return res;
    }

    getMainNavWidth() {
        return this.mainNav.nativeElement.offsetWidth - 390; // 390 - correlation
    }

    addToMain() {
        if (this.dropContainer.length) {
            const view = this.dropContainer.get(0);
            this.dropContainer.detach(this.dropContainer.indexOf(view));
            this.mainContainer.insert(view, this.mainContainer.length);
            return true;
        }
    }

    addToDrop() {
        if (this.mainContainer.length) {
            const view = this.mainContainer.get(this.mainContainer.length - 1);
            this.mainContainer.detach(this.mainContainer.indexOf(view));
            if (!view.destroyed) {
                this.dropContainer.insert(view, 0);
            }
            return true;
        }
    }

    fillMenu() {
        this.items.forEach(item => {
            this.mainContainer.createEmbeddedView(item.template);
        });
    }

    ngOnDestroy() {
        this.destroyed.next();
    }

    ngAfterViewInit() {
        setTimeout(() => this.fillMenu());

        FromEventObservable
            .create(this.winRef.nativeWindow, 'resize')
            .pipe(
                merge(this.interval.interval10),
                debounceTime(10),
                takeUntil(this.destroyed),
            )
            .subscribe(() => this.normalize());
    }

    normalize() {
        let changed;
        const mainNavWidth = this.getMainNavWidth();
        do {
            const mainItemsWidth = this.getMainItemsWidth();
            changed = false;
            if (this.winRef.nativeWindow.innerWidth < 768) {
                changed = this.addToMain();
            } else if (mainNavWidth < mainItemsWidth) {
                changed = this.addToDrop();
            } else {
                if (this.dropContainer.length &&
                    mainNavWidth > mainItemsWidth + this.viewWidth(this.dropContainer.get(0))
                ) {
                    changed = this.addToMain();
                }
            }
        } while (changed);
        this.showDropButton = !!this.dropContainer.length;
    }
}
