import { Directive, HostListener, Input, OnDestroy, OnInit } from '@angular/core';
import { AbstractControl, AbstractControlDirective, NgControl } from '@angular/forms';

import { Observable } from 'rxjs/Observable';
import { Subscription } from 'rxjs/Subscription';

import { ConfigService } from './../services/config.service';
import { MsgsService } from './../services/msgs.service';
import { TranslateService } from './../services/translate.service';
import { UtilsService } from './../services/utils.service';


@Directive({
    selector: '[ngModel]:not([skipValidate])'
})

// This will be assigned to ALL fields except fields with "skipValidate" attribute
// By Default errors will be displayed only when form is submitted
// You can change this behavior using "showErrorAfterTouched" flag - which will show error once field is touched. Dont forget to update style.css in that case
// Also you can change Observable to identify when this error should be displayed, just pass "showError" Observable in that input field
export class ValidationErrorMessageDirective implements OnInit, OnDestroy {

    @Input() fieldLabel: string;
    control: AbstractControl | AbstractControlDirective;
    show: boolean = false;
    subscriptions: Array<Subscription> = [];
    @Input() showError: Observable<boolean>;

    //Below attributes are related to translation API i.e when you want to fetch error message from server
    @Input() fieldName: string;
    @Input() subType: string;
    @Input() modes: string[];
    @Input() errorFromServer: boolean;  //Set this flag to 'true' - when overall application setting says DON'T fetch from server and you still need it
    @Input() tokenReplacements: any;

    constructor(
        private ngControl: NgControl,
        private utilsService: UtilsService,
        private msgsService: MsgsService,
        private configService: ConfigService,
        private translateService: TranslateService) {

    }

    ngOnInit() {
        this.control = this.ngControl.control;

        if (!this.fieldLabel) {
            this.fieldLabel = this.ngControl.name;
        }

        if (!this.showError) {
            this.showError = this.msgsService.showAllErrors; //By Default we will use global showError
        }

        this.subscriptions.push(
            this.showError.subscribe((data) => {
                this.show = data;
                this.showErrors();
            })
        );
    }

    ngOnDestroy() {
        this.msgsService.clearFrontEndErrors(this.ngControl.name);
        this.utilsService.unsubscribeSubscriptions(this.subscriptions);
    }

    @HostListener('blur')
    private onBlur() {
        if (this.configService.settings.showErrorAfterTouched) {
            this.showErrors();
        }
    }

    showErrors() {
        if ((this.configService.settings.showErrorAfterTouched && this.control.touched) || this.show) {
            if (this.ngControl.invalid) {
                this.msgsService.addFrontEndError(this.ngControl.name, this.getErrorMessage());
                return;
            }
        }
        this.msgsService.clearFrontEndErrors(this.ngControl.name);
    }

    getErrorMessage(): string[] {
        let fieldValidationMsgsSet = new Set();

        Object.keys(this.ngControl.errors).forEach(key => {
            var msg;
            if (this.errorFromServer || this.configService.settings.fetchErrorMsgsFromServer) { //If either app settings or field settings is true, it will fetch from server
                msg = this.translateService.translateErrorMsg(this.fieldName, key, this.tokenReplacements, this.modes);
            }
            else {
                msg = this.utilsService.getValidationMessage(key, this.fieldLabel, this.ngControl.errors[key]);
            }
            fieldValidationMsgsSet.add(msg);
        });
        return Array.from(fieldValidationMsgsSet);
    }

    // getControlName(c: AbstractControl): string | null {
    //     const formGroup = c.parent.controls;
    //     return Object.keys(formGroup).find(name => c === formGroup[name]) || null;
    // }
}
