namespace System.ComponentModel.DataAnnotations;

[AttributeUsage(
 AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter,
 AllowMultiple = false)]
public class GuidNotEmptyAttribute : ValidationAttribute
{
    public const string DefaultErrorMessage = "The {0} field must not be empty";
    public GuidNotEmptyAttribute() : base(DefaultErrorMessage) { }

    public override bool IsValid(object value)
    {
        //NotEmpty doesn't necessarily mean required
        if (value is null)
        {
            return true;
        }

        switch (value)
        {
            case Guid guid:
                return guid != Guid.Empty;
            default:
                return true;
        }
    }
}

public class NotDefaultAttribute : ValidationAttribute
{
    public const string DefaultErrorMessage = "The {0} field is is not passed or not set a valid value";
    public NotDefaultAttribute() : base(DefaultErrorMessage) { }

    public override bool IsValid(object value)
    {
        //NotDefault doesn't necessarily mean required
        if (value is null)
        {
            return true;
        }

        var type = value.GetType();
        if (type.IsValueType)
        {
            var defaultValue = Activator.CreateInstance(type);
            return !value.Equals(defaultValue);
        }

        // non-null ref type
        return true;
    }
}
public class CanConvertToTimeAttribute : ValidationAttribute
{
    public const string DefaultErrorMessage = "The {0} field is is  not  a valid  DateTime value";
    public CanConvertToTimeAttribute() : base(DefaultErrorMessage) { }

    public override bool IsValid(object value)
    {
        if (value is null)
        {
            return false;
        }

        if (DateTime.TryParse(value.ToString(), out _) == true)
        {
            return true;
        }
        else
        {
            return false;
        }
    }
}

[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public class DecimalPrecisionAttribute : Attribute
{
    public int Precision { get; }
    public int Scale { get; }

    public DecimalPrecisionAttribute(int precision, int scale)
    {
        Precision = precision;
        Scale = scale;
    }
}