package com.atlassian.bitbucket.commit;

import com.atlassian.bitbucket.util.BuilderSupport;
import com.google.common.base.Objects;
import org.apache.commons.lang3.StringUtils;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.io.Serializable;

import static java.util.Objects.requireNonNull;

public class SimpleMinimalCommit implements MinimalCommit, Serializable {

    public static final int DEFAULT_DISPLAY_ID_LENGTH = 11;

    private final String displayId;
    private final String id;

    protected SimpleMinimalCommit(AbstractMinimalCommitBuilder<?, ?> builder) {
        id = builder.id;
        displayId = builder.getDisplayId();
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o instanceof SimpleMinimalCommit) {
            SimpleMinimalCommit that = (SimpleMinimalCommit) o;

            return Objects.equal(getId(), that.getId());
        }
        return false;
    }

    @Nonnull
    @Override
    public String getDisplayId() {
        return displayId;
    }

    @Nonnull
    @Override
    public String getId() {
        return id;
    }

    @Override
    public int hashCode() {
        return Objects.hashCode(getId());
    }

    @Override
    public String toString() {
        return "SimpleMinimalCommit(id='" + getId() + "')";
    }

    public static class Builder extends AbstractMinimalCommitBuilder<Builder, MinimalCommit> {

        public Builder(@Nonnull String id) {
            super(id);
        }

        public Builder(@Nonnull MinimalCommit commit) {
            super(commit);
        }

        @Nonnull
        @Override
        public SimpleMinimalCommit build() {
            return new SimpleMinimalCommit(this);
        }

        @Nonnull
        @Override
        protected Builder self() {
            return this;
        }
    }

    protected abstract static class AbstractMinimalCommitBuilder<B extends AbstractMinimalCommitBuilder<B, R>, R extends MinimalCommit>
            extends BuilderSupport {

        protected final String id;

        protected String displayId;

        protected AbstractMinimalCommitBuilder(@Nonnull String id) {
            this.id = checkNotBlank(id, "id");
        }

        protected AbstractMinimalCommitBuilder(@Nonnull R commit) {
            displayId = requireNonNull(commit, "ref").getDisplayId();
            id = commit.getId();
        }

        @Nonnull
        public abstract R build();

        @Nonnull
        public B displayId(@Nullable String value) {
            displayId = value;

            return self();
        }

        @Nonnull
        protected abstract B self();

        @Nonnull
        private String getDisplayId() {
            return displayId == null ? StringUtils.substring(id, 0, DEFAULT_DISPLAY_ID_LENGTH) : displayId;
        }
    }
}
