using Exam.Infrastructure.Validation.Enums;
using Exam.Infrastructure.Validation.Exceptions;
using Exam.Infrastructure.Validation.Validation;
using FluentValidation;
using FluentValidation.Results;

namespace Exam.Infrastructure.Validation.Extensions
{
    public static class ValidateResultExtensions
    {
        public static IValidationErrors ToValidationError(this ValidationResult validationResult)
        {
            var validationError = new ValidationErrors();

            foreach (var failure in validationResult.Errors)
            {
                validationError.AddError(failure.PropertyName, failure.AttemptedValue, failure.ErrorMessage, false);
            }

            return validationError;
        }

        public static IValidationErrors DoValidate<T>(this IValidator<T> validator, T instance, string ruleSet = null)
        {
            var validationResult = validator.Validate(instance, v => {
                v.IncludeRuleSets(ruleSet);
            });

            var validationError = new ValidationErrors();

            foreach (var failure in validationResult.Errors)
            {
                validationError.AddError(failure.PropertyName, failure.AttemptedValue, failure.ErrorMessage, false);
            }

            return validationError;
        }

        public static async Task<IValidationErrors> DoValidateAsync<T>(this IValidator<T> validator, T instance, string ruleSet = null, object validateKey = null)
        {
            var validationResult = await validator.ValidateAsync(instance, v => {
                v.IncludeRuleSets(ruleSet);
            });

            var validationError = new ValidationErrors();
            validateKey = validateKey ?? string.Empty;

            var errors = validationResult.Errors.GroupBy(x => new
            {
                propertyName = x.PropertyName,
                ErrorMessage = x.ErrorMessage
            }).Select(m => m.FirstOrDefault());

            foreach (var failure in errors)
            {
                validationError.AddError(failure.PropertyName, failure.AttemptedValue, failure.ErrorMessage, false, validateKey.ToString());
            }

            return validationError;
        }

        public static async Task ToValidateResult<T>(this IValidator<T> validator, T instance, string ruleSet = null, object validateKey = null)
        {

            var validate = await validator.DoValidateAsync(instance, ruleSet, validateKey);

            if (!validate.IsValid)
            {
                throw new DomainException(validate,ValidationErrorType.Body);
            }
        }
    }
}
