import {distinctUntilChanged, debounceTime, takeUntil} from 'rxjs/operators';
import { Directive, Input, Output, EventEmitter, OnDestroy, OnInit } from '@angular/core';
import { NgControl } from '@angular/forms';

import { Subject } from 'rxjs';

@Directive({
  selector: '[ngModel][dsDebounce]',
})
/**
 * Directive for setting a debounce time on an input field
 * It will emit the input field's value when no changes were made to this value in a given debounce time
 */
export class DebounceDirective implements OnInit, OnDestroy {

  /**
   * Emits a value when nothing has changed in dsDebounce milliseconds
   */
  @Output()
  public onDebounce = new EventEmitter<any>();

  /**
   * The debounce time in milliseconds
   */
  @Input()
  public dsDebounce = 500;

  /**
   * Subject to unsubscribe from
   */
  private subject: Subject<void> = new Subject<void>();

  constructor(public model: NgControl) {
  }

  /**
   * Start listening to changes of the input field's value changes
   * Emit it when the debounceTime is over without new changes
   */
  ngOnInit() {
    this.model.valueChanges.pipe(
      takeUntil(this.subject),
      debounceTime(this.dsDebounce),
      distinctUntilChanged())
      .subscribe((modelValue) => {
        if (this.model.dirty) {
          this.onDebounce.emit(modelValue);
        }
      });
  }

  /**
   * Close subject
   */
  ngOnDestroy() {
    this.subject.next();
    this.subject.complete();
  }
}