import {AfterContentChecked, Component, OnInit, TemplateRef, ViewChild} from '@angular/core';
import {MaterialModel} from '../models/material.model';
import {ApiService} from '../services/api.service';
import {ActivatedRoute, Router} from '@angular/router';
import {DataService} from '../services/data.service';
import strCompare from 'str-compare';
import {ModalService} from '@inst-iot/bosch-angular-ui-components';
import {AutocompleteService} from '../services/autocomplete.service';
import {NgForm, Validators} from '@angular/forms';
import {ValidationService} from '../services/validation.service';
import {ErrorComponent} from '../error/error.component';

@Component({
  selector: 'app-material',
  templateUrl: './material.component.html',
  styleUrls: ['./material.component.scss']
})
export class MaterialComponent implements OnInit, AfterContentChecked {

  @ViewChild('materialForm') materialForm: NgForm;

  material: MaterialModel;       // material to edit
  materialNames: string[] = [];  // all other material names for unique validation

  modalText = {list: '', suggestion: ''};  // modal for group and supplier correction
  loading = 0;                             // number of loading instances
  checkFormAfterInit = true;               // revalidate all fields on the next AfterContentChecked

  constructor(
    private api: ApiService,
    private route: ActivatedRoute,
    public d: DataService,
    private modal: ModalService,
    public autocomplete: AutocompleteService,
    private router: Router,
    private validation: ValidationService
  ) { }

  ngOnInit(): void {
    this.loading = 5;
    this.api.get<MaterialModel>('/material/' + this.route.snapshot.paramMap.get('id'), data => {
      this.material = new MaterialModel().deserialize(data);
      this.loading--;
      this.d.load('materials', () => {
        // filter out name of the edited material as it can stay the same
        this.materialNames = this.d.arr.materials.map(e => e.name).filter(e => e !== this.material.name);
        this.loading--;
      });
    });
    this.d.load('materialSuppliers', () => {
      this.loading--;
    });
    this.d.load('materialGroups', () => {
      this.loading--;
    });
    this.d.load('materialTemplates', () => {
      this.loading--;
    });
  }

  ngAfterContentChecked() {
    // attach validators
    if (this.materialForm && this.material.properties.material_template) {  // material template is set
      this.d.id.materialTemplates[this.material.properties.material_template].parameters.forEach((parameter, i) => {
        this.attachValidator(this.materialForm, 'materialParameter' + i, parameter.range);
      });
    }

    // revalidate
    if (this.checkFormAfterInit && this.materialForm !== undefined && this.materialForm.form.get('propertiesSelect')) {
      this.checkFormAfterInit = false;
      Object.keys(this.materialForm.form.controls).forEach(field => {
        this.materialForm.form.get(field).updateValueAndValidity();
      });
    }
  }

  // attach validators specified in range to input with name
  attachValidator(form, name: string, range: {[prop: string]: any}) {
    if (form && form.form.get(name)) {
      const validators = [];
      if (range.hasOwnProperty('required')) {
        validators.push(Validators.required);
      }
      if (range.hasOwnProperty('values')) {
        validators.push(this.validation.generate('stringOf', [range.values]));
      }
      else if (range.hasOwnProperty('min') && range.hasOwnProperty('max')) {
        validators.push(this.validation.generate('minMax', [range.min, range.max]));
      }
      else if (range.hasOwnProperty('min')) {
        validators.push(this.validation.generate('min', [range.min]));
      }
      else if (range.hasOwnProperty('max')) {
        validators.push(this.validation.generate('max', [range.max]));
      }
      form.form.get(name).setValidators(validators);
    }
  }

  materialSave() {
    this.api.put('/material/' + this.material._id, this.material.sendFormat(), () => {
      delete this.d.arr.materials;  // reload materials
      this.d.load('materials');
      this.router.navigate(['/materials']);
    });
  }

  deleteConfirm(modal) {
    this.modal.open(modal).then(result => {
      if (result) {
        this.api.delete('/material/' + this.material._id, (ignore, error) => {
          if (error) {  // material cannot be deleted as it is still referenced by active samples
            const modalRef = this.modal.openComponent(ErrorComponent);
            modalRef.instance.message = 'Cannot delete material as it is still in use!';
          }
          else {
            this.router.navigate(['/materials']);
          }
        });
      }
    });
  }

  checkTypo(event, list, mKey, modal: TemplateRef<any>) {
    // user did not click on suggestion and entry is not in list
    if (!(event.relatedTarget && (event.relatedTarget.className.indexOf('rb-dropdown-item') >= 0 ||
      event.relatedTarget.className.indexOf('close-btn rb-btn rb-passive-link') >= 0)) &&
      this.d.arr[list].indexOf(this.material[mKey]) < 0) {
      this.modalText.list = mKey;
      this.modalText.suggestion = this.d.arr[list]  // find possible entry from list
        .map(e => ({v: e, s: strCompare.sorensenDice(e, this.material[mKey])}))
        .sort((a, b) => b.s - a.s)[0].v;
      this.modal.open(modal).then(result => {
        if (result) {  // use suggestion
          this.material[mKey] = this.modalText.suggestion;
        }
      });
    }
  }

}
