package ru.yandex.canvas.model.validation.presetbased.elements;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;

import org.checkerframework.checker.nullness.qual.NonNull;
import org.springframework.validation.Errors;

import ru.yandex.canvas.model.elements.Element;
import ru.yandex.canvas.model.elements.ElementWithMaxLength;

import static ru.yandex.direct.utils.CommonUtils.nvl;

public class TextLengthValidator extends ElementValidator<Element> {

    private static final String MIN_MAX_MESSAGE = "{javax.validation.constraints.Size.message}";
    private static final String MIN_MESSAGE = "{javax.validation.constraints.MinSize.message}";

    public static final String CHOOSE_VALUE_MESSAGE = "{choose_value}";

    @Nullable
    private Integer minLength = 1;

    @Nullable
    private Integer maxLength;

    @Nullable
    private String message;

    /**
     * Имя поля, которое будет в ошибке валидации.
     * Нужно, например, для ageRestriction, там используется value вместо content
     * @see ru.yandex.canvas.model.elements.AgeRestriction.Options
     */
    @Nonnull
    private String fieldName = "content";

    public TextLengthValidator() {
    }

    public TextLengthValidator(@Nullable Integer maxLength) {
        this.maxLength = maxLength;
    }

    public TextLengthValidator(@Nullable Integer maxLength, @Nullable String message) {
        this.maxLength = maxLength;
        this.message = message;
    }

    public TextLengthValidator(@Nullable Integer maxLength, @Nullable String message, @Nonnull String fieldName) {
        this.maxLength = maxLength;
        this.message = message;
        this.fieldName = fieldName;
    }

    public void setMinLength(int minLength) {
        this.minLength = minLength;
    }

    public void setMaxLength(int maxLength) {
        this.maxLength = maxLength;
    }

    public void setMessage(@Nonnull String message) {
        this.message = message;
    }

    public void setFieldName(@Nonnull String fieldName) {
        this.fieldName = fieldName;
    }

    @Override
    public boolean isSupported(Element element) {
        return element != null && element.getAvailable() &&
                (element.getOptions() instanceof Element.ColoredTextOptions || element instanceof ElementWithMaxLength);
    }

    @Override
    public void validate(Element element, @NonNull Errors errors) {
        Integer maxLength = this.maxLength;

        if (maxLength == null && element instanceof ElementWithMaxLength) {
            maxLength = ((ElementWithMaxLength) element).getMaxLength();
        }

        Element.ColoredTextOptions options = (Element.ColoredTextOptions) element.getOptions();
        int length = nvl(options.getContent(), "").length();

        if (maxLength != null) {
            if (length > maxLength || (minLength != null && length < minLength)) {
                errors.rejectValue("options." + fieldName, "size.exceeded", new String[]{
                        "min", String.valueOf(minLength),
                        "max", String.valueOf(maxLength)
                }, nvl(message, MIN_MAX_MESSAGE));
            }
        } else if (minLength != null) {
            if (length < minLength) {
                errors.rejectValue("options." + fieldName, "size.lack", new String[]{
                        "min", String.valueOf(minLength)
                }, nvl(message, MIN_MESSAGE));
            }
        }
    }
}
