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

namespace IWS5.Services.Validators;

public class CreateFolderFieldValueRequestValidator : AbstractValidator<CreateFolderFieldValueRequest>
{
    public CreateFolderFieldValueRequestValidator(IFieldDefinitionRepository fieldDefinitionRepository)
    {
        RuleFor(x => x.FolderFieldId).GreaterThan(0).WithMessage("FolderFieldId should be greater than 0.");
        
        RuleFor(x => x.FolderFieldName).NotNull().NotEmpty().WithMessage("FolderFieldName should not be null or empty.");
        
        RuleFor(x => x.FolderFieldType).IsInEnum().WithMessage("FolderFieldType value should be in scope of enum FieldInstanceType.");
        
        RuleFor(x => x.FolderFieldValue)
            .MaximumLength(255)
            .When(x => x.FolderFieldType == FieldInstanceType.String)
            .WithMessage("FolderFieldValue must not exceed 255 characters for String type.");
        
        RuleFor(x => x.FolderFieldValue)
            .Must((request, folderFieldValue) => IsParsableToType(folderFieldValue, request.FolderFieldType))
            .WithMessage("FolderFieldValue should be parsable to the type mentioned in FolderFieldType.");

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

    private bool IsParsableToType(string value, FieldInstanceType type)
    {
        switch (type)
        {
            case FieldInstanceType.Number:
                return decimal.TryParse(value, System.Globalization.NumberStyles.Number, System.Globalization.CultureInfo.InvariantCulture, out decimal result) 
                       && result >= -9999999999999999999999999.99999999999999m 
                       && result <= 9999999999999999999999999.99999999999999m;
            case FieldInstanceType.Date:
                return DateTime.TryParse(value, out _);
            case FieldInstanceType.String:
                return true;
            case FieldInstanceType.Option:
                return true;
            default:
                return false;
        }
    }
}