package com.atlassian.bitbucket.mesh.git.builder.revlist;

import com.atlassian.bitbucket.mesh.rpc.v1.RpcCommit;

import javax.annotation.Nonnull;

import static java.util.Objects.requireNonNull;

public class CommitPumpSettings {

    /**
     * A symbolic constant for {@link #getMaxMessageLength() max message length} which means the full commit
     * message should be read regardless of length.
     */
    public static final int UNLIMITED_MESSAGE_LENGTH = -1;

    private final int maxMessageLength;
    private final CommitMessageMode messageMode;

    private CommitPumpSettings(Builder builder) {
        // All values are normalized to at least -1, and the value is discarded if the mode is explicitly NONE
        maxMessageLength = builder.messageMode == CommitMessageMode.NONE ? 0 :
                Math.max(UNLIMITED_MESSAGE_LENGTH, builder.maxMessageLength);
        // If the message length is zero, we do not want messages regardless of the specified mode. Rather than
        // getting the message and discarding it, we should just not get the message in the first place
        messageMode = builder.maxMessageLength == 0 ? CommitMessageMode.NONE : builder.messageMode;
    }

    /**
     * @return the maximum length to read for {@link RpcCommit#getMessage() commit messages}; if set, messages
     *         longer than this will be truncated.
     *         {@code 0} if no message is requested.
     */
    public int getMaxMessageLength() {
        return maxMessageLength;
    }

    /**
     * @return the message mode for the reader
     */
    @Nonnull
    public CommitMessageMode getMessageMode() {
        return messageMode;
    }

    /**
     * @return {@code true} if the commit message should be read in full; otherwise, {@code false} to indicate
     *         there is a {@link #getMaxMessageLength() max message length}
     */
    public boolean isMessageLengthUnlimited() {
        return maxMessageLength == UNLIMITED_MESSAGE_LENGTH;
    }

    public static class Builder {

        private int maxMessageLength;
        private CommitMessageMode messageMode;

        public Builder() {
            maxMessageLength = UNLIMITED_MESSAGE_LENGTH;
            messageMode = CommitMessageMode.RAW_BODY;
        }

        /**
         * @return {@link CommitPumpSettings} based on the assembled values provided to this builder
         */
        @Nonnull
        public CommitPumpSettings build() {
            return new CommitPumpSettings(this);
        }

        /**
         * @param value the maximum length for commit messages, or {@link #UNLIMITED_MESSAGE_LENGTH} (default) to
         *              read the full message without truncation
         * @return {@code this}
         */
        @Nonnull
        public Builder maxMessageLength(int value) {
            maxMessageLength = value;

            return this;
        }

        /**
         * @param value the message mode for the pump, which may not be {@code null}
         * @return {@code this}
         * @throws NullPointerException if the provided {@code value} is {@code null}
         */
        @Nonnull
        public Builder messageMode(@Nonnull CommitMessageMode value) {
            messageMode = requireNonNull(value, "messageMode");

            return this;
        }

        /**
         * @param value {@code true} to read commit messages; otherwise, {@code false} to omit them
         * @return {@code this}
         */
        @Nonnull
        public Builder withMessages(boolean value) {
            if (value) {
                // For withMessages(true), if the messageMode is NONE, set it back to RAW_BODY (the default mode).
                // Otherwise, if messageMode is any other value already, ignore the call.
                if (messageMode == CommitMessageMode.NONE) {
                    messageMode = CommitMessageMode.RAW_BODY;
                }
            } else {
                // For withMessages(false), set messageMode to NONE
                messageMode = CommitMessageMode.NONE;
            }

            return this;
        }
    }
}