import {HttpClient} from "@angular/common/http";
import {ChangeDetectorRef, Component, ElementRef, Input, OnDestroy, OnInit, ViewChild} from "@angular/core";
import {Subscription} from "rxjs";

import {Breadcrumb} from "../utils/breadcrumbs/breadcrumbs.component";
import {EnvProperties} from "../utils/properties/env-properties";
import {properties} from "src/environments/environment";
import {FormBuilder, FormControl} from "@angular/forms";
import {ActivatedRoute, Router} from "@angular/router";
import {Meta, Title} from "@angular/platform-browser";
import {Location} from "@angular/common";
import {StringUtils} from "../utils/string-utils.class";
import {SEOService} from "../sharedComponents/SEO/SEO.service";
import {PiwikService} from "../utils/piwik/piwik.service";
import {debounceTime, distinctUntilChanged} from "rxjs/operators";
import Timeout = NodeJS.Timeout;
import {ISVocabulariesService} from "../utils/staticAutoComplete/ISVocabularies.service";
import {SearchFields} from "../utils/properties/searchFields";

declare var UIkit;

@Component({
	selector: 'fos',
	templateUrl: 'fos.component.html',
	styleUrls: ['fos.component.less']
})
export class FosComponent implements OnInit, OnDestroy {
	public url: string = null;
	public pageTitle: string = "OpenAIRE | Fields of Science";
	public pageDescription: string = "We have integrated a Field-of-Science (FoS) taxonomy into our dataset to organize and discover research more effectively. Using the full capabilities of the OpenAIRE Graph (full-texts, citations, references, venues) we apply AI and bring forward any multidisciplinarity potential.";
	public fos: any[] = [];
	public fosOptions: string[] = [];
	public activeSection: string;

	public keywordControl: FormControl;
	public keyword: string;

	public viewResults = [];

	public result = [];

	properties: EnvProperties = properties;
	public breadcrumbs: Breadcrumb[] = [{name: 'home', route: '/'}, {name: 'Fields of Science'}];
	
	private subscriptions: Subscription[] = [];
	private observer: IntersectionObserver;
	private timeout: Timeout;
	@ViewChild('tabs') tabs: ElementRef;
	public sliderInit: boolean = false;
  private searchFieldsHelper: SearchFields = new SearchFields();

	constructor(
		private vocabulariesService: ISVocabulariesService,
		private fb: FormBuilder,
		private location: Location,
		private route: ActivatedRoute,
		private _router: Router,
		private _meta: Meta,
		private _title: Title,
		private seoService: SEOService,
		private _piwikService: PiwikService,
		private cdr: ChangeDetectorRef
	) {}

	ngOnInit() {
		this.subscriptions.push(this._piwikService.trackView(this.properties, this.pageTitle).subscribe());
		this.url = this.properties.domain + this.properties.baseLink + this._router.url;
		this.seoService.createLinkForCanonicalURL(this.url);
		this.updateUrl(this.url);
    this.updateTitle(this.pageTitle);
    this.updateDescription(this.pageDescription);
		this.vocabulariesService.getFos(properties).subscribe(data => {
			this.fos = data['fos'];
			this.convertFosToOptions();
			if (typeof document !== 'undefined') {
				setTimeout(()=> {
					let slider = UIkit.slider(this.tabs.nativeElement);
					slider.clsActive = 'uk-slider-active';
					slider.updateActiveClasses();
					this.sliderInit = true;
					slider.slides.forEach(item => {
						item.classList.remove('uk-active');
					});
					if (this.route.snapshot.fragment) {
						this.activeSection = this.route.snapshot.fragment;
						let i = this.fos.findIndex(item => item.id == this.route.snapshot.fragment);
						slider.show(i);
					} else {
						this.activeSection = this.fos[0].id;
					}
					this.cdr.detectChanges();
				});
			}
			this.subscriptions.push(this.route.fragment.subscribe(fragment => {
				if(fragment) {
					this.activeSection = fragment;
					if(this.tabs) {
						let slider = UIkit.slider(this.tabs.nativeElement);
						let i = this.fos.findIndex(item => item.id == fragment);
						slider.show(i);
					}
				} else {
					this.activeSection = this.fos[0].id;
				}
			}));
			this.keywordControl = this.fb.control('');
			this.subscriptions.push(this.keywordControl.valueChanges.pipe(debounceTime(500), distinctUntilChanged()).subscribe(value => {
				this.keyword = value;
				this.findMatches(this.keyword);
				if (typeof IntersectionObserver !== 'undefined') {
					setTimeout(() => {
						this.setObserver();
					});
				}
			}));
		});
	}

