package dev.fyloz.trial.colorrecipesexplorer.model.validation

import javax.validation.Constraint
import javax.validation.ConstraintValidator
import javax.validation.ConstraintValidatorContext
import javax.validation.Payload
import kotlin.reflect.KClass

private const val MIN_SIZE = Long.MIN_VALUE
private const val MAX_SIZE = Long.MAX_VALUE
private const val MESSAGE = "must be null or have a correct length"

@Target(AnnotationTarget.FIELD)
@MustBeDocumented
@Constraint(validatedBy = [NullOrSizeValidator::class])
annotation class NullOrSize(
        val min: Long = MIN_SIZE,
        val max: Long = MAX_SIZE,
        val message: String = MESSAGE,
        val groups: Array<KClass<*>> = [],
        val payload: Array<KClass<out Payload>> = []
)

class NullOrSizeValidator : ConstraintValidator<NullOrSize, Any> {
    var min = MIN_SIZE
    var max = MAX_SIZE
    var message = MESSAGE

    override fun initialize(constraintAnnotation: NullOrSize) {
        min = constraintAnnotation.min
        max = constraintAnnotation.max
        message = constraintAnnotation.message
    }

    override fun isValid(value: Any?, context: ConstraintValidatorContext): Boolean {
        if (value == null) return true
        return when (value) {
            is Number -> value.toLong() in min..max
            is String -> value.length in min..max
            is Collection<*> -> value.size in min..max
            else -> throw IllegalStateException("Cannot use @NullOrSize on type ${value::class}")
        }.apply {
            if (!this) context.buildConstraintViolationWithTemplate(message)
        }
    }
}
