import {Component, forwardRef, Input, OnInit, ViewChild} from '@angular/core';
import {AuthService} from '../service/auth.service';
import { debounce } from 'ts-debounce';
import {PeopleModel} from '../models/people.model';
import {ControlValueAccessor, FormControl, FormGroup, NG_VALUE_ACCESSOR} from '@angular/forms';
import {MultiColumnComboBoxComponent} from '@progress/kendo-angular-dropdowns';
import {Observable} from 'rxjs';
import {PeopleService} from '../service/people.service';

@Component({
  selector: 'app-people-select',
  templateUrl: './people-select.component.html',
  styleUrls: ['./people-select.component.scss'],
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => PeopleSelectComponent),
      multi: true
    }
  ]
})
export class PeopleSelectComponent implements OnInit, ControlValueAccessor {

  @Input() disabled = false;
  @Input() translateId: true; // always tralsnate user Id, because name is not unique
  @Input() width: number;
  @Input() initSearch: PeopleModel[];
  @Input() formControl: FormControl = new FormControl(); // this is a dummy place holder
  @ViewChild('list', {static: true}) public text: MultiColumnComboBoxComponent;

  public searchResult: PeopleModel[] = [];
  public value = ''; // selecting the default and only empty contact element // TODO: remove ngModel
  public total = 0;

  private debounceFilter: any ;

  // Function to call when the rating changes.
  private onChange = ( nameOrId: string) => {};
  // Function to call when the input is touched (when a star is clicked).
  private onTouched = () => {};


  constructor(private auth: AuthService, private ps: PeopleService) { }

  ngOnInit(): void {
     this.prepareSearchPeople();
     this.initSearchResult();
  }

  private initSearchResult(): void {
    this.initSearch.forEach( v => {
      this.searchResult.push(v);
    });
    this.total = this.initSearch.length;
  }

  private prepareSearchPeople(): void{
    this.debounceFilter = debounce(  (filter: string): void => {
      this.ps.getPeopleList(filter).subscribe(
        resp => {
          this.text.loading = false;
          this.searchResult = resp.List;
          this.total = resp.Count;
        },
          error => { this.text.loading = false; },
        () => { this.text.loading = false; }
      );
    }, 500) ;
  }

  getEffectiveField(): string {
    return this.translateId ? 'Id' : 'Display';
  }

  filterChange(filter: string): void {
    if ( filter.length > 0 ) {
      this.text.loading = true;
      this.debounceFilter(filter); // conduct search even if filter is empty
    }
  }

  public getContactImageUrl(contactId: string): string {
    return this.auth.getUrl('avatar/' + contactId);
  }

  // ComboBox emit event on value change
  public valueChange(str: string): void {
    return;
    console.log('value change', str);
    this.onChange(this.value);
  }

  // public selectionChange(value: PeopleModel): void {
  //   this.onTouched();
  //   console.log('selectionChange', value);
  //   this.value = this.translateId ? value.Id : value.FullName;
  //   this.onChange(this.value);
  // }

  // public open(): void {
  //   this.onTouched();
  //   // console.log('open', this.text);
  // }
  //
  // public close(): void {
  //   this.onTouched();
  //   // console.log('close', this.text);
  // }
  //
  // public focus(): void {
  //   this.onTouched();
  //   // console.log('focus', this.text);
  // }
  //
  // public blur(): void {
  //   // console.log('blur', this.text);
  // }

  // Allows Angular to update the model (name or ID).
  // Update the model and changes needed for the view here.
  writeValue(nameOrId: string): void {
    if ( nameOrId === undefined ){
      console.log('who called me for write', this);
      return;
    }
    const changed = nameOrId !== this.value;
    if (this.needSearch(nameOrId) ){
      this.text.loading = true;
      console.log('searching ... ', nameOrId, this.translateId ? 'by id' : 'by name');
      this.searchUser(nameOrId, this.translateId).subscribe(
        ppl => {
          const person = new PeopleModel(
            ppl.Id,
            ppl.First,
            ppl.Last,
            ppl.Middle,
            ppl.Title,
            ppl.Display,
            ppl.Nick,
            ppl.Enabled
          );
          console.log('got search result ', person);
          this.searchResult.push(person); // make sure it's available for selection, thus proper display
          this.value = this.translateId ? person.Id : person.FullName;
          console.log('before update', this.text.value);
          this.text.value = this.value;
          console.log('after update', this.text.value);
        }, error => { console.error(error); this.text.loading = false; },
        () => {this.text.loading = false; }
      );
      if ( changed ) {
        this.onChange(nameOrId);
      }
    }
  }

  needSearch(incoming: string ): boolean {
    if ( incoming === undefined || incoming === '' || incoming === this.value ) {
      return false;
    }

    const idx = this.searchResult.findIndex( person => {
      if ( this.translateId) {
        return person.Id === incoming;
      }else{
        return person.FullName.includes(incoming);
      }
    });

    return idx === -1; // not found need search
  }

  // Search a user either based on partial name or a complete ID
  searchUser(nameOrId: string, translateId: boolean): Observable<PeopleModel>{
    if ( translateId )  {
        return this.ps.getPeopleById(nameOrId);
        // return this.searchPersonById( nameOrId) ;
    }else{
        // return this.ps.searchById(nameOrId);
        // return this.searchPersonByName(nameOrId) ;
    }
  }

  // searchPersonByName(name: string): Observable<PeopleModel>{
  //   return new Observable ( observer => {
  //     const dummy: PeopleModel = new PeopleModel(
  //       'dummy-id',
  //       'FSearch',
  //       'LResult',
  //       '',
  //       'Mr.',
  //       'Display Name',
  //       'Nick Name'
  //     );
  //     setTimeout(() => {
  //       observer.next(dummy);
  //       observer.complete();
  //     }, 1000);
  //   });
  // }
  //
  // searchPersonById( id: string): Observable<PeopleModel> {
  //   return new Observable ( observer => {
  //     const dummy: PeopleModel = new PeopleModel(
  //       id,
  //       'FSearch',
  //       'LResult',
  //       '',
  //       'Mr.',
  //       'P:' + id,
  //       'Nick Name'
  //     );
  //     setTimeout(() => {
  //       observer.next(dummy);
  //       observer.complete();
  //     }, 1000);
  //   });
  // }

  // Allows Angular to register a function to call when the model (rating) changes.
  // Save the function as a property to call later here.
  registerOnChange(fn: (nameOrId: string) => void): void {
    this.onChange = fn;
  }
  // Allows Angular to register a function to call when the input has been touched.
  // Save the function as a property to call later here.
  registerOnTouched(fn: () => void): void {
    this.onTouched = fn;
  }
  // Allows Angular to disable the input.
  setDisabledState(isDisabled: boolean): void {
    this.disabled = isDisabled;
  }

}
