package com.atlassian.bitbucket.mesh.git.ref;

import com.atlassian.bitbucket.mesh.util.BuilderSupport;

import javax.annotation.Nonnull;
import java.util.Objects;

import static java.util.Objects.requireNonNull;

public class AbstractRef implements Ref {

    private final String id;
    private final String latestCommit;
    private final RefType type;

    protected AbstractRef(@Nonnull AbstractBuilder<?, ?> builder) {
        requireNonNull(builder, "builder");

        id = requireNonNull(builder.id, "id");
        type = requireNonNull(builder.type, "type");
        latestCommit = requireNonNull(builder.latestCommit, "latestCommit");
    }

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

    @Nonnull
    @Override
    public String getLatestCommit() {
        return latestCommit;
    }

    @Nonnull
    @Override
    public String getObjectId() {
        return getLatestCommit();
    }

    @Nonnull
    @Override
    public RefType getType() {
        return type;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        AbstractRef that = (AbstractRef) o;
        return getId().equals(that.getId()) &&
                getLatestCommit().equals(that.getLatestCommit()) &&
                getType() == that.getType();
    }

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

    protected abstract static class AbstractBuilder<T extends AbstractRef, B extends AbstractBuilder<T, B>>
            extends BuilderSupport {

        private final RefType type;

        private String id;
        private String latestCommit;

        protected AbstractBuilder(@Nonnull RefType type) {
            this.type = requireNonNull(type, "type");
        }

        @Nonnull
        public abstract T build();

        @Nonnull
        public B id(@Nonnull String id) {
            this.id = requireNonNull(id, "id");
            return self();
        }

        @Nonnull
        public B latestCommit(@Nonnull String latestCommit) {
            this.latestCommit = requireNonNull(latestCommit, "latestCommit");
            return self();
        }

        @Nonnull
        protected abstract B self();
    }
}
