import {
  AfterViewInit,
  ChangeDetectionStrategy,
  ChangeDetectorRef,
  Component,
  EventEmitter,
  Injector,
  Input,
  OnChanges,
  Output,
} from '@angular/core';
import { ControlValueAccessor, NgControl, NG_VALUE_ACCESSOR } from '@angular/forms';
import { uuid } from '@utils/uuid.util';
import { UiInputType } from './input-type.enum';
import { UiInputVariation } from './input-variation.enum';

/**
 * A input input. Implemented with control value accessor
 *
 * ## Usage
 * ``import {UiInputModule} from '@ui/input/input.module';``
 */
@Component({
  selector: 'ui-input',
  templateUrl: './input.component.html',
  styleUrls: ['./input.component.scss'],
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: InputComponent,
      multi: true,
    },
  ],
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class InputComponent implements AfterViewInit, ControlValueAccessor, OnChanges {
  @Input() uiId: string = uuid();
  @Input() uiName: string;
  @Input() uiLabel: string = '';
  @Input() uiDescription: string;
  @Input() uiVariation: UiInputVariation = UiInputVariation.M;
  @Input() uiRequired: boolean;
  @Input() uiAnnounceIfOptional: boolean = false;
  @Input() uiMin: number;
  @Input() uiMax: number;
  @Input() uiType: UiInputType = UiInputType.TEXT;
  @Input() uiInvalid: boolean;
  @Input() uiValidationMessage: string;
  @Output() uiOnChange: EventEmitter<any> = new EventEmitter();

  name: string | number;

  onTouched: () => {};
  private onChange: (value: any) => {};
  private _value: any;

  constructor(private injector: Injector, private changeDetectorRef: ChangeDetectorRef) {}

  get currentValue(): string {
    return this._value || '';
  }

  ngAfterViewInit(): void {
    const ngControl: NgControl = this.injector.get(NgControl, null);
    if (ngControl) {
      this.name = this.uiName || ngControl.name;
    }
  }

  ngOnChanges(): void {
    const ngControl: NgControl = this.injector.get(NgControl, null);
    if (ngControl) {
      this.name = this.uiName || ngControl.name;
    }
  }

  checkForChange(rawValue: string): void {
    const value = this.uiType === UiInputType.NUMBER ? +rawValue : rawValue;
    if (this._value !== value) {
      if (this.onChange) {
        this.onChange(value);
      }
      this._value = value;
      this.uiOnChange.emit(value);
    }
  }

  writeValue(value: any): void {
    this._value = value;
    this.changeDetectorRef.detectChanges();
  }

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

  registerOnTouched(fn: () => {}) {
    this.onTouched = fn;
  }
}
