package com.ruoyi.project.business.service.impl;

import static com.ruoyi.common.utils.jep.JEPUtils.AFTER_ANALYSIS_FORMULA;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.common.exception.ServiceErrorException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.MessageUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.ValidateUtils;
import com.ruoyi.common.utils.bean.BeanUtils;
import com.ruoyi.common.utils.jep.JEPUtils;
import com.ruoyi.project.business.domain.TpParaLibrary;
import com.ruoyi.project.business.domain.TpParaValidation;
import com.ruoyi.project.business.domain.TpParaValidationElevator;
import com.ruoyi.project.business.domain.bo.validation.ElevatorQueryBO;
import com.ruoyi.project.business.domain.vo.validataion.ParamCheckResultVO;
import com.ruoyi.project.business.dto.TpParaValidationDto;
import com.ruoyi.project.business.dto.TpParaValidationElevatorDto;
import com.ruoyi.project.business.enums.CalculateResultEnum;
import com.ruoyi.project.business.enums.DelFlagEnum;
import com.ruoyi.project.business.enums.JEPFuncEnum;
import com.ruoyi.project.business.enums.JEPLogicEnum;
import com.ruoyi.project.business.enums.JEPSplitEnum;
import com.ruoyi.project.business.enums.OperationFlagEnum;
import com.ruoyi.project.business.enums.ParamTypeEnum;
import com.ruoyi.project.business.mapper.TpParaValidationMapper;
import com.ruoyi.project.business.service.ITpParaLibraryService;
import com.ruoyi.project.business.service.ITpParaValidationElevatorService;
import com.ruoyi.project.business.service.ITpParaValidationService;
import com.ruoyi.project.system.domain.SysUser;
import com.ruoyi.project.system.service.ISysUserService;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import javax.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * 校验规则配置Service业务层处理
 *
 * @author ruoyi
 * @date 2024-04-29
 */
