
import {debounceTime} from 'rxjs/operators';
import {
    Directive,
    ElementRef,
    EventEmitter,
    HostBinding,
    HostListener,
    Input,
    OnDestroy,
    OnInit,
    Output
} from '@angular/core';
import { HypermediaLink } from './../interfaces';
import { ActivatedRoute, Router } from '@angular/router';
import { Subscription } from 'rxjs';
import { HrefFormatterProvider } from '../services/href-formatter-provider.service';

@Directive({
    selector: '[hmLink]'
})
export class LinkDirective implements OnDestroy, OnInit {
    @Output() beforeNavigation = new EventEmitter<'external' | 'local'>();
    @Input() target = '_blank';
    @Input() delayBeforeNavigation = 0;
    @Input() queryParams = {};

    @Input()
    set hmLink(link: HypermediaLink) {
        if (!link) {
            return;
        }

        this.isPage = link.rel.includes('page');
        this.isExternal = link.rel.includes('external');

        if (this.isPage) {

            const hrefFormatter = this.scopeProvider
                .getHrefFormatters()
                .find(scope => scope.matchesLink(link));

            this.href = hrefFormatter.makePathFromHref(link.href);
        } else if (this.isExternal) {
            this.href = link.href;
        }
    }

    isPage = false;
    isExternal = false;
    href: string;

    @HostBinding('class.active-link')
    activeClass: boolean;

    fragmentSubscription: Subscription;

    constructor(private router: Router,
                private activatedRoute: ActivatedRoute,
                private scopeProvider: HrefFormatterProvider) {
        this.fragmentSubscription = router.events.pipe(debounceTime(100))
            .subscribe(() => {
                if (this.href) {
                    this.activeClass = router.isActive(this.href, true);
                }
            });
    }

    ngOnInit(): void {
        this.activeClass = this.router.isActive(this.href, true);
    }

    private scrollToTop(): void {
        const element = document.querySelector('html');
        if (element) {
            setTimeout(() => {
                element.scrollIntoView({ behavior: 'smooth', block: 'start', inline: 'nearest' });
            }, 100);
        }
    }

    ngOnDestroy(): void {
        this.fragmentSubscription.unsubscribe();
    }

    @HostListener('click')
    onClick(): void {
        if (!this.href) {
            throw new Error('No link was provided!');
        }

        if (this.isPage) {
            this.beforeNavigation.emit('local');
            if(this.delayBeforeNavigation > 0) {
                setTimeout( () => { this.router.navigateByUrl(this.href, {queryParams: this.queryParams}); }, this.delayBeforeNavigation);
            } else {
                this.router.navigateByUrl(this.href, {queryParams: this.queryParams});
            }
            this.scrollToTop();
        } else if (this.isExternal) {
            this.beforeNavigation.emit('external');
            var esc = encodeURIComponent;
            var query = Object.keys(this.queryParams)
                .map(k => esc(k) + '=' + esc(this.queryParams[k]))
                .join('&');
            if(query != '') {
                query = "?" + query;
            }
            if(this.delayBeforeNavigation > 0) {
                setTimeout( () => { window.open(this.href + query, this.target); }, this.delayBeforeNavigation);
            } else {
                window.open(this.href + query, this.target);
            }
        }
    }
}
