package cd.casic.ci.process.engine.worker.afl;


import cd.casic.ci.process.common.WorkAtom;
import cd.casic.ci.process.dto.req.resource.ResourceQueryReq;
import cd.casic.ci.process.dto.resp.resource.ResourceFindResp;
import cd.casic.ci.process.dto.resp.taskResource.TaskResourceFindResp;
import cd.casic.ci.process.engine.runContext.TaskRunContext;
import cd.casic.ci.process.engine.worker.base.DockerWorker;
import cd.casic.ci.process.process.dataObject.pipeline.PipPipeline;
import cd.casic.ci.process.process.dataObject.resource.PipResourceMachine;
import cd.casic.ci.process.process.dataObject.target.TargetVersion;
import cd.casic.ci.process.process.dataObject.task.PipTask;
import cd.casic.ci.process.process.dataObject.testCase.TestCaseInfo;
import cd.casic.ci.process.process.service.target.TargetVersionService;
import cd.casic.ci.process.process.service.testCase.TestCaseInfoService;
import cd.casic.ci.process.util.CryptogramUtil;
import cd.casic.ci.process.util.SftpUploadUtil;
import cd.casic.module.execute.docker.dataobject.dto.DockerEndpointDo;
import com.alibaba.fastjson.JSON;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.io.File;
import java.util.List;
import java.util.Map;
import java.util.Objects;

import static cd.casic.ci.process.engine.constant.PipelineVariableConstant.*;
import static cd.casic.ci.process.engine.constant.TestCaseGenerationConstant.*;

