package cd.casic.ci.process.process.service.aflManager.impl;

import cd.casic.ci.process.dto.req.aflManager.AflManagerReq;
import cd.casic.ci.process.dto.resp.aflManager.AflBaseInfoResp;
import cd.casic.ci.process.dto.resp.aflManager.AflInfoResp;
import cd.casic.ci.process.dto.resp.resource.ResourceDetailResp;
import cd.casic.ci.process.engine.constant.PipelineVariableConstant;
import cd.casic.ci.process.engine.manager.RunContextManager;
import cd.casic.ci.process.engine.runContext.BaseRunContext;
import cd.casic.ci.process.process.converter.AflManagerConverter;
import cd.casic.ci.process.process.dao.aflManager.AflInfoDao;
import cd.casic.ci.process.process.dataObject.aflManager.AflInfo;
import cd.casic.ci.process.process.service.aflManager.AflInfoService;
import cd.casic.ci.process.process.service.resource.ResourceManagerService;
import cd.casic.ci.process.util.SftpUploadUtil;
import cd.casic.framework.commons.exception.ServiceException;
import cd.casic.framework.commons.exception.enums.GlobalErrorCodeConstants;
import cd.casic.module.machine.dal.dataobject.MachineInfoDO;
import cd.casic.module.machine.utils.CryptogramUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import de.danielbechler.util.Collections;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import java.time.Duration;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @author HopeLi
 * @version v1.0
 * @ClassName TargetVersionServiceImpl
 * @Date: 2025/5/17 15:20
 * @Description:
 */
@Service
@Slf4j
public class AflInfoServiceImpl extends ServiceImpl<AflInfoDao, AflInfo> implements AflInfoService {
    private static final String remoteFilePath = "/home/casic/706/yunqi/";

    @Resource
    private RunContextManager runContextManager;

    @Resource
    private ResourceManagerService resourceManagerService;


    @Override
    public String saveAflInfo(AflManagerReq req) throws SftpUploadUtil.SftpUploadException {
        if (StringUtils.isEmpty(req.getPipelineId()) || StringUtils.isEmpty(req.getTaskId())){
            throw new ServiceException(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR.getCode(),"pipelineId或者taskId不能为空");
        }

        BaseRunContext runContext = runContextManager.getContext(req.getPipelineId());
        if (ObjectUtils.isEmpty(runContext)){
            throw new ServiceException(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR.getCode(),"未找到运行上下文");
        }
        String resourceId = runContext.getGlobalVariables().get(PipelineVariableConstant.AFL_RESOURCE_MANAGER_ID_KEY) instanceof String ? ((String) runContext.getGlobalVariables().get(PipelineVariableConstant.AFL_RESOURCE_MANAGER_ID_KEY)) : null;

        if (StringUtils.isEmpty(resourceId)){
            throw new ServiceException(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR.getCode(),"未找到资源");
        }

        ResourceDetailResp resourceById = resourceManagerService.findResourceDetailById(resourceId);
        if (resourceById == null || resourceById.getMachineInfo() == null) {
            throw new ServiceException(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR.getCode(),"资源信息错误");
        }

        MachineInfoDO resourceMachine = resourceById.getMachineInfo();
        resourceMachine.setPassword(CryptogramUtil.doDecrypt(resourceMachine.getPassword()));
        AflInfo aflInfo = SftpUploadUtil.downloadFileSftpForInputStreamAndSetAflInfo(resourceMachine.getHostIp(), resourceMachine.getSshPort(), resourceMachine.getUsername(), resourceMachine.getPassword(),null, remoteFilePath + "PIP_" + req.getPipelineId() + "/ai_afl/default/fuzzer_stats");
        //获取远程文件流，并保存到数据库
        List<String> sourceFilePaths = new ArrayList<>();
        sourceFilePaths.add(remoteFilePath + "PIP_" + req.getPipelineId() + "/ai_afl/default/fuzzer_stats");
        Map<String, byte[]> stringMap = SftpUploadUtil.copyRemoteFilesToByteArray(resourceMachine.getHostIp(), resourceMachine.getSshPort(), resourceMachine.getUsername(), resourceMachine.getPassword(), null, sourceFilePaths);

        aflInfo.setFileContent(stringMap.get(sourceFilePaths.get(0)));
        aflInfo.setPipelineId(req.getPipelineId());
        if (!StringUtils.isEmpty(req.getTaskId())){
            aflInfo.setTaskId(req.getTaskId());
        }
        if (!StringUtils.isEmpty(req.getPipelineHistoryId())){
            aflInfo.setPipelineHistoryId(req.getPipelineHistoryId());
        }
        aflInfo.setGroupIdentifier(req.getGroupIdentifier());
        baseMapper.insert(aflInfo);

        return aflInfo.getGroupIdentifier();
    }

