import {ChangeDetectorRef, Component, ElementRef, Input, ViewChild} from "@angular/core";
import {FormBuilder, FormControl, UntypedFormArray} from "@angular/forms";
import {ActivatedRoute, Router} from "@angular/router";
import {Subscription} from "rxjs";
import {EnvProperties} from "../../utils/properties/env-properties";
import {properties} from "../../../../environments/environment";
import {StringUtils} from "../../utils/string-utils.class";
import {debounceTime, distinctUntilChanged} from "rxjs/operators";
import {HelperFunctions} from "../../utils/HelperFunctions.class";
import {ISVocabulariesService} from "../../utils/staticAutoComplete/ISVocabularies.service";
import Timeout = NodeJS.Timeout;

declare var UIkit;

@Component({
  selector: 'fos-selection',
  templateUrl: 'fos-selection.component.html',
  styleUrls: ['fos-selection.component.less']
})
export class FosSelectionComponent {
  public properties: EnvProperties = properties;
  @Input() subjects: string[];
  @Input() inModal: boolean = false;
  @Input() contentHeight: number = 0;
  @ViewChild("searchElement") searchElement: ElementRef;

  public loading: boolean;
  public fos: any[] = [];
  // public fosOptions: Map<string, boolean>;
  public fosOptions: UntypedFormArray;
  public activeSection: string;

  public keywordControl: FormControl;
  public keyword: string;

  public viewResults = [];

  public result = [];

  private subscriptions: Subscription[] = [];
  private observer: IntersectionObserver;
  private timeout: Timeout;
  @ViewChild('tabs') tabs: ElementRef;
  public sliderInit: boolean = false;

  constructor(
    private vocabulariesService: ISVocabulariesService,
    private fb: FormBuilder,
    private cdr: ChangeDetectorRef,
    private route: ActivatedRoute,
    private _router: Router
  ) {}

  ngOnInit() {
    this.loading = true;
    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;
          }
          if(typeof IntersectionObserver !== "undefined") {
            this.setObserver();
          }
          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();
          });
        }
      }));
      this.loading = false;
    });
  }

  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(() => {
            if(!this.inModal) {
              this._router.navigate(['./'], {
                fragment: entry.target.id,
                relativeTo: this.route,
                state: {disableScroll: true}
              });
            } else {
              this.activeSection = entry.target.id;
            }
          }, 200);
        }
      });
    }, {threshold: 0.1, rootMargin: '-100px'});
    this.fos.forEach(fos => {
      let element = document.getElementById(fos.id);
      if(element) {
        this.observer.observe(element);
      }
    });
  }

  convertFosToOptions() {
    this.fosOptions = this.fb.array([]);
    this.fos.forEach(fos => {
      this.fosOptions.push(this.fb.group({
        id: this.fb.control(fos.id),
        checked: this.fb.control(false)
      }));
      if(fos.children) {
        fos.children.forEach(child => {
          this.fosOptions.push(this.fb.group({
            id: this.fb.control(fos.id),
            checked: this.fb.control(false)
          }));
          if(child.children) {
            child.children.forEach(child2 => {
              this.fosOptions.push(this.fb.group({
                id: this.fb.control(child2.id),
                checked: this.fb.control(this.subjects?.includes(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 reset() {
		this.fosOptions.controls.forEach(control => {
			control.get('checked').setValue(this.subjects?.includes(control.value.id));
		});
	}

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

  public scrollToId(value: string) {
    HelperFunctions.scrollToId(value);
    this.activeSection = value;
  }

  public getSelectedSubjects() {
    if(this.fosOptions) {
      return this.fosOptions.value.filter(sub => sub.checked == true);
    }
    return [];
  }

  public getControl(id: string) {
    if(this.fosOptions?.controls) {
      return this.fosOptions.controls.find(control => control.value.id === id);
    }
    return null;
  }

  public get hasChanges() {
		return !!this.fosOptions && this.fosOptions.dirty;
	}

  get calculatedHeight(): number {
    if(this.contentHeight && this.searchElement) {
      return this.contentHeight - this.searchElement.nativeElement.offsetHeight - 100;
    }
  }
}
