package com.css.simulation.resource.server.app.service;

import api.common.pojo.common.ResponseBodyVO;
import api.common.pojo.constants.DictConstants;
import api.common.pojo.enums.SceneEvaluationEnum;
import api.common.pojo.param.MinioParameter;
import api.common.pojo.param.scene.*;
import api.common.pojo.po.scene.SceneComplexityPO;
import api.common.pojo.po.scene.SceneEvaluationOperatePO;
import api.common.pojo.po.scene.SceneEvaluationRulePO;
import api.common.pojo.po.scene.SceneRiskPO;
import api.common.pojo.po.system.SceneEvaluationRuleScriptPO;
import api.common.util.LogUtil;
import api.common.util.ObjectUtil;
import api.common.util.StringUtil;
import api.common.util.TimeUtil;
import com.alibaba.druid.util.StringUtils;
import com.css.simulation.resource.server.infra.db.mysql.mapper.SceneComplexityMapper;
import com.css.simulation.resource.server.infra.db.mysql.mapper.SceneEvaluationRuleMapper;
import com.css.simulation.resource.server.infra.db.mysql.mapper.ScenePackageMapper;
import com.css.simulation.resource.server.infra.db.mysql.mapper.SceneRiskMapper;
import com.css.simulation.resource.server.infra.feign.service.FileDownService;
import com.css.simulation.resource.server.infra.feign.service.SceneService;
import com.css.simulation.resource.server.infra.feign.service.SchedulerService;
import com.css.simulation.resource.server.infra.oauth.AuthorizationHolder;
import com.css.simulation.resource.server.infra.util.AuthUtil;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

import static api.common.pojo.constants.DictConstants.*;

@Slf4j
@Service
public class SceneEvaluationRuleService {

    @Resource
    private ScenePackageMapper scenePackageMapper;

    @Resource
    private SceneEvaluationRuleMapper sceneEvaluationRuleMapper;

    @Resource
    private SceneComplexityMapper sceneComplexityMapper;

    @Resource
    private SceneRiskMapper sceneRiskMapper;

    @Resource
    private FileDownService fileDownService;

    @Resource
    private SceneService sceneService;

    @Resource
    private SchedulerService schedulerService;

    @SneakyThrows
    public int querySceneEvaluationRuleOnly(String ruleName, String ruleId) {
        return sceneEvaluationRuleMapper.querySceneEvaluationRuleOnly(ruleName, ruleId);
    }

    @SneakyThrows
    public ResponseBodyVO<String> uploadPyScriptAndSaveRule(MultipartFile file, SceneEvaluationRulePO sceneEvaluationRulePO) {

        boolean hasRuleId = StringUtil.isEmpty(sceneEvaluationRulePO.getRuleId());

        // 检查是否存在同名场景评价规则
        int repeatPyScriptAndSaveRuleCount = querySceneEvaluationRuleOnly(sceneEvaluationRulePO.getRuleName(),
                hasRuleId ? null : sceneEvaluationRulePO.getRuleId());
        if (repeatPyScriptAndSaveRuleCount > 0) {
            return new ResponseBodyVO<>(ResponseBodyVO.Response.CLIENT_FAILURE, "场景规则 " + sceneEvaluationRulePO.getRuleName() + " 已存在，请重新命名。");
        }
        // 新建或者是编辑时重新上传文件
        if ((hasRuleId) || sceneEvaluationRulePO.getUploadNewFile()) {
            String roleCode = AuthUtil.getCurrentUserRoleCode();
            if (!DictConstants.ROLE_CODE_ADMIN.equals(roleCode) && !DictConstants.ROLE_CODE_SYSADMIN.equals(roleCode)) {
                return new ResponseBodyVO<>(ResponseBodyVO.Response.CLIENT_FAILURE, "非管理员禁止上传文件");
            }
            // 检查文件内容是否合规
//            String pyStr = new String(file.getBytes(), StandardCharsets.UTF_8);
//            //1 校验 python 语法错误
//            String pylint = PythonUtil.pylint(pyStr, PythonUtil.C, PythonUtil.R, PythonUtil.W, PythonUtil.E0401, PythonUtil.E0601);
//            if (!pylint.contains(PythonUtil.PASS)) {
//                return new ResponseBodyVO<>(ResponseBodyVO.Response.CLIENT_FAILURE, "代码格式错误，请检查。");
//            }
            // 获取文件原本的名字
            String originName = file.getOriginalFilename();
            if (null == originName) {
                return new ResponseBodyVO<>(ResponseBodyVO.Response.CLIENT_FAILURE, "文件名为空，请检查！");
            }
            Integer nowTime = TimeUtil.getRq(new Date(), 0);
            String randomCode = StringUtil.getRandomCode();
            String fileName = "/" + DictConstants.SCENE_EVALUATION_RULE_PY_FILE + "/" + nowTime + "/" + randomCode + "/" + originName;
            ResponseBodyVO<String> response = fileDownService.upload(file, fileName);
            if (response.isStatus()) {
                sceneEvaluationRulePO.setScriptName(originName);
                sceneEvaluationRulePO.setScriptPath(fileName);
            } else {
                return new ResponseBodyVO<>(ResponseBodyVO.Response.CLIENT_FAILURE, "上传失败！");
            }
        }

        sceneEvaluationRulePO.setStatus(SCENE_IMPORT_STATUS_2);
        // 判断 ruleId 是否为空
        if (StringUtil.isEmpty(sceneEvaluationRulePO.getRuleId())) {
            // 创建
            saveSceneEvaluationRule(sceneEvaluationRulePO);
        } else {
            // 修改
            updateSceneEvaluationRule(sceneEvaluationRulePO);
        }
        return new ResponseBodyVO<>(ResponseBodyVO.Response.SUCCESS);
    }


