package cd.casic.server;
import cd.casic.module.machine.utils.CryptogramUtil;
import com.github.dockerjava.api.DockerClient;
import com.github.dockerjava.api.command.CreateContainerResponse;
import com.github.dockerjava.api.command.ExecCreateCmdResponse;
import com.github.dockerjava.api.model.Bind;
import com.github.dockerjava.api.model.Frame;
import com.github.dockerjava.api.model.HostConfig;
import com.github.dockerjava.api.model.Image;
import com.github.dockerjava.core.DockerClientBuilder;
import com.github.dockerjava.httpclient5.ApacheDockerHttpClient;
import org.apache.commons.lang3.StringUtils;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles;

import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.List;
import java.util.concurrent.TimeUnit;

import static java.lang.String.format;

@SpringBootTest(classes = {OpsServerApplication.class})
@ActiveProfiles("local")
public class DockerTest {
    // TODO 测试通过，明天继续整通用的
    public static String executeParsedDockerCommand(
            String dockerHostUri,
            String dockerRunCommand,
            String[] commandInContainer,
            int execTimeoutMinutes) {

        // 1. 解析docker run命令
        String[] parts = dockerRunCommand.split("\\s+");
        if (parts.length < 6 || !"docker".equals(parts[0]) || !"run".equals(parts[1])) {
            throw new RuntimeException("Invalid docker run command format");
        }

        // 2. 提取参数
        String volumeArg = null;
        String imageName = null;
        String initialCommand = null;

        for (int i = 2; i < parts.length; i++) {
            if ("-v".equals(parts[i]) && i + 1 < parts.length) {
                volumeArg = parts[++i];
            } else if ("-it".equals(parts[i])) {
                // 跳过交互式参数
            } else if (imageName == null) {
                imageName = parts[i];
            } else if (initialCommand == null) {
                initialCommand = parts[i];
            }
        }

        if (volumeArg == null || imageName == null) {
            throw new RuntimeException("Missing required parameters in docker run command");
        }

        // 3. 解析卷挂载参数
        String[] volumeParts = volumeArg.split(":");
        if (volumeParts.length != 2) {
            throw new RuntimeException("Invalid volume format, expected host_path:container_path");
        }
        String hostPath = volumeParts[0];
        String containerPath = volumeParts[1];

        ApacheDockerHttpClient httpClient;
        try {
            httpClient = new ApacheDockerHttpClient.Builder().dockerHost(new URI(dockerHostUri)).build();
        } catch (URISyntaxException e) {
            throw new RuntimeException(e);
        }
        DockerClient dockerClient = DockerClientBuilder.getInstance().withDockerHttpClient(httpClient).build();
        try {
            // 5. 创建容器
            HostConfig hostConfig = HostConfig.newHostConfig()
                    .withBinds(Bind.parse(volumeArg));

            CreateContainerResponse container = dockerClient.createContainerCmd(imageName)
                    .withHostConfig(hostConfig)
                    .withCmd(initialCommand)
                    .withTty(true)
                    .exec();

            String containerId = container.getId();

            // 6. 启动容器
            dockerClient.startContainerCmd(containerId).exec();

            try {
                // 7. 构建要在容器内执行的完整命令
                String[] fullCommand = new String[commandInContainer.length + 2];
                fullCommand[0] = "sh";
                fullCommand[1] = "-c";
                fullCommand[2] = "cd " + containerPath + " && " + StringUtils.join(commandInContainer, " ");
//                System.arraycopy(commandInContainer, 0, fullCommand, 3, commandInContainer.length - 1);

                // 8. 创建exec实例
                ExecCreateCmdResponse execCreateCmdResponse = dockerClient.execCreateCmd(containerId)
                        .withAttachStdout(true)
                        .withAttachStderr(true)
                        .withCmd(fullCommand)
                        .exec();

                // 9. 执行命令并获取输出
                String output = dockerClient.execStartCmd(execCreateCmdResponse.getId())
                        .exec(new ExecStartResultCallback())
                        .awaitOutput(execTimeoutMinutes, TimeUnit.MINUTES);

                return output;
            } finally {
                // 10. 清理容器
                dockerClient.stopContainerCmd(containerId).exec();
                dockerClient.removeContainerCmd(containerId).exec();
            }
        } finally {
            try {
                dockerClient.close();
            } catch (IOException e) {

            }
        }
    }

