import { ValidateResult, StandardValidator, Validator } from 'aurelia-validation';
import * as breeze from 'breeze-client';
import { I18N } from 'aurelia-i18n';
import { inject } from 'aurelia-framework';

@inject(I18N, StandardValidator)
export class BreezeValidator {
  constructor(private i18N: I18N, private standardValidator: StandardValidator) {
  }
  ruleExists(rules: any, rule: any): boolean {
    return this.standardValidator.ruleExists(rules, rule);
  }

  async validateObject(entity: breeze.Entity): Promise<ValidateResult[]> {
    // Avoid validation errors in the rare case we send a NULL
    if (entity == null) {
      return [];
    }
    let validations = await this.standardValidator.validateObject(entity);

    if (entity.entityAspect != null) {
      let breezeValidations: ValidateResult[] = [];

      if (!entity.entityAspect.validateEntity()) {
        var valErrors = entity.entityAspect.getValidationErrors();
        breezeValidations = valErrors
          .map(({ errorMessage, propertyName, key, validator, context, property }) => {
            return new ValidateResult(key, entity, propertyName, false, this.translatePropertyName(entity, key, errorMessage, propertyName));
          });

      }
      validations.push(...breezeValidations);
    }
    return validations;
  }

  async validateProperty(entity: breeze.Entity, propertyName) {
    // comment this block of code, even in case of a breeze property we need to satisfy rules defined with aurelia-validation 
    // if (entity.entityAspect == null) {
    //   // this is not a breeze object -> use standard validator
    //   return this.standardValidator.validateProperty(entity, propertyName);
    // }
    let validations = await this.standardValidator.validateProperty(entity, propertyName);

    if (entity.entityAspect != null) {
      let breezeValidations: ValidateResult[] = [];
      if (!entity.entityAspect.validateProperty(propertyName)) {
        breezeValidations = entity.entityAspect
          .getValidationErrors(propertyName)
          .map(({ errorMessage, propertyName, key }) => {
            return new ValidateResult(key, entity, propertyName, false, this.translatePropertyName(entity, key, errorMessage, propertyName));
          });
      }
      validations.push(...breezeValidations);
    }
    return validations;
  }

  translatePropertyName(entity: breeze.Entity, key: string, errorMessage: string, propertyName: string): string {
    let entityName = entity.entityType.shortName;
    let translation = this.getTranslateFromTrEntry(`${entityName.toLowerCase()}.${propertyName}`);
    if (translation == null) {
      translation = this.getTranslateFromTrEntry(`validator.${propertyName}`)
    }
    if (translation != null) {
      let errorKey = key.split(":")[0];
      let message = this.getTranslateFromTrEntry(`validation.${errorKey}`, true);
      if (message != null) {
        return message.replace("%displayName%", translation);
      }
    }
    return errorMessage;
  }

  getTranslateFromTrEntry(translsationKey: string, fromCommon: Boolean = false): string {
    var t = this.i18N.getLocale()
    let trProp = fromCommon ? this.i18N.tr(translsationKey, { ns: "common" }) : this.i18N.tr(translsationKey);
    if (trProp == null || trProp.length == 0 || trProp === translsationKey) return null;

    return trProp;
  }
}
