package ru.yandex.direct.api.v5.validation;

import java.util.Objects;

import javax.annotation.Nullable;
import javax.annotation.ParametersAreNonnullByDefault;

import ru.yandex.direct.i18n.Translatable;
import ru.yandex.direct.validation.result.Path;

import static ru.yandex.direct.validation.result.PathHelper.path;

@ParametersAreNonnullByDefault
public class DefectType {

    private final int code;
    private final MessageProvider shortMessageProvider;
    private final MessageProvider detailedMessageProvider;

    public DefectType(int code, Translatable message) {
        this(code, message, (p, v) -> null);
    }

    public DefectType(int code, Translatable shortMessage, Translatable detailedMessage) {
        this(code, (p, v) -> shortMessage, (p, v) -> detailedMessage);
    }

    public DefectType(int code, Translatable shortMessage, MessageProvider detailedMessageProvider) {
        this(code, (p, v) -> shortMessage, detailedMessageProvider);
    }

    public DefectType(int code, MessageProvider shortMessageProvider, MessageProvider detailedMessageProvider) {
        this.code = code;
        this.shortMessageProvider = shortMessageProvider;
        this.detailedMessageProvider = detailedMessageProvider;
    }

    public int getCode() {
        return code;
    }

    MessageProvider getShortMessageProvider() {
        return shortMessageProvider;
    }

    MessageProvider getDetailedMessageProvider() {
        return detailedMessageProvider;
    }

    public DefectType withDetailedMessage(@Nullable Translatable detailedMessage) {
        return new DefectType(code, shortMessageProvider, (p, v) -> detailedMessage);
    }

    public DefectType withDetailedMessage(MessageProvider detailedMessageProvider) {
        return new DefectType(code, shortMessageProvider, detailedMessageProvider);
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }

        DefectType that = (DefectType) o;

        if (code != that.code) {
            return false;
        }
        if (!shortMessageProvider.getTranslatable(path(), "")
                .equals(that.shortMessageProvider.getTranslatable(path(), ""))) {
            return false;
        }

        return Objects.equals(
                detailedMessageProvider.getTranslatable(path(), ""),
                that.detailedMessageProvider.getTranslatable(path(), "")
        );

    }

    @Override
    public int hashCode() {
        int result = code;
        result = 31 * result + shortMessageProvider.hashCode();
        result = 31 * result + detailedMessageProvider.hashCode();
        return result;
    }

    @Override
    public String toString() {
        return "DefectType{" +
                "code=" + code +
                ", shortMessageProvider=" + shortMessageProvider.getTranslatable(path(), "") +
                ", detailedMessageProvider=" + detailedMessageProvider.getTranslatable(path(), "") +
                '}';
    }

    @FunctionalInterface
    public interface MessageProvider {
        Translatable getTranslatable(Path path, Object value);
    }
}
