import {
  AfterViewInit,
  ChangeDetectorRef,
  Component,
  ContentChildren,
  ElementRef, EventEmitter,
  Input, OnDestroy, Output,
  QueryList,
  ViewChild,
  Inject,
  PLATFORM_ID
} from "@angular/core";
import {SliderTabComponent} from "./slider-tab.component";
import {ActivatedRoute, Router} from "@angular/router";
import {Subscription} from "rxjs";
import {isPlatformServer} from "@angular/common";
import Timeout = NodeJS.Timeout;

declare var UIkit;

@Component({
  selector: 'slider-tabs',
  template: `
    <div #sliderElement class="uk-position-relative" [class.uk-slider]="position === 'horizontal'"
         [ngClass]="customClass">
      <div [class.uk-slider-container-tabs]="position === 'horizontal'" [class.uk-border-bottom]="border && position === 'horizontal'" [ngClass]="containerClass">
        <ul #tabsElement [class.uk-flex-nowrap]="position === 'horizontal'"
            [class.uk-slider-items]="position === 'horizontal'"
            [class.uk-tab-left]="position === 'left'" [class.uk-tab-right]="position === 'right'"
            [attr.uk-switcher]="type === 'static'?('connect:' + connect):null"
            [ngClass]="'uk-flex-' + flexPosition + ' ' + tabsClass">
          <ng-container *ngIf="type === 'static'">
            <li *ngFor="let tab of leftTabs" [ngStyle]="" [style.max-width]="(position === 'horizontal')?'50%':null" class="uk-text-capitalize uk-text-truncate uk-display-block">
              <a>
                  <span *ngIf="tab.title">{{tab.title}}</span>
                  <ng-container *ngTemplateOutlet="tab.tabTemplate"></ng-container>
              </a>
            </li>
            <li *ngFor="let tab of rightTabs; let i=index;" [style.max-width]="(position === 'horizontal')?'50%':null" [ngClass]="i === 0?'uk-flex-1 uk-flex uk-flex-right':''"
                class="uk-text-capitalize uk-text-truncate uk-display-block">
              <a [ngClass]="tab.customClass">
                  <span *ngIf="tab.title">{{tab.title}}</span>
                  <ng-container *ngTemplateOutlet="tab.tabTemplate"></ng-container>
              </a>
            </li>
          </ng-container>
          <ng-container *ngIf="type === 'dynamic'">
            <li *ngFor="let tab of leftTabs; let i=index;" [class.uk-active]="tab.active" [style.max-width]="(position === 'horizontal')?'50%':null">
              <a [routerLink]="tab.routerLink" [queryParams]="tab.queryParams" [ngClass]="tab.customClass" [relativeTo]="tab.relativeTo"
                 (click)="showActive(i)"
                 class="uk-text-capitalize uk-text-truncate uk-display-block">
                  <span *ngIf="tab.title">{{tab.title}}</span>
                  <ng-container *ngTemplateOutlet="tab.tabTemplate"></ng-container>
              </a>
            </li>
            <li *ngFor="let tab of rightTabs; let i=index;" [style.max-width]="(position === 'horizontal')?'50%':null" [class.uk-active]="tab.active"
                [ngClass]="i === 0?'uk-flex-1 uk-flex uk-flex-right':''">
              <a [routerLink]="tab.routerLink" [queryParams]="tab.queryParams" [ngClass]="tab.customClass" [relativeTo]="tab.relativeTo"
                 (click)="showActive(i)"
                 class="uk-text-capitalize uk-text-truncate uk-display-block">
                  <span *ngIf="tab.title">{{tab.title}}</span>
                  <ng-container *ngTemplateOutlet="tab.tabTemplate"></ng-container>
              </a>
            </li>
          </ng-container>
          <ng-container *ngIf="type === 'scrollable'">
            <li *ngFor="let tab of leftTabs" [style.max-width]="(position === 'horizontal')?'50%':null" class="uk-text-capitalize uk-text-truncate uk-display-block" [class.uk-active]="tab.active">
              <a routerLink="./" [fragment]="tab.id" queryParamsHandling="merge" [ngClass]="tab.customClass">
                  <span *ngIf="tab.title">{{tab.title}}</span>
                  <ng-container *ngTemplateOutlet="tab.tabTemplate"></ng-container>
              </a>
            </li>
            <li *ngFor="let tab of rightTabs; let i=index;" [style.max-width]="(position === 'horizontal')?'50%':null" class="uk-text-capitalize uk-text-truncate uk-display-block"
                [ngClass]="i === 0?'uk-flex-1 uk-flex uk-flex-right':''"
                [class.uk-active]="tab.active">
              <a routerLink="./" [fragment]="tab.id" queryParamsHandling="merge" [ngClass]="tab.customClass">
                  <span *ngIf="tab.title">{{tab.title}}</span>
                  <ng-container *ngTemplateOutlet="tab.tabTemplate"></ng-container>
              </a>
            </li>
          </ng-container>
        </ul>
      </div>
      <ng-container *ngIf="!isServer">
        <slider-arrow *ngIf="position === 'horizontal' && arrows" type="previous"></slider-arrow>
        <slider-arrow *ngIf="position === 'horizontal' && arrows" type="next"></slider-arrow>
      </ng-container>
    </div>
  `,
})
export class SliderTabsComponent implements AfterViewInit, OnDestroy {
  /**
   * Type of tabs:
   * Static = Uikit tabs with @connect class or selector
   * Dynamic = Active is defined by tabComponent's active Input
   * Scrollable = Active is defined by the active fragment of URL and position of scroll
   * */
  @Input()
  public type: 'static' | 'dynamic' | 'scrollable' = 'static';
  /**
   * Connect selector in static type. Default: .uk-switcher
   * */
  @Input()
  public connect = '.uk-switcher';
  /**
   * Threshold between 0.0 to 1.0 for Intersection Observer
   * */
  @Input()
  public scrollThreshold = 0.1;
  /**
   * Tabs view: Horizontal is the default.
   * */
  @Input()
  public position: 'horizontal' | 'left' | 'right' = 'horizontal';
  /**
   * Tabs flex position: Left is the default.
   * */
  @Input()
  public flexPosition: 'center' | 'left' | 'right' = 'left';
  /**
   * Set a class for the container
   * */
  @Input()
  public containerClass: string;
  /**
   * Set a class above tabs
   * */
  @Input()
  public customClass: string;
  /**
   * Tabs class
   * */
  @Input()
  public tabsClass: string = 'uk-tab';
  @Input()
  public border: boolean = true;
  @Input()
  public arrows: boolean = true;
  @ContentChildren(SliderTabComponent) tabs: QueryList<SliderTabComponent>;
  @ViewChild('sliderElement') sliderElement: ElementRef;
  @ViewChild('tabsElement') tabsElement: ElementRef;
  private slider;
  /**
   * Notify regarding new active element
   * */
  @Output() activeEmitter: EventEmitter<string> = new EventEmitter<string>();
  private activeIndex: number = 0;
  private subscriptions: any[] = [];
  private observer: IntersectionObserver;
  private timeout: Timeout;
  isServer: boolean;
  
