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.contracts.ExperimentalContracts
import kotlin.contracts.contract
import kotlin.reflect.KClass

private const val MESSAGE = "must be null or not blank"

@Target(AnnotationTarget.FIELD)
@MustBeDocumented
@Constraint(validatedBy = [NullOrNotBlankValidator::class])
annotation class NullOrNotBlank(
    val message: String = MESSAGE,
    val groups: Array<KClass<*>> = [],
    val payload: Array<KClass<out Payload>> = []
)

class NullOrNotBlankValidator : ConstraintValidator<NullOrNotBlank, String> {
    var message = MESSAGE

    override fun initialize(constraintAnnotation: NullOrNotBlank) {
        message = constraintAnnotation.message
    }

    override fun isValid(value: String?, context: ConstraintValidatorContext): Boolean {
        return value.isNullOrNotBlank().apply {
            if (!this) context.buildConstraintViolationWithTemplate(message)
        }
    }
}

fun String?.isNullOrNotBlank(): Boolean = this == null || isNotBlank()

/** Checks if the given string [value] is not null and not blank. */
@ExperimentalContracts
fun isNotNullAndNotBlank(value: String?): Boolean {
    contract { returns(true) implies (value != null) }
    return value != null && value.isNotBlank()
}

@ExperimentalContracts
fun String?.or(alternative: String): String = if (isNotNullAndNotBlank(this)) this else alternative
