package com.atlassian.bitbucket.test.rest.commit;

import com.atlassian.bitbucket.avatar.AvatarRequest;
import com.atlassian.bitbucket.content.DiffWhitespace;
import com.atlassian.bitbucket.test.rest.AbstractRestRequest;
import com.google.common.collect.Maps;
import org.apache.commons.lang3.StringUtils;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.Map;

import static com.google.common.base.Preconditions.checkArgument;

public class RestDiffRequest extends AbstractRestRequest {

    private final Boolean autoSrcPath;
    private final AvatarRequest avatarRequest;
    private final Integer contextLines;
    private final Boolean markup;
    private final String path;
    private final Long pullRequestId;
    private final String since;
    private final String srcPath;
    private final DiffWhitespace whitespace;
    private final Boolean withComments;

    private RestDiffRequest(Builder builder) {
        super(builder);

        autoSrcPath = builder.autoSrcPath;
        avatarRequest = builder.avatarRequest;
        contextLines = builder.contextLines;
        markup = builder.markup;
        path = builder.path;
        pullRequestId = builder.pullRequestId;
        since = builder.since;
        srcPath = builder.srcPath;
        whitespace = builder.whitespace;
        withComments = builder.withComments;
    }

    @Nullable
    public Boolean getAutoSrcPath() {
        return autoSrcPath;
    }

    @Nullable
    public AvatarRequest getAvatarRequest() {
        return avatarRequest;
    }

    @Nullable
    public Integer getContextLines() {
        return contextLines;
    }

    @Nullable
    public Boolean getMarkup() {
        return markup;
    }

    @Nonnull
    public String getPath() {
        return path;
    }

    @Nullable
    public String getSince() {
        return since;
    }

    @Nullable
    public String getSrcPath() {
        return srcPath;
    }

    @Nullable
    public DiffWhitespace getWhitespace() {
        return whitespace;
    }

    @Nullable
    public Boolean getWithComments() {
        return withComments;
    }

    @Nonnull
    @Override
    public Map<String, Object> toQueryParams() {
        Map<String, Object> params = Maps.newLinkedHashMap();
        if (autoSrcPath != null) {
            params.put("autoSrcPath", autoSrcPath);
        }
        if (avatarRequest != null) {
            params.put("avatarSize", avatarRequest.getSize());
            params.put("avatarScheme", avatarRequest.isSecure() ? "https" : "http");
        }
        if (contextLines != null) {
            params.put("contextLines", contextLines);
        }
        if (markup != null) {
            params.put("markup", markup);
        }
        if (pullRequestId != null) {
            params.put("pullRequestId", pullRequestId);
        }
        if (since != null) {
            params.put("since", since);
        }
        if (srcPath != null) {
            params.put("srcPath", srcPath);
        }
        if (whitespace != null) {
            params.put("whitespace", whitespace.name());
        }
        if (withComments != null) {
            params.put("withComments", withComments);
        }

        return params;
    }

    public static class Builder extends AbstractBuilder<Builder, RestDiffRequest> {

        private final String path;

        private Boolean autoSrcPath;
        private AvatarRequest avatarRequest;
        private Integer contextLines;
        private Boolean markup;
        private Long pullRequestId;
        private String since;
        private String srcPath;
        private DiffWhitespace whitespace;
        private Boolean withComments;

        public Builder(@Nonnull String path) {
            this.path = checkNotBlank(path, "path");
        }

        public Builder(@Nonnull RestDiffRequest request) {
            super(request);

            autoSrcPath = request.getAutoSrcPath();
            avatarRequest = request.getAvatarRequest();
            contextLines = request.getContextLines();
            path = checkNotBlank(request.getPath(), "request.path");
            since = request.getSince();
            srcPath = request.getSrcPath();
            whitespace = request.getWhitespace();
            withComments = request.getWithComments();
        }

        @Nonnull
        public Builder autoSrcPath(boolean value) {
            autoSrcPath = value;

            return self();
        }

        @Nonnull
        public Builder avatars(boolean secure, int size) {
            checkArgument(size > 0, "The minimum size for avatars is 1px");

            return avatars(new AvatarRequest(secure, size));
        }

        @Nonnull
        public Builder avatars(@Nullable AvatarRequest value) {
            avatarRequest = value;

            return self();
        }

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

        @Nonnull
        public Builder contextLines(@Nullable Integer value) {
            contextLines = value;

            return self();
        }

        @Nonnull
        public Builder markup(@Nullable Boolean value) {
            markup = value;

            return self();
        }

        @Nonnull
        public Builder pullRequestId(@Nullable Long value) {
            pullRequestId = value;

            return self();
        }

        @Nonnull
        public Builder since(@Nullable String value) {
            since = StringUtils.trimToNull(value);

            return self();
        }

        @Nonnull
        public Builder srcPath(@Nullable String value) {
            srcPath = StringUtils.trimToNull(value);

            return self();
        }

        @Nonnull
        public Builder whitespace(@Nullable DiffWhitespace value) {
            whitespace = value;

            return self();
        }

        @Nonnull
        public Builder withComments(@Nullable Boolean value) {
            withComments = value;

            return self();
        }

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