import { Component, ElementRef, HostListener, Injectable, Input, Renderer2, ViewChild, AfterViewInit, forwardRef } from '@angular/core';
import { AbstractControl, ControlValueAccessor, FormControl, FormGroup, NG_VALIDATORS, NG_VALUE_ACCESSOR, ValidationErrors } from '@angular/forms';
import { IAnalysisTag } from '../../shared';
import { MatChipInputEvent } from '@angular/material';
import { COMMA, ENTER } from '@angular/cdk/keycodes';
import { BsDropdownDirective } from 'ngx-bootstrap';
import { difference as _difference, findIndex as _findIndex } from 'lodash/array';
import { InputNumberComponent } from '../../shared/libs/input-number/input-number.component';

abstract class Evt extends EventTarget {
  abstract get value(): string;
}

@Component({
  selector: 'knk-tag',
  templateUrl: './tag.component.html',
  styleUrls: ['./tag.component.scss'],
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => TagComponent),
      multi: true
    }
    // {
    //   provide: NG_VALIDATORS,
    //   useExisting: UploadGraphComponent, // forwardRef(() => PriceComponent),
    //   multi: true
    // }
  ]
})
export class TagComponent implements ControlValueAccessor {
  tags: IAnalysisTag[] = [];
  selectable: boolean = true;
  removable: boolean = true;
  @Input('availabletags') availabletags: IAnalysisTag[];
  @Input('isotherallowed') isotherallowed: boolean = false;
  // todo: is redo?!
  @Input('redo') redo: boolean = false;
  @ViewChild('dropdown') dropdown: BsDropdownDirective;
  @ViewChild('search') search: ElementRef;

  tagstest: Array<{ name: string }> = [{name: 'Tag1'}, {name: 'Accu'}];

  findCtrl: FormControl;
  find: string;

  visible: boolean = true;
  addOnBlur: boolean = true;

  separatorKeysCodes: number[] = [ENTER, COMMA];

  onChange: (param: IAnalysisTag[]) => void;

  get differenceTags(): IAnalysisTag[] {
    return _difference(this.availabletags, this.tags);
  }

  constructor(private renderer: Renderer2) {
    this.findCtrl = new FormControl('');
  }

  searchScan(): void {
    if (this.search && this.dropdown) {
      const input: HTMLInputElement = this.search.nativeElement as HTMLInputElement;
      const value: string = input.value || '';
      if (value.trim() !== '' && this.tagExistsByName(value, false)) {
        this.dropdown.show();
      } else {
        this.dropdown.hide();
      }
    }
  }

  tagExistsByName(value: string, strict: boolean = false): boolean {
    let tags: IAnalysisTag[] = this.availabletags || [];
    let index: number = -1;

    if (!value || value.length === 0) {
      return false;
    }

    if (!Array.isArray(tags) || tags.length === 0) {
      return false;
    }

    if (!!strict) {
      index = _findIndex(tags, (tag: IAnalysisTag) => (tag.name.toString().toLowerCase() === value.toLowerCase()));
    } else {
      index = _findIndex(tags, (tag: IAnalysisTag) => (tag.name.toString().toLowerCase().indexOf(value.toLowerCase()) !== -1));
    }

    if (index === -1) {
      return false;
    }
    return true;
  }

  removeAll(): void {
    this.tags = [];

    if (this.onChange) {
      this.onChange(this.tags);
    }
  }

  check(tag: IAnalysisTag): void {
    let index: number = this.tags.indexOf(tag);
    if (index !== -1) {
      this.tags.splice(index, 1);
    } else {
      this.tags.push(tag);
    }

    if (this.search && this.dropdown) {
      const input: HTMLInputElement = this.search.nativeElement as HTMLInputElement;
      input.value = '';
      this.dropdown.hide();
    }

    if (this.onChange) {
      this.onChange(this.tags);
    }
  }

  add(input: HTMLInputElement): void {
    let value: string = input.value;
    if ((value || '').trim()) {
      this.tags.push({analysisTagId: -1, name: value.trim()});
    }

    if (this.search && this.dropdown) {
      const input: HTMLInputElement = this.search.nativeElement as HTMLInputElement;
      input.value = '';
      this.dropdown.hide();
    }

    if (this.onChange) {
      this.onChange(this.tags);
    }
  }

  remove(tag: IAnalysisTag): void {
    let index: number = this.tags.indexOf(tag);

    if (index >= 0) {
      this.tags.splice(index, 1);
    }

    if (this.onChange) {
      this.onChange(this.tags);
    }
  }

  isSelected(tag: IAnalysisTag): boolean {
    return this.tags.indexOf(tag) !== -1;
  }

  writeValue(value: IAnalysisTag[]): void {
    if (Array.isArray(value) && value.length) {
      this.tags = value;
    }
    // if (this.tags) {
    //     this.renderer.setProperty(this.imgUrlCtrl.nativeElement, 'value', this.imgGraph);
    // }
  }

  registerOnChange(fn: () => void): void {
    this.onChange = fn;
  }

  registerOnTouched(fn: () => void): void {
    console.log('registerOnTouched');
  }

  @HostListener('document:click', ['$event.target']) onClick(event: EventTarget): void {
    if (!this.redo) {
      const isOpen: string = 'isOpen';
      const hide: string = 'hide';
      const parentNode: string = 'parentNode';
      const classname: string = 'className';
      if (this.dropdown && this.dropdown[isOpen] &&
        !this.isParentClassMatched(event, ['ddtags', 'auto', 'tags-panel', 'mat-option-text'])) {
        this.dropdown[hide]();
      }
    }
  }

  private isParentClassMatched(event: EventTarget, classNameToMatch: string[]): boolean {
    const parentNode: string = 'parentNode';
    const classname: string = 'className';
    if (event[classname] && event[classname].split(' ').find(v => classNameToMatch.find(r => r === v))) {
      return true;
    } else if (event[parentNode]) {
      return this.isParentClassMatched(event[parentNode], classNameToMatch);
    } else {
      return false;
    }
  }
}
