import { Directive, forwardRef, OnChanges, SimpleChanges, Input, ElementRef, ChangeDetectorRef, HostListener, Output, EventEmitter } from '@angular/core';
import { NG_VALIDATORS, Validator, AbstractControl, ValidationErrors } from '@angular/forms';
import { MaskDirective } from '../mask-directive/mask.directive';
import { NbDynamicOverlayHandler, NbDynamicOverlay, NbPosition, NbTrigger, NbAdjustment } from '@nebular/theme';
import { PopoverMsgComponent } from '../rbj-tooltip/popover-msg/popover-msg.component';

@Directive({
  selector: 'input[regexValidator], textarea[regexValidator]',
  providers: [
    {
      provide: NG_VALIDATORS,
      useExisting: forwardRef(() => RegexValidatorDirective),
      multi: true,
    },
    NbDynamicOverlayHandler,
    NbDynamicOverlay
  ],
})
export class RegexValidatorDirective implements OnChanges, Validator {

  private dynamicOverlay: NbDynamicOverlay;
  @Input('regexValidator') public regexExpression: string = '';
  @Input('invalidMsg') public invalidMsg: string = 'Invalid format';


  private _invalid: boolean = false;
  public get invalid(): boolean {
    return this._invalid;
  }
  @Input() public set invalid(v: boolean) {
    if (this._invalid != v) {
      this._invalid = v;
      this.invalidChange.emit(v);
    }
  }
  @Output() invalidChange = new EventEmitter<boolean>()


  private _required: boolean = false;
  public get required(): boolean {
    return this._required;
  }
  public set required(v: boolean) {
    this._required = typeof v !== 'undefined' && v !== false;

  }

  constructor(
    private elementRef: ElementRef,
    private dynamicOverlayHandler: NbDynamicOverlayHandler,
    private cdRef: ChangeDetectorRef) { }


  public get inputText(): string {
    return this.elementRef.nativeElement.value;
  }

  ngOnChanges(changes: SimpleChanges): void {

    this.dynamicOverlay = this.configureDynamicOverlay().rebuild();
  }

  validate(control: AbstractControl): ValidationErrors {

    if (this.inputText && this.inputText.length > 0 &&
      !this.inputText.match(new RegExp(this.regexExpression, 'g'))) {
      this.invalid = true;
      this.show();
      return this.createValidationError(this.inputText)
    }

    this.invalid = false;
    this.hide();
    return null;
  }
  registerOnValidatorChange?(fn: () => void): void {

  }

  ngOnInit() {
    this.dynamicOverlayHandler
      .host(this.elementRef)
      .componentType(PopoverMsgComponent);

  }

  ngAfterViewInit() {
    this.dynamicOverlay = this.configureDynamicOverlay().build();
  }

  ngOnDestroy() {
    this.dynamicOverlayHandler.destroy();
  }

  @HostListener('focusout')
  onFocusOut() {
    if (this.invalid) {
      setTimeout(() => {
        this.elementRef.nativeElement.focus();
      }, 200);
    }
  }

  show() {
    if (this.dynamicOverlay) {
      this.dynamicOverlay.show();
      this.cdRef.detectChanges();
    }
  }

  hide() {
    if (this.dynamicOverlay) {
      this.dynamicOverlay.hide();
      this.cdRef.detectChanges();
    }
  }

  protected configureDynamicOverlay() {
    return this.dynamicOverlayHandler
      .position(NbPosition.BOTTOM_END)
      .trigger(NbTrigger.NOOP)
      .adjustment(NbAdjustment.CLOCKWISE)
      .offset(0)
      //.content(this.msgContext)
      .context({
        message: this.invalidMsg
      });
  }
  private createValidationError(actualValue: string): ValidationErrors {
    return {
      mask: {
        requiredRegex: this.regexExpression,
        actualValue,
      },
    };
  }
}
