/* eslint-disable @angular-eslint/directive-selector, @angular-eslint/no-host-metadata-property */

import { Directive, ElementRef, HostListener } from "@angular/core";
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from "@angular/forms";

@Directive({})
export class ValueAccessor implements ControlValueAccessor {
  private onChange: (value: any) => void = () => {};
  private onTouched: () => void = () => {};
  protected lastValue: any;

  constructor(protected el: ElementRef) {}

  writeValue(value: any) {
    this.el.nativeElement.value = this.lastValue = value == null ? '' : value;
  }

  handleChangeEvent(value: any) {
    if (value !== this.lastValue) {
      this.lastValue = value;
      this.onChange(value);
    }
  }

  @HostListener('focusout')
  _handleBlurEvent() {
    this.onTouched();
  }

  registerOnChange(fn: (value: any) => void) {
    this.onChange = fn;
  }
  registerOnTouched(fn: () => void) {
    this.onTouched = fn;
  }

  setDisabledState(disabled: boolean) {
    this.el.nativeElement.disabled = disabled;
  }
}

@Directive({
  selector: 'duet-input:not([type=number]), duet-textarea, duet-date-picker',
  host: {
    '(duetChange)': 'handleChangeEvent($event.target.value)'
  },
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: TextValueAccessorDirective,
      multi: true
    }
  ]
})
export class TextValueAccessorDirective extends ValueAccessor {
  constructor(el: ElementRef) {
    super(el);
  }
}

@Directive({
  /* tslint:disable-next-line:directive-selector */
  selector: 'duet-range-slider, duet-select, duet-radio-group, duet-choice-group',
  host: {
    '(duetChange)': 'handleChangeEvent($event.target.value)'
  },
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: SelectValueAccessorDirective,
      multi: true
    }
  ]
})
export class SelectValueAccessorDirective extends ValueAccessor {
  constructor(el: ElementRef) {
    super(el);
  }
}

@Directive({
  /* tslint:disable-next-line:directive-selector */
  selector: 'duet-radio, duet-choice[type=radio]',
  host: {
    '(duetSelect)': 'handleChangeEvent($event.target.checked)'
  },
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: RadioValueAccessorDirective,
      multi: true
    }
  ]
})
export class RadioValueAccessorDirective extends ValueAccessor {
  constructor(el: ElementRef) {
    super(el);
  }
}

@Directive({
  /* tslint:disable-next-line:directive-selector */
  selector: 'duet-input[type=number], duet-number-input',
  host: {
    '(duetChange)': 'handleChangeEvent($event.target.value)'
  },
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: NumericValueAccessorDirective,
      multi: true
    }
  ]
})
export class NumericValueAccessorDirective extends ValueAccessor {
  constructor(el: ElementRef) {
    super(el);
  }
  registerOnChange(fn: (_: number | null) => void) {
    super.registerOnChange(value => {
      fn(value === '' ? null : parseFloat(value));
    });
  }
}

@Directive({
  /* tslint:disable-next-line:directive-selector */
  selector: 'duet-checkbox, duet-toggle, duet-choice[type=checkbox]',
  host: {
    '(duetChange)': 'handleChangeEvent($event.target.checked)'
  },
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: BooleanValueAccessorDirective,
      multi: true
    }
  ]
})
export class BooleanValueAccessorDirective extends ValueAccessor {
  constructor(el: ElementRef) {
    super(el);
  }
  writeValue(value: any) {
    this.el.nativeElement.checked = this.lastValue = value == null ? false : value;
  }
}