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 { SelectOption } from './select-option.model';

/**
 * A select component.
 *
 * ## Usage
 * ``import {UiSelectModule} from '@ui/select/select.module';``
 */
@Component({
  selector: 'ui-select',
  templateUrl: './select.component.html',
  styleUrls: ['./select.component.scss'],
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: SelectComponent,
      multi: true,
    },
  ],
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class SelectComponent implements ControlValueAccessor, AfterViewInit, OnChanges {
  @Input() uiInvalid: boolean;
  @Input() uiValidationMessage: string;
  @Input() uiPlaceholder: string;
  @Input() uiOptions: SelectOption[];
  @Input() uiRequired: boolean;
  @Input() uiLabel: string;
  @Input() uiDescription: string;
  @Input() uiAnnounceIfOptional: boolean;
  @Input() uiId: string = uuid();
  @Input() uiName: string;
  @Output() uiOnChange = new EventEmitter<any>();

  name: string | number;
  onTouched: () => {};
  private onChange: (value: any) => {};
  private _value: any;

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

  get currentValue(): any {
    return this._value;
  }

  private get _requiredText() {
    if (this.uiRequired && !this.uiAnnounceIfOptional) {
      return ' (obligatoriskt)';
    }

    if (!this.uiRequired && this.uiAnnounceIfOptional) {
      return ' (frivilligt)';
    }

    return '';
  }

  getLabelText(label: string): string {
    return `${label}${this._requiredText}`;
  }

  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(value: any): void {
    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: any) => {}) {
    this.onChange = fn;
  }

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