@WorkAtom(taskType = "TEST_CASE_GENERATION")
@Slf4j
public class TestCaseGenerationWorker extends DockerWorker {
    @Resource
    private TestCaseInfoService testCaseInfoService;
    @Resource
    private TargetVersionService targetVersionService;
    @Override
    public void execute(TaskRunContext context) {
        int statusCode = -1;
        Map<String, Object> globalVariables = context.getGlobalVariables();
        String workDir = globalVariables.get(AFL_DOCKER_WORK_DIR_KEY) instanceof String ? ((String) globalVariables.get(AFL_DOCKER_WORK_DIR_KEY)) : null;
        if (context.getContextDef() instanceof PipTask taskDef) {
            String seedPath= workDir+File.separator+ AFL_DOCKER_SEED;
            Map<String, Object> taskProperties = taskDef.getTaskProperties();
            Object caseType = taskProperties.get(CASE_TYPE_KEY);
            String binaryName = taskProperties.get(BINARY_NAME) instanceof String ? ((String) taskProperties.get("binaryName")) : null;
            String managerId = getVariableNearby(context, AFL_RESOURCE_MANAGER_ID_KEY) instanceof String ? ((String) getVariableNearby(context, AFL_RESOURCE_MANAGER_ID_KEY)) : null;
            Object itemListObject = taskProperties.get(ITEM_LIST);
            List<String> itemList = JSON.parseArray(JSON.toJSONString(itemListObject),String.class);
            ResourceFindResp resourceById = resourceManagerService.findResourceById(managerId);
            String machineId = resourceById.getMachineId();
            String dockerId = resourceById.getDockerId();
            if (StringUtils.isEmpty(machineId)||StringUtils.isEmpty(dockerId)) {
                append(context,"该资源不支持docker或者ssh");
            }
            ResourceQueryReq req = new ResourceQueryReq();
            req.setId(machineId);
            req.setType("machine");
            TaskResourceFindResp machineQuery = resourceManagerService.findResourceListByType(req);
            req.setId(dockerId);
            req.setType("docker");
            TaskResourceFindResp dockerQuery = resourceManagerService.findResourceListByType(req);
            PipResourceMachine machineInfo = machineQuery.getResourceMachineList().get(0);
            DockerEndpointDo dockerInfo = dockerQuery.getDockerEndpointList().get(0);
            PipPipeline pipeline = (PipPipeline) getContextManager().getContext(taskDef.getPipelineId()).getContextDef();
            TargetVersion targetVersion = targetVersionService.getById(pipeline.getTargetVersionId());
            String fileName = targetVersion.getFileName();
            String imageName = getVariableNearby(context,IMAGE_NAME) instanceof String ? ((String) getVariableNearby(context,IMAGE_NAME)) : null;
            //如果machineId为0，则说明该节点没有配置机器，则使用开始节点的机器
            if (CASE_TYPE_AI.equals(caseType)) {
                // 容器内部test 目录, 获取编译后的文件
                String runScript = "docker run -v "+ AFL_VOLUME_WORK_DIR_PREFIX +":"+ AFL_DOCKER_BASE_DIR+"  -it "+imageName+" bash\n" // 目前测试用例ai生成只有这个路径能跑
                + "cd "+ AFL_DOCKER_BASE_DIR+"\n" +
                        "mkdir -p "+seedPath +"\n"+
                        "cd "+seedPath +"\n"+
                        "PYTHONPATH="+AFL_DOCKER_BASE_DIR+File.separator+"CaseGenerator/src python3 "+AFL_DOCKER_BASE_DIR+File.separator+"CaseGenerator/src/CaseGenerator/main.py --work-dir "+workDir+" --binary "+workDir+File.separator+getSourceName(fileName)+File.separator+binaryName+" --output-dir "+seedPath+" --count 100";
                    //将节点的配置信息反编译成对象
                    log.info("测试用例生成-AI生成，实际执行命令:{}" , runScript);
                    append(context,"测试用例生成-AI生成，实际执行命令:"+runScript);
                    //获取机器
                dockerRun(runScript,dockerInfo,context);
            } else if (CASE_TYPE_FILE.equals(caseType)){
                // 文件上传
                Object filePathObj = taskProperties.get(SEED_SOURCE);
                log.info("当前测试用例taskProperties:{}",taskProperties);
                if (Objects.isNull(filePathObj)) {
                    append(context,"缺少文件");
                    toBadEnding();
                }
                List<String> filePathList = JSON.parseArray(JSON.toJSONString(filePathObj),String.class);
                for (String filePath : filePathList) {
                    File file = new File(filePath);
                    String seedTarget = AFL_VOLUME_WORK_DIR_PREFIX+File.separator+seedPath;
                    // 将文件上传到服务器的 目录底下
                    log.info("测试用例选用上传模式,种子文件路径：{},种子上传路径:{}",filePath,seedTarget);
                    append(context,"测试用例选用上传模式,种子文件路径："+filePath+",种子上传路径:"+seedPath);
                    try {
                        SftpUploadUtil.uploadFileViaSftp(
                                machineInfo.getMachineHost()
                                ,Integer.valueOf(machineInfo.getSshPort()),machineInfo.getUsername(),CryptogramUtil.doDecrypt(machineInfo.getPassword()),"",filePath,seedTarget,file.getName());
                    } catch (SftpUploadUtil.SftpUploadException e) {
                        append(context,"seed文件上传失败");
                        log.error("seed文件上传失败",e);
                    }
                    append(context,file.getName()+"上传文件成功！");
                }
            }else if (CASE_TYPE_ITEM.equals(caseType)){
                List<TestCaseInfo> testCaseInfos = testCaseInfoService.listByIds(itemList);
                String seedTarget = AFL_VOLUME_WORK_DIR_PREFIX+File.separator+seedPath;
                for (TestCaseInfo testCaseInfo : testCaseInfos) {
                    String testFilePath = testCaseInfo.getTestFilePath();
                    if (StringUtils.isEmpty(testFilePath)) {
                        continue;
                    }
                    try {
                        append(context,"当前上传文件:"+testCaseInfo.getFileName());
                        SftpUploadUtil.uploadFileViaSftp(
                                machineInfo.getMachineHost()
                                ,Integer.valueOf(machineInfo.getSshPort())
                                ,machineInfo.getUsername()
                                ,CryptogramUtil.doDecrypt(machineInfo.getPassword())
                                ,"", testFilePath,seedTarget,testCaseInfo.getFileName());
                    } catch (SftpUploadUtil.SftpUploadException e) {
                        toBadEnding();
                    }
                }
            }
            globalVariables.put(AFL_DOCKER_SEED_PATH_KEY,seedPath);
        }
    }
    public String getSourceName(String fileName){
        int dotIndex = fileName.lastIndexOf(".");
        if (dotIndex!=-1) {
            return fileName.substring(0, dotIndex);
        }
        return "";
    }
}
