import { AfterViewInit, Component, Inject, OnInit, Renderer2, ViewChildren, QueryList, OnDestroy } from '@angular/core';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material';
import { TranslateService } from '@ngx-translate/core';
import { AbstractControl, FormBuilder, FormGroup, NgForm } from '@angular/forms';
import { NouisliderComponent } from 'ng2-nouislider';
import { has as _has } from 'lodash/object';
import { KnokService } from '../../shared';
import { Subject } from 'rxjs/Subject';
import { Observable } from 'rxjs/Observable';

@Component({
  selector: 'knk-feedback-knok',
  styleUrls: ['knk-feedback-knok.component.scss'],
  templateUrl: 'knk-feedback-knok.component.pug'
})
export class KnkFeedbackKnokComponent implements OnInit, AfterViewInit, OnDestroy {
  @ViewChildren('noUiSlider', {read: NouisliderComponent}) noUiSliders: QueryList<NouisliderComponent>;

  lang: string;
  feedbackForm: FormGroup;
  knokId: number = -1;
  sliderConfig: any = {
    orientation: 'horizontal',
    connect: true,
    tooltips: true,
    step: 1,
    start: 1,
    range: {
      min: 1,
      max: 5
    }
  };

  private ngUnsubscribe: Subject<void> = new Subject<void>();

  constructor(public dialogRef: MatDialogRef<any>,
              @Inject(MAT_DIALOG_DATA) private data: any,
              private renderer: Renderer2,
              private translateService: TranslateService,
              private knokService: KnokService,
              private fb: FormBuilder) {
    this.knokId = +data.knokId;
  }

  ngOnInit(): void {
    this.lang = this.translateService.currentLang || this.translateService.defaultLang;

    this.feedbackForm = this.fb.group({
      knokId: this.fb.control(String(this.knokId)),
      clear: this.fb.control(+this.sliderConfig.start || 1),
      educational: this.fb.control(+this.sliderConfig.start || 1),
      comprehensive: this.fb.control(+this.sliderConfig.start || 1),
      comment: this.fb.control('')
    });
    this.feedbackForm.updateValueAndValidity({emitEvent: false});
  }

  ngAfterViewInit(): void {
    // todo: implement "Pride" slider
    this.noUiSliders.forEach((noUiSlider: NouisliderComponent): void => {
      noUiSlider.update.distinctUntilChanged().subscribe((values: string[]): void => {
        let slider: any = noUiSlider.slider;
        let handles: any[] = noUiSlider.handles;

        if (handles.length !== 1) {
          return;
        }

        let options: any = slider.options;
        let target: HTMLElement = slider.target;
        let base: HTMLElement = target.querySelector<HTMLElement>('.noUi-base');

        let handle: HTMLElement = handles[0];
        let handleValue: number = parseFloat(handle.getAttribute('aria-valuetext'));
        let handleRoundValue: number = parseInt(handle.getAttribute('aria-valuetext'), 10);
        let handlePercentage: number = parseFloat(handle.getAttribute('aria-valuenow'));

        if (!target.classList.contains('noUi-rate')) {
          this.renderer.addClass(target, 'noUi-rate');
        }

        let connect: HTMLElement = base.querySelector<HTMLElement>('.noUi-rate-connect');
        if (!connect) {
          connect = this.renderer.createElement('div');
          this.renderer.addClass(connect, 'noUi-rate-connect');
          this.renderer.appendChild(base, connect);
        }

        let splash: HTMLElement = connect.querySelector<HTMLElement>('.noUi-rate-connect-splash');
        if (!splash) {
          splash = this.renderer.createElement('div');
          this.renderer.addClass(splash, 'noUi-rate-connect-splash');
          this.renderer.appendChild(connect, splash);
        }
        this.renderer.setStyle(splash, 'width', `${100 - handlePercentage}%`);

        let backdrop: HTMLElement = connect.querySelector<HTMLElement>('.noUi-rate-connect-backdrop');
        if (!backdrop) {
          backdrop = this.renderer.createElement('div');
          this.renderer.addClass(backdrop, 'noUi-rate-connect-backdrop');
          this.renderer.appendChild(connect, backdrop);
        }

        if (_has(options.range, ['min']) && _has(options.range, ['max'])) {
          for (let j: number = +options.range.min; j <= +options.range.max; j += (+options.step || 1)) {
            let x: number = parseInt(String(j), 10);
            if (target.classList.contains(`noUi-rate--point-${x}`) && handleRoundValue !== x) {
              this.renderer.removeClass(target, `noUi-rate--point-${x}`);
            }
            if (!target.classList.contains(`noUi-rate--point-${handleRoundValue}`)) {
              this.renderer.addClass(target, `noUi-rate--point-${handleRoundValue}`);
            }
          }

          let rails: HTMLElement = base.querySelector<HTMLElement>('.noUi-rate-rails');
          if (!rails) {
            rails = this.renderer.createElement('div');
            this.renderer.addClass(rails, 'noUi-rate-rails');
            this.renderer.appendChild(base, rails);
          }

          let railList: NodeListOf<Element> = rails.getElementsByClassName('noUi-rate-rails');
          if (railList.length !== options.range.max) {
            while (rails.hasChildNodes()) {
              rails.removeChild(rails.firstChild);
            }

            for (let i: number = +options.range.min; i <= +options.range.max; i += +options.step) {
              let n: number = (i - 1) * +options.range.max * +options.range.max;
              let rail: HTMLElement = this.renderer.createElement('div');
              this.renderer.addClass(rail, 'noUi-rate-rail');
              this.renderer.appendChild(rails, rail);
              this.renderer.setStyle(rail, 'left', `${n}%`);
            }
          }
        }
      });
    });
  }

  ngOnDestroy(): void {
    this.ngUnsubscribe.next();
    this.ngUnsubscribe.complete();
  }

  onSubmit(form: FormGroup): void {
    if (this.feedbackForm.valid) {
      this.knokService.addOngoingKnokFeedback(this.feedbackForm.value).subscribe((result: any) => {
        if (_has(result, ['value']) && !!result.value) {
          Observable.timer(1000).takeLast(1).subscribe((): void => {
            this.feedbackForm.reset({
              knokId: String(this.knokId),
              clear: (+this.sliderConfig.start || 1),
              educational: (+this.sliderConfig.start || 1),
              comprehensive: (+this.sliderConfig.start || 1),
              comment: ''
            }, {emitEvent: true});
            this.feedbackForm.updateValueAndValidity({emitEvent: false});

            if (_has(this.data, ['markFeedback']) && typeof this.data.markFeedback === 'function') {
              this.data.markFeedback();
            }
            this.close();
          });
        }
      });
    }
  }

  close(): void {
    this.dialogRef.close(false);
  }
}