    @Override
    public void updateHistoryPipelineIdByAflInfo(AflManagerReq req) {
        if (!StringUtils.isEmpty(req.getGroupIdentifier())){
            throw new ServiceException(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR.getCode(),"groupIdentifier不能为空");
        }
        QueryWrapper<AflInfo> wrapper = new QueryWrapper<>();
        wrapper.eq("group_identifier", req.getGroupIdentifier());
        List<AflInfo> aflInfos = baseMapper.selectList(wrapper);
        if (!Collections.isEmpty(aflInfos)){
            aflInfos.forEach(o->{
                o.setPipelineHistoryId(req.getPipelineHistoryId());
            });
        }
        baseMapper.updateBatch(aflInfos);
    }

    @Override
    public AflInfoResp findAflInfo(AflManagerReq req) throws SftpUploadUtil.SftpUploadException {
        if (StringUtils.isEmpty(req.getPipelineId()) || StringUtils.isEmpty(req.getTaskId())){
            throw new ServiceException(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR.getCode(),"pipelineId或者taskId不能为空");
        }

        BaseRunContext runContext = runContextManager.getContext(req.getPipelineId());
        if (ObjectUtils.isEmpty(runContext)){
            throw new ServiceException(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR.getCode(),"未找到运行上下文");
        }
        String resourceId = runContext.getGlobalVariables().get(PipelineVariableConstant.AFL_RESOURCE_MANAGER_ID_KEY) instanceof String ? ((String) runContext.getGlobalVariables().get(PipelineVariableConstant.AFL_RESOURCE_MANAGER_ID_KEY)) : null;

        if (StringUtils.isEmpty(resourceId)){
            throw new ServiceException(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR.getCode(),"未找到资源");
        }

        ResourceDetailResp resourceById = resourceManagerService.findResourceDetailById(resourceId);
        if (resourceById == null || resourceById.getMachineInfo() == null) {
            throw new ServiceException(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR.getCode(),"资源信息错误");
        }

        MachineInfoDO resourceMachine = resourceById.getMachineInfo();
        String password = CryptogramUtil.doDecrypt(resourceMachine.getPassword());
        resourceMachine.setPassword(password);
        AflInfo aflInfo = SftpUploadUtil.downloadFileSftpForInputStreamAndSetAflInfo(resourceMachine.getHostIp(), resourceMachine.getSshPort(), resourceMachine.getUsername(), resourceMachine.getPassword(),null, remoteFilePath + "PIP_" + req.getPipelineId() + "/ai_afl/default/fuzzer_stats");

        return AflManagerConverter.INSTANCE.toAflInfoResp(aflInfo);
    }

    @Override
    public List<AflInfoResp> findAflInfoListByHistory(AflManagerReq req) {
        QueryWrapper<AflInfo> wrapper = new QueryWrapper<>();
        if (!ObjectUtils.isEmpty(req.getId())){
            wrapper.eq("id",req.getId());
        }
        if (!ObjectUtils.isEmpty(req.getPipelineId())){
            wrapper.eq("pipeline_id",req.getPipelineId());
        }
        if (!ObjectUtils.isEmpty(req.getPipelineHistoryId())){
            wrapper.eq("pipeline_history_id",req.getPipelineHistoryId());
        }
        if (!ObjectUtils.isEmpty(req.getTaskId())){
            wrapper.eq("task_id",req.getTaskId());
        }
        if (!ObjectUtils.isEmpty(req.getGroupIdentifier())){
            wrapper.eq("group_identifier",req.getGroupIdentifier());
        }

        List<AflInfo> aflInfos = baseMapper.selectList(wrapper);
        if (ObjectUtils.isEmpty(aflInfos)){
            return new ArrayList<>(0);
        }

        return AflManagerConverter.INSTANCE.toAflInfoRespList(aflInfos);
    }

