package ru.yandex.webmaster3.core.semantic.review_business.biz.model;

import com.google.common.base.Strings;
import org.json.JSONException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ru.yandex.webmaster3.core.semantic.review_business.ModelUtils;
import ru.yandex.webmaster3.core.semantic.review_business.biz.model.impl.json.Moderation2JsonConversions;

import java.util.Date;

/**
 * This class contains all info about review moderation.
 * <p/>
 * Getters of this class are used to count hashCode, so to keep contract (see first point in {@link Object#hashCode()})
 * they should return objects which have same hashCode value during application run time
 * In general - implementation should be immutable and return references which are also immutable
 * <p/>
 *
 * @author Dima Schitinin <dimas@yandex-team.ru>
 */
public abstract class Moderation2 {

    private static final Logger log = LoggerFactory.getLogger(Moderation2.class);

    /**
     * Moderation status of review
     */
    public enum Status {
        /**
         * New review. Indicates no moderation actions.
         */
        NEW,
        /**
         * Indicates review under moderation.
         * For example, sent to QAS or under administrator investigation.
         */
        IN_PROGRESS,
        /**
         * Review satisfies to all conditions and can be shown for external users.
         */
        ACCEPTED,
        /**
         * Review doesn't satisfy to conditions and must not be shown for external users.
         */
        DECLINED;

        public static Status safeValueOf(final String name) {
            if (Strings.isNullOrEmpty(name))
                return null;
            try {
                return valueOf(name);
            } catch (IllegalArgumentException e) {
                log.error("Unknown status: " + name);
                return null;
            }
        }
    }

    /**
     * Describes why review has been declined.
     */
    public enum RejReason {
        UPPERCASE("Ваш текст набран заглавными буквами. Пожалуйста, смените их на обычные. Так ваш отзыв будет удобнее читать."),
        TRANSLIT("Ваш текст набран транслитом. Пожалуйста, отредактируйте его, сменив раскладку клавиатуры."),
        SPURIOUS("Ваш отзыв содержит мало информации. Пожалуйста, напишите про ваш опыт общения с этой организацией чуть более подробно."),
        COMPETITOR("В отзыве упомянута конкурирующая организация. Пожалуйста, напишите об этой организации на ее странице отзывов."),
        RUDE("Пожалуйста, смягчите формулировки."),
        PERSONAL("Пожалуйста, не упоминайте в отзыве персональные данные человека."),
        DISCUSSION("К сожалению, эта страница не предназначена для общения между пользователями. Пожалуйста, ограничьтесь здесь рассказом об организации."),
        FRAGMENTARY("Пожалуйста, более подробно опишите ситуацию, чтобы она была понятна другим пользователям."),
        LINKS("Пожалуйста, исключите из текста ссылки, которые не относятся к отзыву."),
        WRONG_ORGANIZATION("Ваш отзыв содержит много информации о другой организации. Пожалуйста, перенесите его на страницу соответствующей организации."),
        ORG_REJECTED("Организация, о которой вы написали, сочла ваш отзыв ошибочным. Если вы уверены, что адресовали отзыв верно, пожалуйста, обратитесь в поддержку."),
        SIGNAL("Спасибо за ваше сообщение о некорректности данных об организации. В ближайшее время мы постараемся решить эту проблему."),
        OTHERS("Пожалуйста, отредактируйте свой отзыв, сделайте его более грамотным и понятным, и мы с удовольствием его разместим."),
        WRONG_LANGUAGE("Пожалуйста, напишите отзыв на русском языке."),
        SPAM("Отзыв отклонен системой фильтрации спама, просим отнестись с пониманием."),
        CUSTOM("");

        private final String text;

        private RejReason(String text) {
            this.text = text;
        }

        public static RejReason safeValueOf(final String name) {
            if (Strings.isNullOrEmpty(name))
                return null;
            try {
                return valueOf(name);
            } catch (IllegalArgumentException e) {
                log.error("Unknown rejection reason: " + name);
                return null;
            }
        }

        /**
         * Human readable text describes rejection reason.
         */
        public String getText() {
            return text;
        }
    }

    /**
     * Handler of review and creator of moderation status.
     */
    public enum Handler {
        /**
         * External moderator (from QAS)
         */
        MODERATOR,
        /**
         * Somebody from review administrator interface
         */
        ADMINISTRATOR,
        /**
         * Status has been encountered automatically
         */
        AUTO;

        public static Handler safeValueOf(final String name) {
            if (Strings.isNullOrEmpty(name))
                return null;
            try {
                return valueOf(name);
            } catch (IllegalArgumentException e) {
                log.error("Unknown handler: " + name);
                return null;
            }
        }
    }

    public abstract Status getStatus();

    public abstract RejReason getRejectionReason();

    /**
     * Internalized rejection text
     */
    public abstract String getRejectionText();

    /**
     * Rejection text in case of CUSTOM rejection reason.
     */
    public abstract String getCustomRejectionText();

    public abstract Handler getHandler();

    public abstract Date getTime();

    /**
     * Some note can be leaved from administrator.
     * To be visible only from admistrator interface.
     */
    public abstract String getNote();

    @Override
    public boolean equals(final Object o) {
        if (this == o) return true;
        if (!(o instanceof Moderation2)) return false;

        final Moderation2 that = (Moderation2) o;

        return hashCode() == that.hashCode()
                && ModelUtils.equals(getStatus(), that.getStatus())
                && ModelUtils.equals(getRejectionReason(), that.getRejectionReason())
                && ModelUtils.equals(getCustomRejectionText(), that.getCustomRejectionText())
                && ModelUtils.equals(getHandler(), that.getHandler())
                && ModelUtils.equals(getTime(), that.getTime())
                && ModelUtils.equals(getNote(), that.getNote());
    }

    @Override
    public int hashCode() {
        return ModelUtils.hashCode(
                getStatus()
                , getRejectionReason()
                , getCustomRejectionText()
                , getHandler()
                , getTime()
                , getNote()
        );
    }

    @Override
    public String toString() {
        try {
            return Moderation2JsonConversions.toJson(this).toString(1);
        } catch (JSONException e) {
            throw new AssertionError("Not expected to be thrown");
        }
    }
}
