import { Component, OnInit, OnDestroy, ElementRef, ViewChild, ChangeDetectorRef, ChangeDetectionStrategy, Input } from '@angular/core';
import { Process } from '../../core/models/process.model';
import { Observable, Subject } from 'rxjs';
import { Breadcrumb } from '../../core/models/breadcrumb.model';
import { Store, Select } from '@ngxs/store';
import { AddProcess } from '../../core/store/actions/process.actions';
import { addAnimation } from './add.animation';
import { Router } from '@angular/router';
import { AddBreadcrumb } from '../../core/store/actions/breadcrumb.actions';
import { takeUntil, switchMap, filter, distinctUntilChanged } from 'rxjs/operators';
import { ProcessSelectors } from '../../core/store/selectors/process.selectors';
import { WindowRef } from '../../core/services/window-ref.service';
import { ModuleSwitcher } from '../../core/models/app-switcher.enum';

@Component({
  selector: 'app-process-header',
  templateUrl: './process-header.component.html',
  styleUrls: ['./process-header.component.scss'],
  animations: [addAnimation],
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ProcessHeaderComponent implements OnInit, OnDestroy {
  startProcessLabel = 'VORGANG STARTEN';
  @ViewChild('panel', { read: ElementRef }) public panel: ElementRef<any>;
  @Select(ProcessSelectors.getProcesses) process$: Observable<Process[]>;
  @Select(ProcessSelectors.getCurrentProcess) selectedProcess$: Observable<Process>;
  @Input() module: ModuleSwitcher;
  branchProcess = <Process>{
    id: 1,
    name: 'Wareneingang',
  };
  processes: Process[] = [];
  destroy$ = new Subject();
  showNext = false;
  showBack = false;
  showFowardContainer = false;
  showBackContainer = false;
  offset: number;
  selectedProcessId: string;
  selectedProcess: any;
  isIPad = false;
  showAddingPadding = false;
  private iPadDetected = false;
  private iPadEventRecieved = false;

  constructor(private store: Store, private router: Router, private cdr: ChangeDetectorRef, private windowRef: WindowRef) {}

  addProcess() {
    const itemNo = !this.processes
      ? 0
      : this.processes && this.processes.length === 0
      ? 1
      : this.processes[this.processes.length - 1].id + 1;
    const newProcess = <Process>{
      id: itemNo,
      new: true,
      name: `Vorgang ${itemNo}`,
      currentRoute: '/product/search',
    };
    if (itemNo >= 4) {
      this.initializeAnimation(itemNo);
    }
    this.store
      .dispatch(new AddProcess(newProcess))
      .toPromise()
      .then(() => {
        this.store.dispatch(
          new AddBreadcrumb(
            <Breadcrumb>{
              name: 'Artikelsuche',
              path: '/product/search',
            },
            'product',
            true
          )
        );
        this.router.navigate(['/product/search']);
      });
  }

  ngOnInit() {
    this.isIPad = this.isIPadEnv();
    this.selectedProcess$
      .pipe(
        switchMap((proc: Process) => {
          if (proc) {
            this.selectedProcessId = proc.id + '';
          }

          return this.process$;
        }),
        takeUntil(this.destroy$),
        distinctUntilChanged((prev, curr) => this.processComperer(prev, curr))
      )
      .subscribe(
        (data) => {
          this.processes = data;
          this.cdr.detectChanges();
          if (this.panel.nativeElement.children.length > 0) {
            this.scrollableArrows();
          }
        },
        (err) => console.error(err)
      );
  }

  private initializeAnimation(processCount: number) {
    this.showAddingPadding = true;
    this.cdr.detectChanges();

    setTimeout(() => {
      this.panel.nativeElement.scrollTo({ left: this.panel.nativeElement.scrollLeft + 300 * processCount, behavior: 'smooth' });
      this.cdr.detectChanges();
    }, 100);
  }

  processComperer(prev: Process[], curr: Process[]) {
    try {
      if (!prev || !curr) {
        return false;
      }
      if (prev.length !== curr.length) {
        return false;
      }
      if (prev.length === 0 || curr.length === 0) {
        return false;
      }
      const prevStr = JSON.stringify(
        prev.map((t) => {
          return { new: t.new, name: t.name };
        })
      );
      const currStr = JSON.stringify(
        curr.map((t) => {
          return { new: t.new, name: t.name };
        })
      );
      const status = prevStr === currStr;
      return status;
    } catch (error) {
      return false;
    }
  }

  ngOnDestroy() {
    this.destroy$.next();
  }

  isIPadEnv() {
    const navigator = this.windowRef.nativeWindow.navigator as Navigator;
    const standalone = (navigator as any).standalone,
      userAgent = navigator.userAgent.toLowerCase(),
      ios = /iphone|ipod|ipad/.test(userAgent);

    this.iPadDetected = ios && !standalone;
    return this.iPadDetected || this.iPadEventRecieved;
  }

  scrollableArrows() {
    this.offset = Math.ceil(this.panel.nativeElement.clientWidth / 2);
    let selected: any;

    for (let _i = 0; _i < this.panel.nativeElement.children.length; _i++) {
      const proc = this.panel.nativeElement.children[_i];
      if (proc.id === this.selectedProcessId) {
        selected = proc;
        this.selectedProcess = proc;
      }
    }

    const lastProcess = this.panel.nativeElement.children[this.panel.nativeElement.children.length - 1];

    if (selected) {
      const clientWidth = this.panel.nativeElement.clientWidth;

      this.showAddingPadding = false;
      this.cdr.detectChanges();

      const selecetedPos = selected.offsetLeft + selected.offsetWidth;
      const lastPos = lastProcess.offsetLeft + lastProcess.offsetWidth;

      this.showFowardContainer =
        (selecetedPos + this.offset * 2 > clientWidth || selecetedPos + this.offset < lastPos) &&
        lastPos > clientWidth &&
        lastPos > this.panel.nativeElement.scrollWidth;

      // This number is from testing > 643
      this.showBackContainer = selecetedPos > 643;
    }

    this.cdr.detectChanges();
  }

  scrollBack() {
    const moveCalc = this.panel.nativeElement.scrollLeft - this.offset;
    this.panel.nativeElement.scrollTo({ left: moveCalc, behavior: 'smooth' });
    this.cdr.detectChanges();

    this.showBackContainer = this.panel.nativeElement.scrollLeft - this.offset > 0;
    this.showBack = false;

    this.showFowardContainer = this.panel.nativeElement.scrollLeft < this.panel.nativeElement.scrollWidth;

    this.cdr.detectChanges();
  }

  scrollFoward() {
    const moveCalc = this.panel.nativeElement.scrollLeft + this.offset;
    this.panel.nativeElement.scrollTo({ left: moveCalc, behavior: 'smooth' });
    this.cdr.detectChanges();

    this.showFowardContainer = moveCalc + this.offset * 2 < this.panel.nativeElement.scrollWidth;
    this.showNext = false;

    // If clicked next, then back button is always there
    this.showBackContainer = true;
    this.cdr.detectChanges();
  }

  showFowardIcon() {
    this.showNext = true;
  }

  hideFowardIcon() {
    this.showNext = false;
  }

  showBackIcon() {
    this.showBack = true;
  }

  hideBackIcon() {
    this.showBack = false;
  }
}