    @Override
    public AflBaseInfoResp findAflBaseInfoList(AflManagerReq req) throws SftpUploadUtil.SftpUploadException {
        AflBaseInfoResp resp = new AflBaseInfoResp();
        BaseRunContext taskRunContext = runContextManager.getContext(req.getTaskId());
        if (ObjectUtils.isEmpty(taskRunContext)){
            throw new ServiceException(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR.getCode(),"未找到task运行上下文");
        }
        LocalDateTime startTime = taskRunContext.getStartTime();
        LocalDateTime endTime = taskRunContext.getEndTime();

        if (ObjectUtils.isEmpty(startTime) && ObjectUtils.isEmpty(endTime)){
            resp.setStatus("1");
        }else if (!ObjectUtils.isEmpty(startTime) && ObjectUtils.isEmpty(endTime)){
            resp.setStatus("2");
            resp.setCreateTime(startTime);
            // 计算时间差（分钟）
            Duration duration = Duration.between(startTime, LocalDateTime.now());
            int minutesDifference = Math.toIntExact(Math.abs(duration.toMinutes()));
            resp.setDurationTime(minutesDifference);
        }else if (!ObjectUtils.isEmpty(startTime) && !ObjectUtils.isEmpty(endTime)){
            resp.setStatus("3");
            resp.setCreateTime(startTime);
            // 计算时间差（分钟）
            Duration duration = Duration.between(startTime, endTime);
            int minutesDifference = Math.toIntExact(Math.abs(duration.toMinutes()));
            resp.setDurationTime(minutesDifference);
        }

        String dockerName = taskRunContext.getGlobalVariables().get(PipelineVariableConstant.IMAGE_NAME) instanceof String ? ((String) taskRunContext.getGlobalVariables().get(PipelineVariableConstant.IMAGE_NAME)) : null;
        String applicationName = taskRunContext.getGlobalVariables().get(PipelineVariableConstant.EXECUTABLE_NAME_KEY) instanceof String ? ((String) taskRunContext.getGlobalVariables().get(PipelineVariableConstant.EXECUTABLE_NAME_KEY)) : null;
        resp.setDockerName(dockerName);
        resp.setApplicationName(applicationName);

        BaseRunContext pipelineCunContext = runContextManager.getContext(req.getPipelineId());
        if (ObjectUtils.isEmpty(pipelineCunContext)){
            throw new ServiceException(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR.getCode(),"未找到运行上下文");
        }
        String resourceId = pipelineCunContext.getGlobalVariables().get(PipelineVariableConstant.AFL_RESOURCE_MANAGER_ID_KEY) instanceof String ? ((String) pipelineCunContext.getGlobalVariables().get(PipelineVariableConstant.AFL_RESOURCE_MANAGER_ID_KEY)) : null;

        if (StringUtils.isEmpty(resourceId)){
            throw new ServiceException(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR.getCode(),"未找到资源");
        }

        ResourceDetailResp resourceById = resourceManagerService.findResourceDetailById(resourceId);
        if (resourceById == null || resourceById.getMachineInfo() == null) {
            throw new ServiceException(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR.getCode(),"资源信息错误");
        }
        MachineInfoDO resourceMachine = resourceById.getMachineInfo();
        //找出seed文件夹下的所有测试样例文件，计算数量
        List<String> files = SftpUploadUtil.listFilesInRemoteDirectory(
                resourceMachine.getHostIp(), resourceMachine.getSshPort(), resourceMachine.getUsername(), CryptogramUtil.doDecrypt(resourceMachine.getPassword()), null, remoteFilePath + "PIP_" + req.getPipelineId() + "/SEED/");

        if (!CollectionUtils.isEmpty(files)){
            resp.setTestCaseCount(files.size());
        }else {
            resp.setTestCaseCount(0);
        }

        return resp;
    }

}
