/*
 * Copyright (C) 2018 Robert Bosch GmbH Copyright (C) 2018 Robert Bosch Manufacturing Solutions GmbH, Germany. All rights reserved.
 */

import { Directive, ElementRef, forwardRef, Inject, Optional, Renderer2 } from '@angular/core';
import {
  AbstractControl,
  COMPOSITION_BUFFER_MODE,
  DefaultValueAccessor,
  NG_VALIDATORS,
  NG_VALUE_ACCESSOR,
  ValidationErrors,
  Validator,
} from '@angular/forms';

@Directive({
  // eslint-disable-next-line @angular-eslint/directive-selector
  selector: 'textarea[inputPolygonCoordinates]',
  // eslint-disable-next-line @angular-eslint/no-host-metadata-property
  host: {
    '(input)': '$any(this)._handleInput($event.target.value)',
    '(blur)': 'onTouched()',
    '(compositionstart)': '$any(this)._compositionStart()',
    '(compositionend)': '$any(this)._compositionEnd($event.target.value)',
  },
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => PolygonCoordinatesTextareaDirective),
      multi: true,
    },
    {
      provide: NG_VALIDATORS,
      useExisting: forwardRef(() => PolygonCoordinatesTextareaDirective),
      multi: true,
    },
  ],
})
export class PolygonCoordinatesTextareaDirective extends DefaultValueAccessor implements Validator {
  private error = false;
  private data: [[[number, number]]];

  constructor(
    _renderer: Renderer2,
    _elementRef: ElementRef,
    @Optional() @Inject(COMPOSITION_BUFFER_MODE) _compositionMode: boolean
  ) {
    super(_renderer, _elementRef, _compositionMode);
    this.onChange = (value) => this.deserialize(value);
  }

  /* eslint-disable-next-line @typescript-eslint/no-unused-vars */
  publicOnChange = (_: any) => { return };

  registerOnChange(fn: (_: any) => void): void {
    this.publicOnChange = fn;
  }

  /* eslint-disable-next-line @typescript-eslint/no-unused-vars */
  validate(c: AbstractControl): ValidationErrors | null {
    return !this.error
      ? null
      : {
          parse: {
            valid: false,
          },
        };
  }

  writeValue(obj: any): void {
    this.data = obj;
    const serialized = obj === null ? null : JSON.stringify(obj, null, 2);
    super.writeValue(serialized);
  }

  private deserialize(value) {
    try {
      this.data = !value ? null : JSON.parse(value);
      this.error = false;
    } catch (parseException) {
      this.error = true;
    }
    this.publicOnChange(this.data);
  }
}
