package com.atlassian.bitbucket.test;

import com.jayway.restassured.RestAssured;
import com.jayway.restassured.http.ContentType;
import com.jayway.restassured.specification.RequestSpecification;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;

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

import static com.atlassian.bitbucket.test.rest.ResponseMatchers.noContent;
import static com.atlassian.bitbucket.test.rest.ResponseMatchers.successful;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.hamcrest.Matchers.not;

public class BranchModelTestHelper {

    public static final String BUGFIX_TYPE = "BUGFIX";
    public static final String FEATURE_TYPE = "FEATURE";
    public static final String HOTFIX_TYPE = "HOTFIX";
    public static final String RELEASE_TYPE = "RELEASE";

    private static final String BRANCH_UTILS_REST_MODULE = "branch-utils";
    private static final String BRANCH_MODEL_PATH = "/branchmodel";
    private static final String BRANCH_MODEL_CONFIGURATION_PATH = BRANCH_MODEL_PATH + "/configuration";

    private final String username;
    private final String password;
    private final String projectKey;
    private final String repoSlug;

    public BranchModelTestHelper(@Nonnull String username, @Nonnull String password, @Nonnull String projectKey,
                                 @Nonnull String repoSlug) {
        this.username = checkNotNull(username, "username");
        this.password = checkNotNull(password, "password");
        this.projectKey = checkNotNull(projectKey, "projectKey");
        this.repoSlug = checkNotNull(repoSlug, "repoSlug");
    }

    public BranchModelTestHelper(@Nonnull String projectKey, @Nonnull String repoSlug) {
        this(DefaultFuncTestData.getAdminUser(), DefaultFuncTestData.getAdminPassword(), projectKey, repoSlug);
    }

    public BranchModelTestHelper() {
        this(DefaultFuncTestData.getProject1(), DefaultFuncTestData.getProject1Repository1());
    }

    public static JSONObject createBranchModelJson(JSONObject developmentConfiguration, JSONObject productionConfiguration,
                                                   JSONObject... types) {
        JSONObject body = new JSONObject();
        body.put("development", developmentConfiguration);
        if (productionConfiguration != null) {
            body.put("production", productionConfiguration);
        }
        if (types.length > 0) {
            JSONArray typesJson = new JSONArray();
            typesJson.addAll(Arrays.asList(types));
            body.put("types", typesJson);
        }
        return body;
    }

    public static JSONObject createBranchModelUseDefaultJson() {
        JSONObject body = new JSONObject();
        body.put("useDefault", true);
        return body;
    }

    public static JSONObject createBranchConfiguration(String refId, boolean useDefault) {
        JSONObject branchConfiguration = new JSONObject();
        if (refId != null) {
            branchConfiguration.put("refId", refId);
        }
        branchConfiguration.put("useDefault", useDefault);
        return branchConfiguration;
    }

    public static JSONObject createBranchTypeConfiguration(String id, String prefix, boolean enabled) {
        JSONObject type = new JSONObject();
        type.put("id", id);
        type.put("prefix", prefix);
        type.put("enabled", enabled);
        return type;
    }

    public void disable() {
        rest().expect()
                .statusCode(noContent())
                .log().ifStatusCodeMatches(not(noContent()))
                .delete(getConfigurationUrl());
    }

    public void enable() {
        enable(null);
    }

    public void enable(@Nullable JSONObject customConfiguration) {
        RequestSpecification specification = rest();
        if (customConfiguration != null) {
            specification.body(customConfiguration);
        }
        specification.expect()
                .statusCode(successful())
                .log().ifStatusCodeMatches(not(successful()))
                .put(getConfigurationUrl());
    }

    public void enableAutoMerge() {
        RestAssured.expect()
                .given().auth().preemptive().basic(DefaultFuncTestData.getAdminUser(), DefaultFuncTestData.getAdminPassword()).body(new JSONObject()).contentType(ContentType.JSON)
                .expect().response().statusCode(successful())
                .when().put(DefaultFuncTestData.getRepositoryRestURL("branch-utils", "latest", projectKey, repoSlug) + "/automerge/enabled");
    }

    public void resetToDefault() {
        rest().body(createBranchModelUseDefaultJson())
                .expect()
                .statusCode(successful())
                .log().ifStatusCodeMatches(not(successful()))
                .put(getConfigurationUrl());
    }

    public String getConfigurationUrl() {
        return DefaultFuncTestData.getRepositoryRestURL(BRANCH_UTILS_REST_MODULE, "latest", projectKey, repoSlug) + BRANCH_MODEL_CONFIGURATION_PATH;
    }

    private RequestSpecification rest() {
        return RestAssured.given().auth().preemptive().basic(username, password).contentType(ContentType.JSON);
    }
}
