using Exam.Infrastructure.Extensions;
using Exam.Infrastructure.Validation.Enums;
using Exam.Infrastructure.Validation.Validation;
using System.Linq.Expressions;

namespace Exam.Infrastructure.Validation.Exceptions
{
    /// <summary>
    /// 业务逻辑异常
    /// </summary>
    [Serializable]
    public class DomainException : Exception
    {
        /// <summary>
        /// 异常对应领域实体属性名称(可为null)
        /// </summary>
        protected string EffectPropertyName
        {
            get;
            set;
        }

        public IValidationErrors ValidationErrors { get; private set; }

        public DomainException()
        {
            ValidationErrors = new ValidationErrors();
        }

        protected DomainException(string message) : base(message)
        {
            ValidationErrors = new ValidationErrors();
        }

        public DomainException(IValidationErrors validationErrors, ValidationErrorType errorType = ValidationErrorType.Body)
        {
            ValidationErrors = validationErrors;
            foreach (var validationError in ValidationErrors.ErrorItems)
            {
                validationError.ErrorType = errorType.GetDescription();
            }
        }

        public void AddErrors(IValidationErrors validationErrors)
        {
            ValidationErrors.AddErrors(validationErrors.ErrorItems);
        }

        public IValidationErrors AddError<TObject, TProperty>(Expression<Func<TObject, TProperty>> expression, object attemptedValue, string errorMessage, bool customState = false)
        {
            var memberExpression = expression.Body as MemberExpression;
            if (memberExpression != null)
                return ValidationErrors.AddError(memberExpression.Member.Name, errorMessage, attemptedValue, customState);
            return new ValidationErrors();
        }

        public IValidationErrors AddError(string propertyName, string errorMessage, string errorCode, string errorDescription, object attemptedValue)
        {
            return ValidationErrors.AddDomainError(propertyName, errorMessage, errorCode, errorDescription, attemptedValue);
        }

        public static TException Create<TException>(IValidationErrors errors) where TException : DomainException, new()
        {
            var exception = new TException();
            if (errors != null)
            {
                exception.ValidationErrors = errors;
            }

            return exception;
        }
    }
}
