﻿using CarDiaryX.Application.Common.Constants;
using CarDiaryX.Domain.VehicleServices;
using FluentValidation;
using System;
using System.Linq;
using System.Threading.Tasks;

namespace CarDiaryX.Application.Features.V1.VehicleServices.Commands
{
    public class UpdateReviewCommandValidator : AbstractValidator<UpdateReviewCommand>
    {
        public UpdateReviewCommandValidator()
        {
            this.RuleFor(x => x.ReviewId)
                .GreaterThan(ApplicationConstants.ZERO_NUMBER)
                .WithMessage(ApplicationConstants.VehicleServices.UNEXISTING_REVIEW);

            this.RuleFor(x => x.Review)
                .NotNull()
                .WithMessage(ApplicationConstants.VehicleServices.INVALID_REVIEW_NULL);

            this.WhenAsync((x, t) => Task.FromResult(x.Review is not null), () =>
            {
                this.RuleFor(u => u.Review.Name)
                    .NotEmpty()
                    .WithMessage(ApplicationConstants.VehicleServices.INVALID_NAME_REVIEW_EMPTY)
                    .MinimumLength(ApplicationConstants.VehicleServices.NAME_MIN_LENGTH)
                    .WithMessage(ApplicationConstants.VehicleServices.INVALID_NAME_REVIEW)
                    .MaximumLength(ApplicationConstants.VehicleServices.NAME_REVIEW_MAX_LENGTH)
                    .WithMessage(ApplicationConstants.VehicleServices.INVALID_NAME_REVIEW);

                this.RuleFor(u => u.Review.Prices)
                    .MustAsync((u, t) => this.ValidatePricesEnum(u))
                    .WithMessage(string.Format(ApplicationConstants.VehicleServices.INVALID_REVIEW_PRICES, this.GetValidPricesEnumList()));

                this.RuleFor(u => u.Review.Ratings)
                    .MustAsync((u, t) => this.ValidateRatingsEnum(u))
                    .WithMessage(string.Format(ApplicationConstants.VehicleServices.INVALID_REVIEW_RATINGS, this.GetValidRatingsEnumList()));
            });
        }

        private string GetValidPricesEnumList()
            => string.Join(",", Enum.GetValues(typeof(Prices)).Cast<int>());

        private string GetValidRatingsEnumList()
            => string.Join(",", Enum.GetValues(typeof(Ratings)).Cast<int>());

        private Task<bool> ValidatePricesEnum(int prices)
        {
            var isDefinedEnum = Enum.IsDefined(typeof(Prices), prices);

            if (!isDefinedEnum)
            {
                return Task.FromResult(false);
            }

            return Task.FromResult(true);
        }

        private Task<bool> ValidateRatingsEnum(int ratings)
        {
            var isDefinedEnum = Enum.IsDefined(typeof(Ratings), ratings);

            if (!isDefinedEnum)
            {
                return Task.FromResult(false);
            }

            return Task.FromResult(true);
        }
    }
}