    private static class ExecStartResultCallback extends com.github.dockerjava.api.async.ResultCallback.Adapter<Frame> {
        private final StringBuilder output = new StringBuilder();

        @Override
        public void onNext(Frame frame) {
            output.append(new String(frame.getPayload()));
        }

        public String awaitOutput(long timeout, TimeUnit timeUnit) {
            try {
                super.awaitCompletion(timeout, timeUnit);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                throw new RuntimeException("Command execution interrupted", e);
            }
            return output.toString();
        }
    }

    // 示例用法
    @Test
    public void test() {
        // *** 请将此处的远程 Docker TCP 地址替换为您实际的值 ***
        String remoteDockerHostUri = "tcp://175.6.27.228:22375"; // <-- !!! REPLACE THIS !!!

        // *** 提供您希望解析的 docker run 命令字符串 ***
        // 注意：此解析器仅支持简化的格式
        String dockerRunCmdString = "docker run -v /home/yunqi/:/test -it aflplusplus/aflplusplus bash";
        System.out.println("待解析并执行的 Docker run 命令: " + dockerRunCmdString);


        // 要在容器内执行的 afl-fuzz 命令及其参数
        // 这部分仍然需要单独提供，因为解析器不负责从 docker run 命令中提取后续要 exec 的命令
        String[] aflFuzzCommand = {
                "afl-fuzz",
                "-i", "case",
                "-o", "ai_afl",
                "-t", "3000",
                "-Q",
                "./CaseGenerator/testdata/libpng/libpng/pngfix",
                "@@"
        };
        System.out.print("将在容器内执行的命令: ");
        for (String arg : aflFuzzCommand) {
            System.out.print(arg + " ");
        }
        System.out.println();


        // 命令执行超时时间（分钟）
        int commandTimeoutMinutes = 60; // 例如，给 afl-fuzz 60 分钟运行时间

        try {
            // 调用解析并执行的方法
            System.out.println("\n开始执行解析后的 Docker 命令序列...");
            String aflOutput = executeParsedDockerCommand(
                    remoteDockerHostUri,
                    dockerRunCmdString,
                    aflFuzzCommand,
                    commandTimeoutMinutes
            );

            System.out.println("\n--- AFL-fuzz 命令的标准输出 ---");
            System.out.println(aflOutput);
            System.out.println("------------------------------");

        } catch (RuntimeException e) {
            System.err.println("\n--- 执行过程中发生错误 ---");
            System.err.println(e.getMessage());
            e.printStackTrace();
            System.err.println("---------------------------");
        }
    }
    @Test
    public void imageList() throws URISyntaxException {
        URI uri = new URI(format("tcp://%s:%s", "175.6.27.158", "22375"));

        ApacheDockerHttpClient httpClient = new ApacheDockerHttpClient.Builder().dockerHost(uri).build();
        DockerClient build = DockerClientBuilder.getInstance().withDockerHttpClient(httpClient).build();
        List<Image> exec = build.listImagesCmd().exec();
        for (Image image : exec) {
            String[] repoTags = image.getRepoTags();
            if (repoTags ==null) {
                System.out.println("虚悬镜像");
            } else if (repoTags.length>1){
                System.out.println("多标签1镜像");
            } else {
                System.out.println("");
            }

        }
        System.out.println(exec);
    }
    @Test
    public void encode(){
        System.out.println(CryptogramUtil.doEncrypt("Hunter@2024"));
    }

}