    @SneakyThrows
    public ResponseBodyVO<String> uploadPyScriptAndSaveRuleByPath(SceneEvaluationRulePO sceneEvaluationRulePO, HttpServletRequest request) {
        if (ObjectUtil.isNull(sceneEvaluationRulePO)) {
            return new ResponseBodyVO<>(false, 500, "参数错误！", null);
        }
        String sceneType = sceneEvaluationRulePO.getRuleType();
        if (ObjectUtil.isNull(sceneType) || DictConstants.SCENE_GENERAL.equals(sceneType)) {
            return new ResponseBodyVO<>(false, 500, "参数错误！", null);
        }
        boolean createRule = StringUtil.isEmpty(sceneEvaluationRulePO.getRuleId());

        // 检查是否存在同名场景评价规则
        int repeatPyScriptAndSaveRuleCount = querySceneEvaluationRuleOnly(sceneEvaluationRulePO.getRuleName(),
                createRule ? null : sceneEvaluationRulePO.getRuleId());
        if (repeatPyScriptAndSaveRuleCount > 0) {
            return new ResponseBodyVO<>(ResponseBodyVO.Response.CLIENT_FAILURE, "场景规则 " + sceneEvaluationRulePO.getRuleName() + " 已存在，请重新命名。");
        }
        // 新建或者是编辑时重新上传文件
        if ((createRule) || sceneEvaluationRulePO.getUploadNewFile()) {
            String roleCode = AuthUtil.getCurrentUserRoleCode();
            if (!DictConstants.ROLE_CODE_ADMIN.equals(roleCode) && !DictConstants.ROLE_CODE_SYSADMIN.equals(roleCode)) {
                return new ResponseBodyVO<>(ResponseBodyVO.Response.CLIENT_FAILURE, "非管理员禁止上传文件");
            }
            sceneEvaluationRulePO.setStatus(SCENE_IMPORT_STATUS_0);
            // 判断 ruleId 是否为空
            if (StringUtil.isEmpty(sceneEvaluationRulePO.getRuleId())) {
                // 创建
                saveSceneEvaluationRule(sceneEvaluationRulePO);
            } else {
                // 修改
                updateSceneEvaluationRule(sceneEvaluationRulePO);
            }
            // 异步上传
            SceneEvaluationRuleScriptPO sceneEvaluationRuleScriptPO = new SceneEvaluationRuleScriptPO();
            sceneEvaluationRuleScriptPO.setRuleId(sceneEvaluationRulePO.getRuleId());
            sceneEvaluationRuleScriptPO.setLocalPath(sceneEvaluationRulePO.getLocalPath());
            String authorization = request.getHeader("Authorization");
            AuthorizationHolder.setAuthorization(authorization);
            sceneService.startImportEvaluationScript(sceneEvaluationRuleScriptPO);
            return new ResponseBodyVO<>(ResponseBodyVO.Response.SUCCESS);
        }
        updateSceneEvaluationRule(sceneEvaluationRulePO);
        return new ResponseBodyVO<>(ResponseBodyVO.Response.SUCCESS);
    }


    @SneakyThrows
    public void deleteSceneEvaluationRule(SceneEvaluationRulePO params) {
        // 先查
        SceneEvaluationRulePO oldSceneEvaluationRule = sceneEvaluationRuleMapper.querySceneEvaluationPyById(params.getRuleId());
        String scriptPath = null;
        if (oldSceneEvaluationRule != null) {
            scriptPath = oldSceneEvaluationRule.getScriptPath();
        }
        params.setIsDeleted("1");
        params.setModifyTime(TimeUtil.getNowForMysql());
        params.setModifyUserId(AuthUtil.getCurrentUserId());
        sceneEvaluationRuleMapper.updateSceneEvaluationRule(params);
        if (StringUtil.isNotEmpty(scriptPath)) {
            MinioParameter minioParameter = new MinioParameter();
            minioParameter.setObjectName(scriptPath);
            fileDownService.remove(minioParameter);
        }
        // 同步把使用该评分规则的测试包设为禁用
        scenePackageMapper.updateIsUnavailableBySceneEvaluationRuleId(params);
        LogUtil.delete();
    }