@Service
@Slf4j
public class TpParaValidationServiceImpl extends ServiceImpl<TpParaValidationMapper, TpParaValidation> implements
    ITpParaValidationService {

    public static final String CALCULATE_VALUE_TRUE = "1.0";

    @Resource
    private TpParaValidationMapper tpParaValidationMapper;

    @Resource
    private ITpParaValidationElevatorService iTpParaValidationElevatorService;

    @Resource
    private ISysUserService iSysUserService;

    @Resource
    private ITpParaLibraryService iTpParaLibraryService;

    /**
     * 查询校验规则配置
     *
     * @param id 校验规则配置主键
     * @return 校验规则配置
     */
    @Override
    public TpParaValidation selectTpParaValidationById(Long id) {
        return tpParaValidationMapper.selectTpParaValidationById(id);
    }

    /**
     * 查询校验规则配置列表
     *
     * @param tpParaValidation 校验规则配置
     * @return 校验规则配置
     */
    @Override
    public List<TpParaValidation> selectTpParaValidationList(TpParaValidation tpParaValidation) {
        return tpParaValidationMapper.selectTpParaValidationList(tpParaValidation);
    }

    /**
     * 新增校验规则配置
     *
     * @param tpParaValidation 校验规则配置
     * @return 结果
     */
    @Override
    public int insertTpParaValidation(TpParaValidation tpParaValidation) {
        tpParaValidation.setCreateTime(DateUtils.getNowDate());
        return tpParaValidationMapper.insertTpParaValidation(tpParaValidation);
    }

    /**
     * 修改校验规则配置
     *
     * @param tpParaValidation 校验规则配置
     * @return 结果
     */
    @Override
    public int updateTpParaValidation(TpParaValidation tpParaValidation) {
        tpParaValidation.setUpdateTime(DateUtils.getNowDate());
        return tpParaValidationMapper.updateTpParaValidation(tpParaValidation);
    }

    /**
     * 批量删除校验规则配置
     *
     * @param ids 需要删除的校验规则配置主键
     * @return 结果
     */
    @Override
    public int deleteTpParaValidationByIds(Long[] ids) {
        return tpParaValidationMapper.deleteTpParaValidationByIds(ids);
    }

    /**
     * 删除校验规则配置信息
     *
     * @param id 校验规则配置主键
     * @return 结果
     */
    @Override
    public int deleteTpParaValidationById(Long id) {
        return tpParaValidationMapper.deleteTpParaValidationById(id);
    }

    @Override
    public List<TpParaValidationDto> getTableList(TpParaValidationDto param) {
        List<TpParaValidationDto> dataList = tpParaValidationMapper.getTableList(param);
        if (dataList != null && dataList.size() > 0) {
            //取出所有的id
            List<Long> ids = dataList.stream().map(TpParaValidationDto::getId).collect(Collectors.toList());
            //取出所有的 创建人id，更新人id
            List<Long> createUserIds = dataList.stream().map(item -> Long.valueOf(item.getCreateBy()))
                .collect(Collectors.toList());
            List<Long> updateUserIds = dataList.stream().filter(item -> Objects.nonNull(item.getUpdateBy()))
                .map(item -> Long.valueOf(item.getUpdateBy())).collect(Collectors.toList());
            if (updateUserIds.size() > 0) {
                createUserIds.addAll(updateUserIds);
            }
            List<SysUser> userList = iSysUserService.listByIds(createUserIds);

            Map<Long, String> userMap = userList.stream()
                .collect(Collectors.toMap(SysUser::getUserId, SysUser::getNickName));
            //回显nickName
            if (userMap.size() > 0) {
                dataList.forEach(item -> {
                    if (StringUtils.isNotBlank(item.getCreateBy())) {
                        item.setCreateByName(userMap.get(Long.valueOf(item.getCreateBy())));
                    }
                    if (StringUtils.isNotBlank(item.getUpdateBy())) {
                        item.setUpdateByName(userMap.get(Long.valueOf(item.getUpdateBy())));
                    }
                });
            }

            List<TpParaValidationElevator> relationEnters = iTpParaValidationElevatorService
                .list(Wrappers.<TpParaValidationElevator>lambdaQuery()
                    .in(TpParaValidationElevator::getParaValidationId, ids)
                    .eq(TpParaValidationElevator::getDelFlag, DelFlagEnum.NORMAL.getValue()));
            Map<Long, List<TpParaValidationElevator>> countMap = relationEnters.stream()
                .collect(Collectors.groupingBy(TpParaValidationElevator::getParaValidationId));
            //设置 关联数量
            if (!countMap.isEmpty()) {
                dataList.forEach(item -> {
                    if (countMap.containsKey(item.getId())) {
                        item.setRelationNums(countMap.get(item.getId()).size());
                    }
                });
            }

            //回显公式
            List<String> paramsList = new ArrayList<>();

            for (TpParaValidationDto data : dataList) {
                paramsList.addAll(JEPUtils.getParam(data.getConditionFormula()));
            }
            paramsList = paramsList.stream().distinct().sorted(
                Comparator.comparingInt(String::length)
            ).collect(Collectors.toList());
            //查询所有的 参数
            List<TpParaLibrary> libraries = iTpParaLibraryService.list(
                Wrappers.<TpParaLibrary>lambdaQuery()
                    .in(TpParaLibrary::getParaCode, paramsList)
            );
            Map<String, String> codeToNameMap = new HashMap<>();
            if (libraries.size() > 0) {
                codeToNameMap = libraries.stream().collect(Collectors
                    .toMap(TpParaLibrary::getParaCode, TpParaLibrary::getParaName));
            }
            for (TpParaValidationDto data : dataList) {
                //替换逻辑判断符号 && ||
                data.setConditionFormula(
                    data.getConditionFormula().replace(JEPLogicEnum.OR.getLogicValue(), JEPLogicEnum.OR.getLogicKey()));
                data.setConditionFormula(data.getConditionFormula()
                    .replace(JEPLogicEnum.AND.getLogicValue(), JEPLogicEnum.AND.getLogicKey()));
                //替换 方法
                List<String> funcList = JEPUtils.getFuncShort(data.getConditionFormula());
                for (String func : funcList) {
                    String formula = data.getConditionFormula();
                    formula = formula.replace(JEPSplitEnum.FUNC_SPLIT_FLAG.getFuncKey(), "");
                    func = func.replace(JEPSplitEnum.FUNC_SPLIT_FLAG.getFuncKey(), "");
                    JEPFuncEnum jEPFuncEnum = JEPFuncEnum.fromByKey(func);
                    formula = formula.replace(func, jEPFuncEnum.getFuncValue());
                    data.setConditionFormula(formula);
                }
                //替换 参数
                String formula = data.getConditionFormula();
                List<String> params = JEPUtils.getParam(formula);
                for (String s : params) {
                    s = s.replace(JEPSplitEnum.PARAM_SPLIT_FLAG.getFuncKey(), "");
                    if (codeToNameMap.containsKey(s)) {
                        formula = formula.replace(s, codeToNameMap.get(s))
                            .replace(JEPSplitEnum.PARAM_SPLIT_FLAG.getFuncKey(), "");
                        data.setConditionFormula(formula);
                    }
                }

            }


        }

        return dataList;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int saveOrUpdate(TpParaValidationDto param) {
        Integer operationFlag = param.getOperationFlag();
        Date date = DateUtils.getNowDate();
        //校验唯一性
        boolean uniqueFlag = checkUnique(param.getCaseName(), param.getId(), operationFlag);
        if (!uniqueFlag) {
            // 规则名称唯一
            throw new ServiceErrorException(MessageUtils.message("validation.noQuine"));
        }
        if (param.getRelationEnters() == null || param.getRelationEnters().size() == 0) {
            //请选择 关联梯型
            throw new ServiceErrorException(MessageUtils.message("validation.pleaseSelectRelation"));
        }
        List<TpParaValidationElevator> relationEnters = param.getRelationEnters().stream().map(item -> {
            TpParaValidationElevator relationEnter = new TpParaValidationElevator();
            BeanUtils.copyBeanProp(relationEnter, item);
            return relationEnter;
        }).collect(Collectors.toList());

        //新增
        if (OperationFlagEnum.ADD.getFlag().equals(operationFlag)) {
            TpParaValidation tpParaValidation = new TpParaValidation();
            BeanUtils.copyBeanProp(tpParaValidation, param);
            tpParaValidation.setCreateBy(SecurityUtils.getStrUserId());
            tpParaValidation.setCreateTime(date);
            this.save(tpParaValidation);
            //relationEnters 来源是 tp_elevator_model
            relationEnters.forEach(item -> {
                item.setCreateBy(SecurityUtils.getStrUserId());
                item.setCreateTime(date);
                item.setParaValidationId(tpParaValidation.getId());
            });
            iTpParaValidationElevatorService.saveBatch(relationEnters);
        } else if (OperationFlagEnum.EDIT.getFlag().equals(operationFlag)) {
            //编辑
            TpParaValidation sqlData = getById(param.getId());
            if (sqlData == null) {
                //数据已被删除
                throw new ServiceErrorException(MessageUtils.message("common.dataDeleted"));
            }
            if (!ValidateUtils.allowUpdate(sqlData.getUpdateTime(), param.getUpdateTime())) {
                throw new ServiceErrorException(MessageUtils.message("common.dataUpdated"));
            }
            if (param.getDeleteRelationEnterIds() != null && param.getDeleteRelationEnterIds().size() > 0) {
                List<TpParaValidationElevator> deleteRelationEnters = iTpParaValidationElevatorService.list(Wrappers
                    .<TpParaValidationElevator>lambdaQuery()
                    .in(TpParaValidationElevator::getId, param.getDeleteRelationEnterIds())
                    .eq(TpParaValidationElevator::getDelFlag, DelFlagEnum.NORMAL.getValue()));
                if (deleteRelationEnters == null || deleteRelationEnters.size() == 0
                    || deleteRelationEnters.size() != param.getDeleteRelationEnterIds().size()) {
                    throw new ServiceErrorException(MessageUtils.message("common.relationDeleted"));
                }
                deleteRelationEnters.forEach(item -> {
                    item.setUpdateBy(SecurityUtils.getStrUserId());
                    item.setUpdateTime(date);
                    item.setDelFlag(DelFlagEnum.DELETED.getValue());
                });
                iTpParaValidationElevatorService.updateBatchById(deleteRelationEnters);
            }
            List<TpParaValidationElevator> addRealtionEnters = relationEnters.stream()
                .filter(item -> OperationFlagEnum.ADD.getFlag().equals(item.getOperationFlag()))
                .collect(Collectors.toList());
            if (addRealtionEnters.size() > 0) {
                addRealtionEnters.forEach(item -> {
                    item.setCreateTime(date);
                    item.setCreateBy(SecurityUtils.getStrUserId());
                    item.setParaValidationId(param.getId());
                });
                iTpParaValidationElevatorService.saveBatch(relationEnters);
            }
            TpParaValidation tpParaValidation = new TpParaValidation();
            BeanUtils.copyBeanProp(tpParaValidation, param);
            tpParaValidation.setUpdateTime(date);
            tpParaValidation.setUpdateBy(SecurityUtils.getStrUserId());
            this.updateById(tpParaValidation);
        } else {
            log.info("公式规则配置，操作符错误，operationFlag={}", operationFlag);
        }
        return 0;
    }

    @Override
    public TpParaValidationDto getInfoById(Long id) {
        TpParaValidationDto basicInfoDto = new TpParaValidationDto();
        TpParaValidation basicInfo = getById(id);
        if (Objects.isNull(basicInfo)) {
            //数据已被删除
            throw new ServiceErrorException(MessageUtils.message("common.dataDeleted"));
        }
        BeanUtils.copyBeanProp(basicInfoDto, basicInfo);

        List<TpParaValidationElevatorDto> relationEnters = iTpParaValidationElevatorService.initData(
            basicInfoDto.getId());
        basicInfoDto.setRelationEnters(relationEnters);
        Map<String, Object> result = JEPUtils.analysisFormula(basicInfo.getConditionFormula());
        basicInfoDto.setFormulaValueStr(result.get(AFTER_ANALYSIS_FORMULA).toString());
        return basicInfoDto;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int deleteById(Long id, Date updateTime) {
        TpParaValidation sqlData = getById(id);
        if (sqlData == null) {
            //数据已被删除
            throw new ServiceErrorException(MessageUtils.message("common.dataDeleted"));
        }
        if (!ValidateUtils.allowUpdate(sqlData.getUpdateTime(), updateTime)) {
            throw new ServiceErrorException(MessageUtils.message("common.dataUpdated"));
        }
        Date date = new Date();
        //step 1: 删除关联表
        List<TpParaValidationElevator> relationEnters = iTpParaValidationElevatorService.list(
            Wrappers.<TpParaValidationElevator>lambdaQuery()
                .in(TpParaValidationElevator::getParaValidationId, id)
                .eq(TpParaValidationElevator::getDelFlag, DelFlagEnum.NORMAL.getValue())
        );
        relationEnters.forEach(item -> {
            item.setUpdateTime(date);
            item.setUpdateBy(SecurityUtils.getStrUserId());
            item.setDelFlag(DelFlagEnum.DELETED.getValue());
        });
        iTpParaValidationElevatorService.updateBatchById(relationEnters);
        sqlData.setUpdateBy(SecurityUtils.getStrUserId());
        sqlData.setUpdateTime(date);
        sqlData.setDelFlag(DelFlagEnum.DELETED.getValue());
        updateById(sqlData);
        return 1;
    }

    @Override
    public int changeStatus(TpParaValidationDto param) {
        TpParaValidation sqlData = getById(param.getId());
        if (sqlData == null) {
            //数据已被删除
            throw new ServiceErrorException(MessageUtils.message("common.dataDeleted"));
        }
        if (!ValidateUtils.allowUpdate(sqlData.getUpdateTime(), param.getUpdateTime())) {
            throw new ServiceErrorException(MessageUtils.message("common.dataUpdated"));
        }
        sqlData.setStatus(param.getStatus());
        sqlData.setUpdateBy(SecurityUtils.getStrUserId());
        sqlData.setUpdateTime(new Date());
        updateById(sqlData);
        return 0;
    }

    boolean checkUnique(String caseName, Long id, Integer operationFlag) {
        List<TpParaValidation> list = list(Wrappers.<TpParaValidation>lambdaQuery()
            .eq(TpParaValidation::getCaseName, caseName)
            .eq(TpParaValidation::getDelFlag, DelFlagEnum.NORMAL.getValue()));

        if (OperationFlagEnum.ADD.getFlag().equals(operationFlag)) {
            return list == null || list.size() == 0;
        } else if (OperationFlagEnum.EDIT.getFlag().equals(operationFlag)) {

            if (list != null && list.size() > 0) {
                List<Long> ids = list.stream().map(TpParaValidation::getId).filter(itemId -> !itemId.equals(id))
                    .collect(Collectors.toList());
                return ids.size() == 0;
            }
        }
        return true;
    }

    @Override
    public List<ParamCheckResultVO> checkElevatorParam(ElevatorQueryBO queryBO) {
        List<ParamCheckResultVO> resultVOList = new ArrayList<>();
        List<TpParaValidation> tpParaValidationList = this.baseMapper.listByElevatorModelId(
            queryBO.getElevatorModelId());
        Map<String, Object> paramMap = new HashMap<>();
        if (CollUtil.isNotEmpty(queryBO.getParamList())) {
            queryBO.getParamList().forEach(item -> {
                if (!item.getParamType().equals(ParamTypeEnum.BAR.getCode())) {
                    paramMap.put(JEPSplitEnum.PARAM_SPLIT_FLAG.getFuncKey() + item.getParaCode()
                            + JEPSplitEnum.PARAM_SPLIT_FLAG.getFuncKey(),
                        item.getParaValue());
                }
            });
        }
        for (TpParaValidation tpParaValidation : tpParaValidationList) {
            Map<String, Object> calculate = JEPUtils.calculate(tpParaValidation.getConditionFormula(),
                paramMap, true);
            String result = String.valueOf(calculate.get(JEPUtils.CALCULATE_RESULT));
            String calculateValue = String.valueOf(calculate.get(JEPUtils.CALCULATE_VALUE));
            // 计算结果NG || 计算值不等于1.0 为校验失败
            if (CalculateResultEnum.NG.getValue().equals(result) || !calculateValue.equals(CALCULATE_VALUE_TRUE)) {
                ParamCheckResultVO convert = ParamCheckResultVO.convert(tpParaValidation);
                convert.setResult(result);
                convert.setCalculateValue(calculateValue);
                resultVOList.add(convert);
            }
            log.info("[{}] 计算结果  [{}]", tpParaValidation.getCaseName(), result);
        }
        return resultVOList;
    }
}
