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.taskResource.TaskResourceFindResp;
import cd.casic.ci.process.engine.constant.AFLConstant;
import cd.casic.ci.process.engine.constant.DIYImageExecuteCommandConstant;
import cd.casic.ci.process.engine.constant.PipelineGlobalVariableConstant;
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.target.TargetVersion;
import cd.casic.ci.process.process.dataObject.task.PipTask;
import cd.casic.ci.process.process.service.target.TargetVersionService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.CollectionUtils;

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

@WorkAtom(taskType = "AFL")
@Slf4j
public class AFLWorker extends DockerWorker {
    @Resource
    private TargetVersionService targetVersionService;
    @Override
    public void execute(TaskRunContext context) {
        int statusCode = -1;
        Map<String, Object> localVariables = context.getLocalVariables();
        Map<String, Object> globalVariables = context.getGlobalVariables();
        if (context.getContextDef() instanceof PipTask taskDef) {
            log.info(taskDef.getTaskName());
            Map<String, Object> taskProperties = taskDef.getTaskProperties();
            //从taskProperties中获取资源id
            String resourceType = taskProperties.get("resourceType").toString();
            String resourceId = taskProperties.get("resourceId").toString();
            String commandEnd = taskProperties.get("commandEnd").toString();
            String imageName = taskProperties.get("imageName").toString();
            // 代码编译目录
            String workDir = (String)globalVariables.get(PipelineGlobalVariableConstant.AFL_DOCKER_WORK_DIR_KEY);
            // 入参目录
            String seedPath = (String)globalVariables.get(PipelineGlobalVariableConstant.AFL_DOCKER_SEED_PATH_KEY);
            if (StringUtils.isEmpty(seedPath) ||
                    StringUtils.isEmpty(workDir) ||
                    StringUtils.isEmpty(resourceId) ||
                    StringUtils.isEmpty(commandEnd) ||
                    StringUtils.isEmpty(resourceType)) {
//                缺少参数
                toBadEnding();
            }
            ResourceQueryReq req = new ResourceQueryReq();
            req.setId(resourceId);
            req.setType(resourceType);
            TaskResourceFindResp resourceListByType = getResourceManagerService().findResourceListByType(req);
            if (CollectionUtils.isEmpty(resourceListByType.getDockerEndpointList())) {
                append(context,"当前机器不支持docker");
                return;
            }
            String output = workDir +File.separator+ PipelineGlobalVariableConstant.AFL_DOCKER_OUTPUT;
            //
            String volumeWorkDirPath = PipelineGlobalVariableConstant.AFL_VOLUME_WORK_DIR_PREFIX;
            PipPipeline pipeline = (PipPipeline) getContextManager().getContext(taskDef.getPipelineId()).getContextDef();
            TargetVersion targetVersion = targetVersionService.getById(pipeline.getTargetVersionId());
            String fileName = targetVersion.getFileName();
            append(context,"AFL 输出路径："+output);
            Object timeObj = taskProperties.get("runningTime");
            Double timeHours = Double.valueOf(String.valueOf(timeObj));
            String commandScript = "docker run -v "+volumeWorkDirPath+":/test  -it "+imageName+" bash\n" +
                    "cd " +PipelineGlobalVariableConstant.AFL_DOCKER_BASE_DIR+File.separator+workDir+ "\n"+
                    cdSourceName(fileName) +
                    "mkdir -p "+PipelineGlobalVariableConstant.AFL_DOCKER_BASE_DIR+File.separator+output+"\n" +
                    "afl-fuzz -i "+PipelineGlobalVariableConstant.AFL_DOCKER_BASE_DIR+File.separator+seedPath+" -o "+PipelineGlobalVariableConstant.AFL_DOCKER_BASE_DIR+File.separator+output+"  "+commandEnd;
            try {
                //将节点的配置信息反编译成对象
                log.info("AFL模糊测试执行脚本：{}",commandScript);
                append(context,"AFL模糊测试执行脚本："+commandScript);
                Long runningTime = getRunningTime(timeHours);
                append(context,"运行时间"+runningTime);
                // 获取docker 暂时先写固定值
                dockerRun(commandScript,resourceListByType.getDockerEndpointList().get(0),context, runningTime);
            } catch (Exception e) {
                String errorMessage = "该节点配置信息为空，请先配置该节点信息" + "\r\n";
                log.error("执行ssh失败:", e);
                append(context, errorMessage);
                toBadEnding();
            }
            localVariables.put(DIYImageExecuteCommandConstant.STATUS_CODE, statusCode);
        }
    }
    public String cdSourceName(String fileName){
        int dotIndex = fileName.lastIndexOf(".");
        if (dotIndex!=-1) {
            return "cd "+fileName.substring(0, dotIndex)+"\n";
        }
        return "";
    }
    public Long getRunningTime(Double runningTimeHours){
        if (runningTimeHours!=null && runningTimeHours >0) {
            return (long)(runningTimeHours*60*60*1000);
        }
        return null;
    }
}
