package com.microservices.pms.pipeline.domain.vo;

import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.apache.commons.lang3.StringUtils;

import java.util.*;
import java.util.stream.Collectors;

@Getter
@Setter
@NoArgsConstructor
public class NodeActionVo {

    private String name;
    private final Map<String, Object> on = new LinkedHashMap<>();
    private final Map<String, Object> jobs = new LinkedHashMap<>();
    @JsonIgnore
    private Map<String, Object> params = new LinkedHashMap<>();

    public void buildName(String name) {
        this.name = name;
    }

    public void parse(List<Map<String, Object>> steps, PipelineVo.PipelineJson.Nodes node){
        String nodeName = Optional.ofNullable(node.getName()).orElse("");
        if (nodeName.startsWith("on-")) {
            buildOn(node);
        }else if (nodeName.startsWith("setup-")) {
            buildSetupStep(steps, node);
        }else if (Objects.equals(nodeName,"shell")) {
            buildShellStep(steps, node);
        }else if (StringUtils.isNotEmpty(nodeName)) {
            buildOtherStep(steps, node);
        }
    }

    public void buildOn(PipelineVo.PipelineJson.Nodes node) {
        String nodeName = node.getName();
        Map<String, Object> step = new LinkedHashMap<>();
        List<PipelineVo.PipelineJson.Nodes.Inputs> inputs = getInputs(node);

        if (Objects.equals(nodeName, "on-schedule")) {
            inputs.forEach(e -> {
                step.put(e.getName(), e.getValue());
            });
            this.on.put(nodeName.split("-")[1], step);
            return;
        }

        inputs.forEach(e -> {
            step.put(e.getName(), e.getValue().replace("\'","").split(","));
        });

        this.on.put(nodeName.split("-")[1], step);
    }

    public void buildJobs(String jobKey, String jobName, List<Map<String, Object>> steps) {
        if (steps.isEmpty()) return;
        Map<String, Object> job = new LinkedHashMap<>();
        job.put("runs-on", "ubuntu-latest");
        job.put("name", jobName);
        job.put("steps", steps);
        this.jobs.put(jobKey+(this.jobs.size()), job);
    }

    public void buildSetupStep(List<Map<String, Object>> steps, PipelineVo.PipelineJson.Nodes node) {
        String nodeName = node.getName();
        Map<String, Object> step = new LinkedHashMap<>();

        List<PipelineVo.PipelineJson.Nodes.Inputs> inputs = getInputs(node);

        if (nodeName.startsWith("setup-java")) {

            Map<String, String> name2Value = inputs.stream()
                    .collect(Collectors.toMap(e -> e.getName(), e -> e.getValue(), (o, n) -> n));

            Map<String, Object> with = new LinkedHashMap<>();
            if (name2Value.containsKey("download_url") && StringUtils.isNotBlank(name2Value.get("download_url"))) {
                steps.add(Collections.singletonMap("run", "download_url=" + name2Value.get("download_url") + " && " + "wget -O $RUNNER_TEMP/java_package.tar.gz $download_url"));
                with.put("distribution", "jdkfile");
                with.put("jdkFile", "${{ runner.temp }}/java_package.tar.gz");
            }
            step.put("name", node.getLabel());
            step.put("uses", node.getFull_name().trim());
            if (!inputs.isEmpty()) {

                inputs.forEach(i -> {
                    with.put(i.getName(), Optional.ofNullable(i.getValue()).orElse(""));
                });

                step.put("with", with);
            }
            steps.add(step);
            return;
        }

        step.put("name", node.getLabel());
        step.put("uses", node.getFull_name().trim());
        if (!inputs.isEmpty()) {
            Map<String, Object> with = new LinkedHashMap<>();
            inputs.forEach(i -> {
                with.put(i.getName(), Optional.ofNullable(i.getValue()).orElse(""));
            });

            step.put("with", with);
        }
        steps.add(step);

    }

    public void buildShellStep(List<Map<String, Object>> steps, PipelineVo.PipelineJson.Nodes node) {
        Map<String, Object> step = new LinkedHashMap<>();
        step.put("name", node.getLabel());
        List<PipelineVo.PipelineJson.Nodes.Inputs> inputs = Optional.ofNullable(node.getInputs()).orElse(new ArrayList<>());
        inputs.forEach(i -> {
            step.put(i.getName(), Optional.ofNullable(i.getValue()).orElse(""));
        });

        steps.add(step);
    }

    public void buildOtherStep(List<Map<String, Object>> steps, PipelineVo.PipelineJson.Nodes node) {
        Map<String, Object> step = new LinkedHashMap<>();

        List<PipelineVo.PipelineJson.Nodes.Inputs> inputs = getInputs(node);

        step.put("name", node.getLabel());
        step.put("uses", node.getFull_name().trim());
        if (!inputs.isEmpty()) {
            Map<String, Object> with = new LinkedHashMap<>();
            inputs.forEach(i -> {
                with.put(i.getName(), Optional.ofNullable(i.getValue()).orElse(""));
            });

            step.put("with", with);
        }
        steps.add(step);
    }

    private  List<PipelineVo.PipelineJson.Nodes.Inputs> getInputs(PipelineVo.PipelineJson.Nodes node) {
        return Optional.ofNullable(node.getInputs()).orElse(new ArrayList<>())
                .stream()
                .filter(e -> StringUtils.isNotBlank(e.getValue())).collect(Collectors.toList());
    }
}
