package com.atlassian.stash.internal.web.soy.functions;

import com.atlassian.soy.renderer.JsExpression;
import com.atlassian.soy.renderer.SoyClientFunction;
import com.atlassian.soy.renderer.SoyServerFunction;
import com.atlassian.stash.internal.web.repos.ViewRef;
import com.atlassian.stash.internal.web.repos.ViewRefType;
import com.atlassian.stash.internal.web.repos.ViewRefTypeHelper;
import com.google.common.base.Preconditions;
import org.apache.commons.lang3.StringUtils;

import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static com.atlassian.stash.internal.web.soy.functions.SoyArgumentUtils.argCountFromTo;

public class HydrateRefFromIdFunction implements SoyServerFunction<ViewRef>, SoyClientFunction {
    public static final Set<Integer> VALID_ARG_SIZES = argCountFromTo(1, 4);
    private final ViewRefTypeHelper viewRefTypeHelper;

    public HydrateRefFromIdFunction(ViewRefTypeHelper viewRefTypeHelper) {
        this.viewRefTypeHelper = viewRefTypeHelper;
    }

    @Override
    public String getName() {
        return "hydrate_ref_from_id";
    }

    @Override
    public JsExpression generate(JsExpression... args) {
        //Don't call this, if you need to use this in JS, use model/revision-reference::hydrateRefFromId directly
        return new JsExpression("");
    }

    @Override
    public ViewRef apply(Object... args) {
        Preconditions.checkArgument(args.length >= 1, "Wrong number of arguments (minimum 1)");
        Preconditions.checkArgument(args[0] instanceof String && !StringUtils.isBlank((String) args[0]), "The first argument, the ref id, should be a non-empty string");
        if (args.length >= 2) {
            Preconditions.checkArgument(args[1] == null || args[1] instanceof Boolean, "The second argument, isDefault, should be a Boolean or null");
        }
        if (args.length >= 3) {
            Preconditions.checkArgument(args[2] == null || args[2] instanceof String, "The third argument, typeId, should be a String or null");
        }
        if (args.length >= 4) {
            Preconditions.checkArgument(args[3] == null || args[3] instanceof String, "The third argument, latestCommit, should be a String or null");
        }

        String id = (String) args[0];
        Boolean isDefault = false;
        String typeId = null;
        String latestCommit = null;

        if (args.length >= 2 && (args[1] != null)) {
            isDefault = (Boolean) args[1];
        }

        if (args.length >= 3 && (args[2] != null)) {
            typeId = (String) args[2];
        }

        if (args.length >= 4 && (args[3] != null)) {
            latestCommit = (String) args[3];
        }

        return hydrate(id, isDefault, typeId, latestCommit);
    }

    private ViewRef hydrate(String id, Boolean isDefault, String typeId, String latestCommit) {
        String idPatternStr = "^refs/(heads|tags)/(.+)";
        String displayId = id.replaceAll(idPatternStr, "$2");

        if (StringUtils.isBlank(typeId)) {
            typeId = ViewRefType.BRANCH;

            Pattern pattern = Pattern.compile(idPatternStr);
            Matcher matcher = pattern.matcher(id);

            if (matcher.find()) {
                if (matcher.group(1).equals("tags")) {
                    typeId = ViewRefType.TAG;
                }
            }
        }

        return new ViewRef(id, displayId, isDefault, viewRefTypeHelper.getViewRefType(typeId), latestCommit);
    }

    @Override
    public Set<Integer> validArgSizes() {
        return VALID_ARG_SIZES;
    }
}
