using FluentValidation;
using IWS5.Core.Enums;
using IWS5.Core.Models.Request;
using IWS5.DatabaseAccess.Interfaces;

namespace IWS5.Services.Validators;
public class UpdateFieldValueRequestValidator : AbstractValidator<UpdateFolderFieldValueRequest>
{
    public UpdateFieldValueRequestValidator(IFieldDefinitionRepository fieldDefinitionRepository)
    {
        RuleFor(x => x.FieldInstanceId).Must((request, fieldInstanceId) => {
            if (fieldInstanceId != null) {
                return true;
            } else
            {
                return fieldDefinitionRepository.AnyAsync(fd => fd.FieldId == request.FieldId).Result;
            }
        }).WithMessage(request => $"Field ID {request.FieldId} must match a valid field definition when field instance ID is null.");

        RuleFor(x => x.InstanceType).NotNull().WithMessage("Instance type is required.");

        RuleFor(x => x.InstanceType)
            .IsInEnum().WithMessage("Invalid instance type.");

        RuleFor(x => x.NewValue).Must((request, newValue) =>
        {
            switch (request.InstanceType)
            {
                case FieldInstanceType.Date:
                    return DateTime.TryParse(newValue, out _);
                case FieldInstanceType.Number:
                    var isParsable = decimal.TryParse(newValue, out decimal number);
                    if (!isParsable)
                        return false;
                    
                    decimal absValue = Math.Abs(number);
                    int digitsBeforeDecimal = absValue >= 1 ? (int)Math.Floor(Math.Log10((double)absValue)) + 1 : 1;
                    int decimalPlaces = BitConverter.GetBytes(decimal.GetBits(number)[3])[2];
                    int totalDigits = digitsBeforeDecimal + decimalPlaces;
                    return totalDigits <= 28 && decimalPlaces <= 14;
                case FieldInstanceType.String:
                    return true;
                case FieldInstanceType.Option:
                    return true;
                default:
                    return false;
            }

        }).WithMessage(request =>
            $"New value {request.NewValue} does not match the instance type {request.InstanceType.ToString()}.");

        RuleFor(x => x.NewValue).Must((request, newValue) =>
        {
            switch (request.InstanceType)
            {
                case FieldInstanceType.Option:
                    return fieldDefinitionRepository.ListFieldOptionsByFieldIdAsync(request.FieldId).Result.Contains(newValue);
                default:
                    return true;
            }
        }).WithMessage(request => 
            $"New value {request.NewValue} is not a valid option based on the field definition's evaluated SQL query.");
    }
}
