package cn.reghao.bnt.web.devops.builder.tool.compiler;

import lombok.extern.slf4j.Slf4j;
import org.apache.maven.model.Model;
import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
import org.apache.maven.shared.invoker.*;
import org.apache.maven.shared.utils.cli.CommandLineException;
import org.codehaus.plexus.util.xml.pull.XmlPullParserException;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;

/**
 * Maven 编译，打包
 *
 * @author reghao
 * @date 2019-10-12 23:55:01
 */
@Slf4j
public class MavenCompiler implements CodeCompiler {
    private final MavenXpp3Reader reader;
    private final Invoker invoker;
    private final String[] standaloneArgs;

    public MavenCompiler(String mavenHome) {
        System.setProperty("maven.home", mavenHome);
        this.invoker = new DefaultInvoker();
        this.reader = new MavenXpp3Reader();
        this.standaloneArgs = new String[]{"clean", "package", "-Dmaven.test.skip=true"};
    }

    @Override
    public void compile(String appId, String appCompileHome) throws Exception {
        throw new Exception("未实现此方法");
    }

    @Override
    public void compile(String appId, String appCompileHome, String env, String appRootPath) throws Exception {
        String pomPath = appCompileHome + "/pom.xml";
        boolean multiModule = isMultiModule(pomPath);
        MavenBuild mavenBuild;
        if (multiModule) {
            mavenBuild = setMultiModuleInvocationRequest(pomPath, env, appRootPath);
        } else {
            mavenBuild = setStandaloneInvocationRequest(pomPath, env);
        }

        InvocationResult result = invoker.execute(mavenBuild.invocationRequest);
        if (result.getExitCode() != 0) {
            CommandLineException exception = result.getExecutionException();
            if (exception != null) {
                throw exception;
            }
            throw new Exception(mavenBuild.stringBuilder.toString());
        }
    }

    private boolean isMultiModule(String pomPath) throws IOException, XmlPullParserException {
        FileInputStream fis = new FileInputStream(pomPath);
        Model model = reader.read(fis);
        String packaging = model.getPackaging();
        return "pom".equals(packaging);
    }

    /**
     * mvn clean package -Dmaven.test.skip=true -Pdev
     *
     * @param
     * @return
     * @date 2022-05-12 下午2:56
     */
    private MavenBuild setStandaloneInvocationRequest(String pomPath, String env) {
        MavenBuild mavenBuild = new MavenBuild();
        InvocationRequest request = mavenBuild.invocationRequest;
        request.setPomFile(new File(pomPath));
        // mvn clean package -Dmaven.test.skip=true
        request.setGoals(Arrays.asList(standaloneArgs));
        // -Penv
        request.setProfiles(Collections.singletonList(env));
        request.setOutputHandler(s -> mavenBuild.stringBuilder.append(s).append(System.lineSeparator()));
        return mavenBuild;
    }

    /**
     * mvn clean package -Dmaven.test.skip=true -am -Pdev -pl mgr
     *
     * @param
     * @return
     * @date 2020-05-12 上午10:36
     */
    private MavenBuild setMultiModuleInvocationRequest(String pomPath, String env, String appDirname) {
        MavenBuild mavenBuild = new MavenBuild();
        InvocationRequest request = mavenBuild.invocationRequest;
        request.setPomFile(new File(pomPath));
        // mvn clean package -Dmaven.test.skip=true
        request.setGoals(Arrays.asList(standaloneArgs));
        // -Penv
        request.setProfiles(Collections.singletonList(env));
        // -am
        request.setAlsoMake(true);
        // -pl app
        request.setProjects(Collections.singletonList(appDirname));
        request.setOutputHandler(s -> mavenBuild.stringBuilder.append(s).append(System.lineSeparator()));
        return mavenBuild;
    }

    static class MavenBuild {
        InvocationRequest invocationRequest;
        StringBuilder stringBuilder;

        MavenBuild() {
            this.invocationRequest = new DefaultInvocationRequest();
            this.stringBuilder = new StringBuilder();
        }
    }
}