	public ngOnDestroy() {
    for (let sub of this.subscriptions) {
      sub.unsubscribe();
    }
		if(this.observer) {
			this.observer.disconnect();
		}
  }
	
	private setObserver() {
		if(this.observer) {
			this.observer.disconnect();
		}
		this.observer = new IntersectionObserver((entries) => {
			entries.forEach(entry => {
				if(entry.isIntersecting) {
					if(this.timeout) {
						clearTimeout(this.timeout);
					}
					this.timeout = setTimeout(() => {
						this._router.navigate(['./'], {fragment: entry.target.id, relativeTo: this.route, state: {disableScroll: true}});
					}, 200);
				}
			});
		}, {threshold: 0.25, rootMargin: '-100px'});
		this.fos.forEach(fos => {
			let element = document.getElementById(fos.id);
			if(element) {
				this.observer.observe(element);
			}
		});
	}
	
	convertFosToOptions() {
		this.fosOptions = [];
		this.fos.forEach(fos => {
			this.fosOptions.push(fos.id);
			if(fos.children) {
				fos.children.forEach(child => {
					this.fosOptions.push(child.id);
					if(child.children) {
						child.children.forEach(child2 => {
							this.fosOptions.push(child2.id);
						});
					}
				});
			}
		});
	}

	findMatches(value: string) {
		this.viewResults = JSON.parse(JSON.stringify(this.fos));
		let matchLevel1: boolean = false;
		let matchLevel2: boolean = false;
		// 1st level search
		if(this.viewResults.length) {
			this.viewResults = this.viewResults.filter(item => {
				matchLevel1 = !!item.id.includes(value?.toLowerCase());
				// // 2nd level search
				if(item.children?.length && !matchLevel1) {
					item.children = item.children.filter(subItem => {
						matchLevel2 = !!subItem.id.includes(value?.toLowerCase());
						// 3rd level search
						if(subItem.children?.length && !matchLevel2) {
							subItem.children = subItem.children.filter(subSubItem => subSubItem.id.includes(value?.toLowerCase()));
						}
						return subItem.children?.length > 0 || matchLevel2;
					});
				}
				return item.children?.length > 0;
			});
		}
	}

	highlightKeyword(name) {
		if(name.includes(this.keyword.toLowerCase())) {
			return name.replace(new RegExp(this.keyword, "gi"), (matchedValue) => `<mark class="highlighted">${matchedValue}</mark>`);
		} else {
			return name;
		}
	}

  public urlEncodeAndQuote(str: string): string {
    return StringUtils.quote(StringUtils.URIEncode(str));
  }

	private updateUrl(url: string) {
    this._meta.updateTag({content: url}, "property='og:url'");
  }

	private updateTitle(title: string) {
    var _title = ((title.length > 50) ? title.substring(0, 50) : title);
    this._title.setTitle(_title);
    this._meta.updateTag({content: _title}, "property='og:title'");
  }

	private updateDescription(description: string) {
    this._meta.updateTag({content: description}, "name='description'");
    this._meta.updateTag({content: description}, "property='og:description'");
  }

  public buildFosQueryParam(fos) {
    // return {'foslabel': this.urlEncodeAndQuote(fos.id+"||"+fos.label)};
    return (this.searchFieldsHelper.getFosParameter() == 'foslabel' ? ({'foslabel': this.urlEncodeAndQuote(fos.id+"||"+fos.label)}) : ({'fos': this.urlEncodeAndQuote(fos.id)}));
  }
}