    /**
     * 查询场景评价规则列表
     */
    @SneakyThrows
    public List<SceneEvaluationRulePO> querySceneEvaluationRuleList(SceneEvaluationRuleParam params) {
        return sceneEvaluationRuleMapper.querySceneEvaluationRuleList(params);
    }

    /**
     * 查询复杂度脚本
     */
    @SneakyThrows
    public List<SceneEvaluationRulePO> queryEvaluationScript(SceneEvaluationScriptParam sceneEvaluationScriptParam) {
        return sceneEvaluationRuleMapper.queryEvaluationScript(sceneEvaluationScriptParam);
    }

    /**
     * 查询复杂度脚本类型
     */
    @SneakyThrows
    public boolean checkSceneEvaluationScript(String sceneEvaluationRuleId) {
        SceneEvaluationRulePO sceneEvaluationRulePO = sceneEvaluationRuleMapper.querySceneEvaluationPyById(sceneEvaluationRuleId);
        if (sceneEvaluationRulePO == null) {
            return false;
        }
        return StringUtils.equals(DictConstants.COMPLEXITY, sceneEvaluationRulePO.getRuleType());
    }


    @SneakyThrows
    public void saveSceneEvaluationRule(SceneEvaluationRulePO params) {
        params.setCreateTime(TimeUtil.getNowForMysql());
        params.setModifyTime(TimeUtil.getNowForMysql());
        params.setRuleId(StringUtil.getRandomUUID());
        params.setRuleCode(StringUtil.getRandomCode());
        params.setCreateUserId(AuthUtil.getCurrentUserId());
        params.setIsDeleted("0");
        sceneEvaluationRuleMapper.saveSceneEvaluationRule(params);
        LogUtil.insert();
    }

    @SneakyThrows
    public void updateSceneEvaluationRule(SceneEvaluationRulePO params) {
        params.setModifyTime(TimeUtil.getNowForMysql());
        params.setModifyUserId(AuthUtil.getCurrentUserId());
        sceneEvaluationRuleMapper.updateSceneEvaluationRule(params);
        LogUtil.update();
    }

    @SneakyThrows
    public List<SceneComplexityPO> querySceneEvaluationComplexityDetail(SceneEvaluationDetailParam param) {
        return sceneComplexityMapper.querySceneEvaluationComplexityDetail(param.getSceneId());
    }

    @SneakyThrows
    public List<SceneRiskPO> querySceneEvaluationRiskDetail(SceneEvaluationDetailParam param) {
        return sceneRiskMapper.querySceneEvaluationRiskDetail(param.getSceneId());
    }

    @SneakyThrows
    public SceneEvaluationOperatePO getSceneEvaluationFirst(SceneEvaluationForListParam param) {
        SceneComplexityPO sceneComplexityPO = new SceneComplexityPO();
        sceneComplexityPO.setMinComplexity(param.getMinComplexity());
        sceneComplexityPO.setMaxComplexity(param.getMaxComplexity());
        sceneComplexityPO.setComplexityLevel(SceneEvaluationEnum.matchLevelEnumByLevel(param.getComplexityLevel()));
        sceneComplexityPO.setSceneIdList(param.getSceneIdList());
        // 查询复杂度的符合条件的第一条数据
        List<SceneComplexityPO> sceneReferenceLibCSPOS = sceneComplexityMapper.selectSceneIdsByEvaluation(sceneComplexityPO);
        sceneReferenceLibCSPOS.forEach(po -> po.setComplexityLevel(SceneEvaluationEnum.matchLevelEnumByLevelValue(po.getComplexityLevel())));

        Map<String, SceneComplexityPO> complexityPOMap = sceneReferenceLibCSPOS.stream().collect(Collectors.toMap(SceneComplexityPO::getSceneId, Function.identity()));
        SceneRiskPO sceneRiskPO = new SceneRiskPO();
        sceneRiskPO.setMaxRisk(param.getMaxRisk());
        sceneRiskPO.setMinRisk(param.getMinRisk());
        sceneRiskPO.setRiskLevel(SceneEvaluationEnum.matchLevelEnumByLevel(param.getRiskLevel()));
        sceneRiskPO.setSceneIdList(param.getSceneIdList());
        // 查询复杂度的符合条件的第一条数据
        List<SceneRiskPO> sceneReferenceLibCRPOS = sceneRiskMapper.selectSceneIdsByEvaluation(sceneRiskPO);
        sceneReferenceLibCRPOS.forEach(po -> po.setRiskLevel(SceneEvaluationEnum.matchLevelEnumByLevelValue(po.getRiskLevel())));
        Map<String, SceneRiskPO> riskPOMap = sceneReferenceLibCRPOS.stream().collect(Collectors.toMap(SceneRiskPO::getSceneId, Function.identity()));
        return SceneEvaluationOperatePO.builder().sceneComplexityPOMap(complexityPOMap).sceneRiskPOMap(riskPOMap).build();
    }


    public void computeSceneEvaluation(SceneEvaluationComputeParam sceneEvaluationComputeParam) {
        schedulerService.computeSceneEvaluation(sceneEvaluationComputeParam);
    }
}
