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

import org.json.JSONException;
import ru.yandex.webmaster3.core.semantic.review_business.ModelUtils;
import ru.yandex.webmaster3.core.semantic.review_business.biz.model.impl.json.ComplaintJsonConversion;

import java.util.Date;

/**
 * Complaint from biz on review.
 * It's  created by biz and checked by moderator.
 * While biz creates complaint it must specify reason and may specify text.
 * While moderator examines complaint he must specify check status and check message.
 * <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 Complaint {
    /**
     * Describes reason of a complaint.
     */
    public enum Reason {
        /**
         * Indicates any complaint.
         */
        GENERAL,

        /**
         * Indicates special case of complaint
         * 'This review isn't about us'.
         */
        MISMATCH
    }

    /**
     * Describes lifecycle of a complaint.
     */
    public enum CheckStatus {
        /**
         * Just created. Moderator didn't see on it.
         */
        NEW,

        /**
         * Moderator considers the complaint is well-grounded.
         * Correspond review will be removed from search.
         */
        ACCEPTED,
        /**
         * Moderator considers the complaint isn't well-grounded.
         */
        DECLINED
    }

    /**
     * @return unique identity of complaint
     */
    public abstract String getId();

    /**
     * @return id of biz who creates complaint
     */
    public abstract Long getBizId();

    /**
     * @return review id (permanent id) that is complaint on
     */
    public abstract String getReviewId();

    /**
     * @return date of complaint creation
     */
    public abstract Date getCreationDate();

    /**
     * @return reason of the complaint {@see Reason}
     */
    public abstract Reason getReason();

    /**
     * @return explanation of complaint
     */
    public abstract String getText();

    /**
     * @return status of moderator's check. {@see CheckStatus}
     */
    public abstract CheckStatus getCheckStatus();

    /**
     * @return moderator's explanation of complaint's check.
     */
    public abstract String getCheckMessage();

    /**
     * @return UID of user who handled this complaint
     *         or null if complaint wasn't handle
     */
    public abstract Long getHandlerUid();

    /**
     * @return date of handling this complaint
     */
    public abstract Date getHandledTime();

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

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

        final Complaint complaint = (Complaint) o;

        return hashCode() == complaint.hashCode()
                && ModelUtils.equals(getId(), complaint.getId())
                && ModelUtils.equals(getReviewId(), complaint.getReviewId())
                && ModelUtils.equals(getReason(), complaint.getReason())
                && ModelUtils.equals(getText(), complaint.getText())
                && ModelUtils.equals(getCheckStatus(), complaint.getCheckStatus())
                && ModelUtils.equals(getCheckMessage(), complaint.getCheckMessage());
    }

    @Override
    public int hashCode() {
        return ModelUtils.hashCode(
                getId()
                ,getReviewId()
                ,getReason()
                ,getText()
                ,getCheckStatus()
                ,getCheckMessage()
        );
    }
}