  constructor(private route: ActivatedRoute,
              private router: Router,
              private cdr: ChangeDetectorRef,
              @Inject(PLATFORM_ID) private platform: any) {
    this.isServer = isPlatformServer(this.platform);
  }
  
  ngAfterViewInit() {
    this.initTabs();
    this.tabs.changes.subscribe(() => {
     this.initTabs();
    });
  }

  public initTabs() {
    if (typeof document !== 'undefined' && this.tabs.length > 0) {
      setTimeout(() => {
        if (this.position === 'horizontal') {
          this.slider = UIkit.slider(this.sliderElement.nativeElement, {finite: true});
          this.slider.clsActive = 'uk-slider-active';
          this.slider.updateActiveClasses();
          this.slider.slides.forEach((item, index) => {
            if(!this.tabs.get(index).active) {
              item.classList.remove('uk-active');
            }
          });
          if (this.type === 'static') {
            let tabs = UIkit.switcher(this.tabsElement.nativeElement, {connect: this.connect});
            tabs.show(this.activeIndex);
            if (this.connect.includes('#')) {
              this.scrollToStart();
            }
          } else if(this.type =='dynamic') {
            this.activeIndex = this.tabs.toArray().findIndex(tab => tab.active);
            this.slider.show(this.activeIndex);
          } else if (this.type === 'scrollable') {
            this.scrollable(this.slider);
          }
        } else {
          this.scrollable();
        }
      });
    }
  }
  
  private scrollToStart() {
    this.subscriptions.push(UIkit.util.on(this.connect, 'shown', (event): void => {
      let index = event.detail[0].index();
      if (index !== this.activeIndex) {
        this.activeIndex = index;
        this.router.navigate(['./'], {relativeTo: this.route, fragment: this.connect.replace('#', ''), queryParamsHandling: "merge"});
      }
    }));
  }
  
  private scrollable(slider = null) {
    this.activeFragment(this.route.snapshot.fragment, slider);
    this.subscriptions.push(this.route.fragment.subscribe(fragment => {
      this.activeFragment(fragment, slider);
    }));
    this.setObserver();
  }
  
  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},
              queryParamsHandling: 'merge'
            });
          }, 200);
        }
      });
    }, {threshold: 0.1});
    this.tabs.forEach(tab => {
      let element = document.getElementById(tab.id);
      if (element) {
        this.observer.observe(element);
      }
    });
  }

  public showActive(index) {
    this.activeIndex = index;
    this.activeEmitter.emit(this.tabs.get(this.activeIndex).id);
    if(this.slider) {
      this.slider.show(this.activeIndex);
    }
  }
  
  private activeFragment(fragment, slider) {
    let index = 0;
    if (fragment) {
      index = this.tabs.toArray().findIndex(item => item.id == fragment);
    }
    if (slider) {
      slider.show(index);
    }
    this.tabs.forEach((tab, i) => {
      if (index === i) {
        tab.active = true;
        this.activeEmitter.emit(tab.id);
      } else {
        tab.active = false;
      }
    });
    this.cdr.detectChanges();
  }
  
  get leftTabs(): SliderTabComponent[] {
    return this.tabs.toArray().filter(tab => tab.align === 'left');
  }
  
  get rightTabs(): SliderTabComponent[] {
    return this.tabs.toArray().filter(tab => tab.align === 'right');
  }
  
  ngOnDestroy() {
    this.subscriptions.forEach(subscription => {
      if (subscription instanceof Subscription) {
        subscription.unsubscribe();
      } else if (subscription instanceof Function) {
        subscription();
      }
    });
    if (this.observer) {
      this.observer.disconnect();
    }
  }
}
