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

import ru.yandex.webmaster3.core.semantic.review_business.ModelUtils;

import java.util.Collection;
import java.util.Date;

import static ru.yandex.webmaster3.core.semantic.review_business.biz.model.ToStringUtils.append;

/**
 * Represents author of the review.
 * <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 Author {
    public enum SignPrivacy {
        LOGIN,
        NAME,
        ANONYMOUS;

        public static SignPrivacy byValue(String value, SignPrivacy defaultValue) {
            for (SignPrivacy privacy : values()) {
                if (privacy.name().equals(value)) {
                    return privacy;
                }
            }
            return defaultValue;
        }
    }

    /**
     * Readable author name (typically name and surname).
     *
     * @return author's names
     *         or null if it inaccessible
     */
    public abstract String getFn();

    /**
     * @return author's login (on Yandex or another resource)
     *         or null if it's inaccessible
     */
    public abstract String getLogin();

    /**
     * Readable author name should be shown to users.
     * It may be real name and surname, or login or anonimous marker.
     * If it's null or empty client should choose appropriate substitution:
     * it may be {@see getFn} or {@see getLogin} or {@see getEmail}.
     */
    @Deprecated
    public abstract String getDisplayName();

    /**
     * This value signalize whether review will be sign by name or login.
     * Review may be anonymous as well.
     */
    public abstract SignPrivacy getSignPrivacy();

    /**
     * URL of the profile of author.
     *
     * @return URL of author's profile
     *         or null if it doesn't specified.
     */
    public abstract String getUrl();

    /**
     * E-mail of author.
     *
     * @return E-mail of author
     *         or null if it doesn't specified
     */
    public abstract String getEmail();

    /**
     * Avatar of author.
     *
     * @return URL of authors' avatar
     *         or null if it doesn't specified
     */
    public abstract String getAvatarUrl();

    /**
     * Number of thanks to user.
     * It may be used for calculate trust level for user.
     *
     * @return number of thanks to user
     *         or null if it's inaccessible
     */
    public abstract Integer getThanksCount();

    /**
     * Number of user's posts on the resource.
     * It may be used for calculate trust level for user.
     *
     * @return number of user's post count on the resource
     *         or null if it's inaccessible
     */
    public abstract Integer getPostsCount();

    /**
     * Number of user's comments on the resource.
     * It may be used for calculate trust level for user.
     *
     * @return number of user's comments on the resource
     *         or null if it's inaccessible
     */
    public abstract Integer getCommentsCount();

    /**
     * Number of user's friends on the resource.
     * It may be used for calculate trust level for user.
     *
     * @return number of user's friends on the resource
     *         or null if it's inaccessible
     */
    public abstract Integer getFriendsCount();

    /**
     * Abstract number that used
     * for calculate user's trust level.
     */
    public abstract Float getKarma();

    /**
     * Account registration date from passport
     */
    public abstract Date getRegdate();

    /**
     * Social info for authors authorized with social account
     */
    public abstract Collection<Social> getSocials();

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

        final Author author = (Author) o;

        return hashCode() == o.hashCode()
                && ModelUtils.equals(getFn(), author.getFn())
                && ModelUtils.equals(getUrl(), author.getUrl())
                && ModelUtils.equals(getEmail(), author.getEmail())
                && ModelUtils.equals(getAvatarUrl(), author.getAvatarUrl())
                && ModelUtils.equals(getThanksCount(), author.getThanksCount())
                && ModelUtils.equals(getPostsCount(), author.getPostsCount())
                && ModelUtils.equals(getCommentsCount(), author.getCommentsCount())
                && ModelUtils.equals(getFriendsCount(), author.getFriendsCount())
                && ModelUtils.equals(getKarma(), author.getKarma())
                && ModelUtils.equals(getRegdate(), author.getRegdate())
                && ModelUtils.equals(getSocials(), author.getSocials());
    }

    @Override
    public int hashCode() {
        return ModelUtils.hashCode(
                getFn()
                , getUrl()
                , getEmail()
                , getAvatarUrl()
                , getThanksCount()
                , getPostsCount()
                , getCommentsCount()
                , getFriendsCount()
                , getKarma()
                , getRegdate()
                , getSocials()
        );
    }

    @Override
    public String toString() {
        final StringBuilder sb = new StringBuilder();
        sb.append("Author: [");
        append(sb, "Fn", getFn());
        append(sb, "Login", getLogin());
        append(sb, "SignPrivacy", getSignPrivacy());
        append(sb, "Url", getUrl());
        append(sb, "Email", getEmail());
        append(sb, "AvatarUrl", getAvatarUrl());
        append(sb, "ThanksCount", getThanksCount());
        append(sb, "PostsCount", getPostsCount());
        append(sb, "CommentsCount", getCommentsCount());
        append(sb, "FriendsCount", getFriendsCount());
        append(sb, "Karma", getKarma());
        append(sb, "RegDate", getRegdate());
        append(sb, "Socials", getSocials());
        sb.append("]");
        return sb.toString();
    }
}
