package com.atlassian.stash.internal.plugin.hooks.allapprovers;

import com.atlassian.bitbucket.repository.Repository;
import com.atlassian.bitbucket.ui.ContextualFormFragment;
import com.atlassian.bitbucket.ui.ValidationErrors;
import com.atlassian.bitbucket.view.TemplateRenderingException;
import com.atlassian.soy.renderer.SoyException;
import com.atlassian.soy.renderer.SoyTemplateRenderer;

import javax.annotation.Nonnull;
import java.io.IOException;
import java.util.Collection;
import java.util.Map;

import static com.atlassian.stash.internal.plugin.hooks.allapprovers.AllApproversMergeCheckConfig.MODULE_KEY;
import static java.util.Objects.requireNonNull;

public class AllApproversMergeCheckFormFragment implements ContextualFormFragment {

    private static final String FRAGMENT_TEMPLATE = "bitbucket.internal.allApprovers.mergeCheck.fragment";
    private static final String REQUIRE_ALL_APPROVERS_ID = "require-all-approvers-for-merge";
    private static final String REQUIRE_ALL_APPROVERS_PARAM = "requireAllApproversForMerge";
    private static final String REPOSITORY = "repository";

    private final AllApproversMergeCheckConfig config;
    private final SoyTemplateRenderer soyTemplateRenderer;

    public AllApproversMergeCheckFormFragment(AllApproversMergeCheckConfig config,
                                              SoyTemplateRenderer soyTemplateRenderer) {
        this.config = config;
        this.soyTemplateRenderer = soyTemplateRenderer;
    }

    @Override
    public void doView(@Nonnull Appendable appendable, @Nonnull Map<String, Object> context) throws IOException {
        requireNonNull(appendable, "appendable");
        requireNonNull(context, "context");

        context.put(REQUIRE_ALL_APPROVERS_PARAM, config.areAllApproversRequired(getRepository(context)));
        renderView(appendable, context);
    }

    @Override
    public void validate(@Nonnull Map<String, String[]> stringMap, @Nonnull ValidationErrors validationErrors,
                         @Nonnull Map<String, Object> stringObjectMap) {
        //Validation is not required as it's a checkbox (checked is a non null value, unchecked is null)
    }

    @Override
    public void doError(@Nonnull Appendable appendable, @Nonnull Map<String, String[]> requestParams,
                        @Nonnull Map<String, Collection<String>> fieldErrors, @Nonnull Map<String, Object> context)
            throws IOException {
        requireNonNull(appendable, "appendable");
        requireNonNull(context, "context");
        requireNonNull(requestParams, "requestParams");

        context.put(REQUIRE_ALL_APPROVERS_ID, isCheckBoxEnabled(requestParams));
        renderView(appendable, context);
    }

    @Override
    public void execute(@Nonnull Map<String, String[]> requestParams, @Nonnull Map<String, Object> context) {
        requireNonNull(context, "context");
        requireNonNull(requestParams, "requestParams");

        config.setAllApproversRequired(getRepository(context), isCheckBoxEnabled(requestParams));
    }

    private Repository getRepository(Map<String, Object> context) {
        return (Repository) context.get(REPOSITORY);
    }

    private boolean isCheckBoxEnabled(Map<String, String[]> requestParams) {
        String[] values = requestParams.get(REQUIRE_ALL_APPROVERS_ID);
        return values != null && values.length == 1 && values[0].equalsIgnoreCase("on");
    }

    private void renderView(Appendable appendable, Map<String, Object> context) {
        try {
            soyTemplateRenderer.render(appendable, MODULE_KEY, FRAGMENT_TEMPLATE, context);
        } catch (SoyException e) {
            throw new TemplateRenderingException("Failed to render " + FRAGMENT_TEMPLATE, e);
        }
    }
}
