package com.atlassian.bitbucket.pull;

import com.atlassian.bitbucket.commit.Commit;
import com.atlassian.bitbucket.util.BuilderSupport;
import com.google.common.collect.ImmutableList;

import javax.annotation.Nonnull;
import java.io.Serializable;
import java.util.*;

import static java.util.Objects.requireNonNull;

/**
 * @since 4.5
 */
public class SimpleRescopeDetails implements RescopeDetails, Serializable {

    public static final SimpleRescopeDetails EMPTY = new SimpleRescopeDetails();

    /**
     * Orders commits in reverse chronological order, by descending {@link Commit#getAuthorTimestamp() author
     * timestamp}.
     * <p>
     * Note: This does <i>not</i> match the date ordering used by {@code git rev-list}, which is reverse chronological
     * order by <i>committer</i> timestamp, not author. The two are <i>usually</i> the same, but rebase-heavy workflows
     * may result in rescope activities showing commits in a different order than the "Commits" tab.
     */
    public static final Comparator<Commit> DATE_ORDER = (lhs, rhs) ->
            rhs.getAuthorTimestamp().compareTo(lhs.getAuthorTimestamp());

    private final List<Commit> commits;
    private final int total;

    private SimpleRescopeDetails() {
        commits = Collections.emptyList();
        total = 0;
    }

    private SimpleRescopeDetails(Builder builder) {
        commits = ImmutableList.copyOf(builder.commits);
        total = builder.total;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        SimpleRescopeDetails that = (SimpleRescopeDetails) o;
        return Objects.equals(total, that.total) &&
                Objects.equals(commits, that.commits);
    }

    @Nonnull
    @Override
    public List<Commit> getCommits() {
        return commits;
    }

    @Override
    public int getTotal() {
        return total;
    }

    @Override
    public int hashCode() {
        return Objects.hash(commits, total);
    }

    public boolean isEmpty() {
        return total == 0;
    }

    @Override
    public String toString() {
        return "{RescopeDetails total: " + total + ", commits: " + commits + "}";
    }

    public static class Builder extends BuilderSupport {

        private final List<Commit> commits;

        private int total;

        public Builder() {
            commits = new ArrayList<>();
        }

        public Builder(@Nonnull RescopeDetails details) {
            commits = new ArrayList<>(requireNonNull(details, "details").getCommits());
            total = details.getTotal();
        }

        @Nonnull
        public SimpleRescopeDetails build() {
            //Sort the commits to ensure, regardless of the order they are added in, they are always listed in
            //reverse chronological order
            Collections.sort(commits, DATE_ORDER);

            return new SimpleRescopeDetails(this);
        }

        @Nonnull
        public Builder commit(Commit value) {
            addIf(Objects::nonNull, commits, value);

            return this;
        }

        @Nonnull
        public Builder commits(Iterable<Commit> value) {
            addIf(Objects::nonNull, commits, value);

            return this;
        }

        @Nonnull
        public Builder total(int value) {
            total = value;

            return this;
        }
    }
}
