package com.ytpm.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.ytpm.advertise.enums.AdSourceTypeEnum;
import com.ytpm.agent.model.YtApp;
import com.ytpm.agent.model.YtPlatformBanned;
import com.ytpm.agent.model.YtPlatformDeblocking;
import com.ytpm.agent.model.YtPlatformUserApp;
import com.ytpm.agent.view.AgentAppClassView;
import com.ytpm.agent.view.AgentEnableAppView;
import com.ytpm.agent.view.AgentUserInfo;
import com.ytpm.app.model.YtDyzAdRecord;
import com.ytpm.app.model.YtDyzLoginRecord;
import com.ytpm.app.model.YtDyzUser;
import com.ytpm.custom.CustomField;
import com.ytpm.dao.AppMapper;
import com.ytpm.dao.DictMapper;
import com.ytpm.dao.RiskConfigMapper;
import com.ytpm.dao.RiskManageMapper;
import com.ytpm.dao.RiskUserMapper;
import com.ytpm.feign.AppFeign;
import com.ytpm.general.PageMeta;
import com.ytpm.general.RepMessage;
import com.ytpm.general.Result;
import com.ytpm.general.ResultTable;
import com.ytpm.handle.CustomerException;
import com.ytpm.irun.feign.IRunFeign;
import com.ytpm.risk.enums.BannedTypeEnum;
import com.ytpm.risk.enums.EffectNodeEnum;
import com.ytpm.risk.model.YtRiskConfig;
import com.ytpm.risk.model.YtRiskTemplate;
import com.ytpm.risk.param.RiskBannedListParam;
import com.ytpm.risk.param.RiskBannedParam;
import com.ytpm.risk.param.RiskConfigListParam;
import com.ytpm.risk.param.RiskConfigParam;
import com.ytpm.risk.param.RiskDeblockingListParam;
import com.ytpm.risk.param.RiskRelativeAppParam;
import com.ytpm.risk.param.RiskUserStatusParam;
import com.ytpm.risk.view.RiskBannedListView;
import com.ytpm.risk.view.RiskConfigListView;
import com.ytpm.risk.view.RiskConfigView;
import com.ytpm.risk.view.RiskDeblockingListView;
import com.ytpm.risk.view.RiskTemplateView;
import com.ytpm.service.RiskService;
import com.ytpm.util.FeignClientInvoker;
import com.ytpm.util.RedisService;
import com.ytpm.util.ReflectUtil;
import io.swagger.annotations.ApiModelProperty;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

@Slf4j(topic = "风控服务")
@Service
@RefreshScope
public class RiskServiceImpl extends ReflectUtil implements RiskService {

    @Autowired
    private FeignClientInvoker feignInvoker;
    @Value("${risk.banned.defaultLimit}")
    private Integer defaultLimit;
    @Value("${risk.banned.defaultReason}")
    private String defaultReason;
    @Resource
    private DictMapper  dictMapper;
    @Resource
    private RiskConfigMapper configMapper;
    @Resource
    private RiskUserMapper riskUserMapper;
    @Resource
    private RiskManageMapper riskManageMapper;
    @Value("${risk.banned.tips}")
    private String tips;
    @Resource
    private RedisService redisService;
    @Resource
    private AppMapper appMapper;
    /**
     * 查询配置字段选项
     */
    @Override
    public ResultTable<RiskConfigView> getRiskConfig(String appIds) {
        List<AgentAppClassView> viewList = configMapper.getAppClazz(appIds);
        List<RiskConfigView> configList = new ArrayList<>();
        try{
            for (AgentAppClassView view : viewList) {
                addConfigItem(Class.forName(view.getFullName()).getDeclaredFields(),configList,null);
            }
        }catch (Exception e){
            log.error(e.getMessage());
            throw new CustomerException(e.getMessage());
        }
        return ResultTable.resultTableOk(new PageInfo<RiskConfigView>(configList));
    }

    /**
     * 根据业务节点查询配置项
     */
    @Override
    public ResultTable<RiskConfigView> getFieldConfigByNode(Integer effectNode) {
        List<AgentAppClassView> viewList = configMapper.getAppClazz("");
        List<RiskConfigView> configList = new ArrayList<>();
        Set<String> clazzSet = viewList.stream().map(AgentAppClassView::getFullName).collect(Collectors.toSet());
        try{
            for (String fullName : clazzSet) {
                addConfigItem(Class.forName(fullName).getDeclaredFields(),configList,effectNode);
            }
        }catch (Exception e){
            log.error(e.getMessage());
            throw new CustomerException(e.getMessage());
        }
        return ResultTable.resultTableOk(new PageInfo<RiskConfigView>(configList));
    }

    /**
     * 添加配置项
     */
    private void addConfigItem(Field[] fields, List<RiskConfigView> configList, Integer effectNode) {
        RiskConfigView view;
        for (Field field : fields) {
            field.setAccessible(true);
            if((Objects.nonNull(effectNode) && field.getAnnotation(CustomField.class).node()!=99 &&
                    field.getAnnotation(CustomField.class).node() != effectNode)||
                    !field.isAnnotationPresent(CustomField.class)
            )continue;
            view = new RiskConfigView();
            view.setFieldName(field.getName());
            if(CharSequenceUtil.isNotBlank(field.getAnnotation(CustomField.class).value())){
                view.setDictList(dictMapper.getByTypeCode(field.getAnnotation(CustomField.class).value()));
            }
            view.setFieldDesc(field.getAnnotation(ApiModelProperty.class).value());
            configList.add(view);
        }
    }

    /**
     * 保存风控配置
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<?> saveConfig(RiskConfigParam param) {
        List<RiskConfigListParam> configList = param.getConfigList();
        if(CollUtil.isEmpty(param.getConfigList())){
            return Result.resultErr(RepMessage.COLLECTION_EMPTY);
        }
        List<YtRiskConfig> configs = new ArrayList<>();
        YtRiskConfig config;
        StringBuilder content = new StringBuilder();
        for (RiskConfigListParam listVO : configList) {
            listVO.setConfigId(IdUtil.fastSimpleUUID());
            config = new YtRiskConfig();
            BeanUtil.copyProperties(listVO, config);
            config.setChannelId(param.getChannelId());
            String format = String.format(config.getFieldDesc(), config.getConfigVal());
            if(CharSequenceUtil.isNotBlank(format)){
                content.append(format);
                if(configList.indexOf(listVO)!= (configList.size() - 1)){
                    content.append(",");
                }
            }
            configs.add(config);
        }
        configMapper.insertAll(configs);
        addTemplateAndRelative(param,content.toString(),configs);
        return Result.resultOk(RepMessage.SAVE_SUCCESS);
    }

    /**
     * 新增模版和关联配置
     */
    private void addTemplateAndRelative(RiskConfigParam param,String content,List<YtRiskConfig> configs) {
        YtRiskTemplate template = new YtRiskTemplate();
        BeanUtil.copyProperties(param,template);
        template.setTemplateId(IdUtil.fastSimpleUUID());
        template.setTemplateContent(content);
        template.setEnabled(0);
        template.setCreateUserId(param.getChannelId());
        template.setCreateTime(new Date());
        configMapper.saveTemplate(template);

        configMapper.addRelease(template.getTemplateId(),
                configs.stream().map(YtRiskConfig::getConfigId).collect(Collectors.toList()),
                param.getOperator(),param.getOperatorName()
        );
    }


    /**
     * 锁定用户禁止用户登录
     */
    @Override
    public Result<?> lockUser(String userId,String appId, AgentUserInfo userInfo) {
        //通过redis进行业务分离， 再各个子服务中进行锁定和解锁，解耦feign调用
        redisService.setTimeOutStr("lock_"+userId,appId,1000);
        RiskBannedParam param = new RiskBannedParam();
        param.setUserId(userId);
        param.setAppId(appId);
        param.setBannedReason(BannedTypeEnum.CHANNEL.getDesc()+"禁止登录");
        param.setOperatorName(userInfo.getNickName());
        param.setOperator(userInfo.getUserId());
        param.setAgentId(userInfo.getUserId());
        param.setBannedType(BannedTypeEnum.CHANNEL.getCode());
        addBannedRecord(Collections.singletonList(userId),param);
        //预设24小时过期key 用于解锁用户
        redisService.setTimeOutHoursStr("unlock_"+userId,appId,24);
        return Result.resultOk(RepMessage.LOCK_USER_SUCCESS);
    }

    /**
     * 封禁用户
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Result<?> banned(RiskBannedParam param) {
        redisService.setTimeOutStr("lock_"+param.getUserId(),param.getAppId(),1000);
        addBannedRecord(Collections.singletonList(param.getUserId()),param);
        //预设24小时过期key 用于解锁用户
        redisService.setTimeOutHoursStr("unlock_"+param.getUserId(),param.getAppId(),param.getBannedLimit() * 24L);
        return Result.resultOk(RepMessage.ALREADY_RISK_USER);
    }

    /**
     * 查询风控配置列表
     */
    @Override
    public ResultTable<RiskConfigListView> getRiskConfigList(RiskConfigParam param) {
        PageHelper.startPage(param.getPage(),param.getLimit());
        return ResultTable.resultTableOk(new PageInfo<RiskConfigListView>(configMapper.getRiskConfigList(param)));
    }

    /**
     * 查询风控记录
     */
    @Override
    public ResultTable<RiskBannedListView> bannedList(RiskBannedListParam param) {
        PageHelper.startPage(param.getPage(),param.getLimit());
        List<RiskBannedListView> bannedList = riskManageMapper.getBannedList(param);
        if(CollUtil.isNotEmpty(bannedList)){
//            setBannedLoginInfo(bannedList);
        }
        return ResultTable.resultTableOk(new PageInfo<RiskBannedListView>(bannedList));
    }


    /**
     * 查询解封记录
     */
    @Override
    public ResultTable<RiskDeblockingListView> deblockingList(RiskDeblockingListParam param) {
        PageHelper.startPage(param.getPage(),param.getLimit());
        List<RiskDeblockingListView> deblockingList = riskManageMapper.getDeblockingList(param);
        if(CollUtil.isNotEmpty(deblockingList)){
//            setDeblockLoginInfo(deblockingList,param);
        }
        return ResultTable.resultTableOk(new PageInfo<RiskDeblockingListView>(deblockingList));
    }

    /**
     * 修改用户状态
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<?> changeUserStatus(RiskUserStatusParam param) {
        //如果原账号状态正常且本次操作状态不正常
        modifyAppUserInfo(param.getUserId(),param);
        return Result.resultOk(RepMessage.USER_STATUS_MODIFY);
    }

    /**
     * 风控配置关联应用
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<?> relativeApp(RiskRelativeAppParam param) {
        List<AgentEnableAppView> appList = param.getAppList();
        if(CollUtil.isEmpty(appList)){
            return Result.resultErr(RepMessage.COLLECTION_EMPTY);
        }
        riskManageMapper.deleteRelatives(param.getTemplateId());
        riskManageMapper.relativeApps(param);
        return Result.resultOk(RepMessage.RELATIVE_APP_SUCCESS);
    }

    /**
     * 启用或关闭风控配置
     */
    @Override
    public Result<?> isEnabledConfig(String templateId, String userId) {
        YtRiskTemplate template = configMapper.selectOneTemplate(templateId);
        if(Objects.isNull(template)){
            return Result.resultErr(RepMessage.OBJECT_NOT_EXIST);
        }
        Integer enabled = template.getEnabled();

        YtRiskTemplate newTemp = new YtRiskTemplate();
        newTemp.setTemplateId(templateId);
        newTemp.setUpdateUserId(userId);
        newTemp.setUpdateTime(new Date());
        newTemp.setEnabled(enabled == 0?1:0);
        configMapper.updateByTempId(newTemp);
        return Result.resultOk(RepMessage.MODIFY_SUCCESS);
    }

    /**
     * 风控配置模板详情
     */
    @Override
    public Result<RiskTemplateView> templateView(String templateId, String channelId) {
        return Result.resultObjOk(configMapper.getTemplateView(templateId,channelId));
    }

    /**
     * 修改风控配置模版
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<?> updateConfig(RiskConfigParam param) {
        YtRiskTemplate old = configMapper.selectOneTemplate(param.getTemplateId());
        if(Objects.isNull(old)){
            return Result.resultErr(RepMessage.OBJECT_NOT_EXIST);
        }
        //修改配置值
        List<RiskConfigListParam> configList = param.getConfigList();
        StringBuilder content = new StringBuilder();
        for (RiskConfigListParam listParam : configList) {
            YtRiskConfig config = new YtRiskConfig();
            config.setConfigId(listParam.getConfigId());
            config.setConfigVal(listParam.getConfigVal());
            configMapper.updateConfigVal(config);
            String format = String.format(listParam.getFieldDesc(), listParam.getConfigVal());
            if(CharSequenceUtil.isNotBlank(format)){
                content.append(format).append(",");
            }
        }
        //同步修改配置模版内容
        YtRiskTemplate template = new YtRiskTemplate();
        BeanUtil.copyProperties(param,template);
        template.setTemplateContent(content.toString());
        template.setUpdateTime(new Date());
        template.setUpdateUserId(param.getChannelId());
        configMapper.updateByTempId(template);
        return Result.resultOk(RepMessage.MODIFY_SUCCESS);
    }

    /**
     * 登录检查默认风控配置
     */
    @Override
    public Result<?> checkRisk(YtDyzUser dyzUser) {
        //查询当前用户今日有被解封则直接放行
        List<RiskDeblockingListView> vo = riskManageMapper.queryTodayDeblock(dyzUser.getUserId());
        if(CollUtil.isNotEmpty(vo)){
            return Result.resultOk(RepMessage.QUERY_SUCCESS);
        }
        RiskTemplateView view = configMapper.getByCode(dyzUser.getRiskCode());
        //如果启用了该配置 校验默认的风控配置
        if(1==view.getEnabled()){
            checkDefaultRiskConfig(dyzUser, view.getConfigList());
        }
        checkRisk322(dyzUser);
        //查询用户所在app是否配置其他风控规则
//        checkCustomRisk(dyzUser,EffectNodeEnum.LOGIN.getNode(),null);
        return Result.resultOk(RepMessage.QUERY_SUCCESS);
    }

    private String getTipsMsg(){
        String[] split = tips.split(",");
        return split[RandomUtil.randomInt(split.length)];
    }
    /**
     * 校验风控规则322
     */
    private void checkRisk322(YtDyzUser dyzUser) {
        RiskTemplateView view = configMapper.getByCode("322");
        //根据用户所属应用查询该应用母包openid查询用户信息
        YtApp ytApp = appMapper.selectRiskApp(dyzUser.getAppId());
        YtPlatformUserApp userApp =  appMapper.selectParentApp(ytApp.getSuperiorId());
        Object o = feignInvoker.invoke(userApp.getServiceName(),"queryByOpenid",dyzUser.getWxOpenId());
        List<YtDyzUser> dyzUsers = JSONArray.parseArray(JSON.toJSONString(o), YtDyzUser.class);

        List<RiskConfigView> configList = view.getConfigList();
        Map<String, String> configMap = configList.stream().collect(
                Collectors.toMap(RiskConfigView::getFieldName, RiskConfigView::getConfigVal));
        //判断同应用 UID生成数如果不小于配置数则触发规则校验
        int uidCount = Integer.parseInt(configMap.get("uidCount"));
        int days = Integer.parseInt(configMap.get("days"));
        //过滤该用户注册时间在三天内的渠道数
        long ditchCount = dyzUsers.stream().filter(
                s->(days>DateUtil.between(new Date(), s.getRegistryTime(),DateUnit.DAY))
        ).count();
        //三天内注册的渠道数小于预设的渠道数通过校验，否则风控锁定用户
        if(ditchCount<uidCount)return;
        riskLockUser(dyzUser,"322","系统判定重复刷单用户限制",getTipsMsg());
    }

    /**
     * 校验默认风控配置， 固定配置值不改
     *  days ?天内为1
     *  ipPrefix IP前?段为4
     *  ipSameCount 同IP登录数量为>2
     */
    private void checkDefaultRiskConfig(YtDyzUser dyzUser, List<RiskConfigView> configList) {
        //封装配置值map
        Map<String, String> configMap = configList.stream().collect(
                Collectors.toMap(RiskConfigView::getFieldName, RiskConfigView::getConfigVal));
        //封装用户值map
        List<YtDyzLoginRecord> recordList = dyzUser.getLoginRecordList();
        Calendar instance = Calendar.getInstance();
        instance.add(Calendar.DATE, -Integer.parseInt(configMap.get("days")));
        Date yesterday = instance.getTime();
        //拿到同IP登录次数
        List<YtDyzLoginRecord> dayLoginList = recordList.stream().filter(
                s -> s.getLoginTime().after(yesterday) &&
                        s.getLoginTime().before(new Date())).collect(Collectors.toList());
        int intCount = 0;
        if(!dayLoginList.isEmpty()){
            for (YtDyzLoginRecord loginRecord : dayLoginList) {
                loginRecord.setLoginIp(loginRecord.getLoginIp()
                        .substring(0,Integer.parseInt(configMap.get("ipPrefix"))));
            }
            intCount = Math.toIntExact(dayLoginList.stream().map(YtDyzLoginRecord::getLoginIp).distinct().count());
        }
        int ipSameCount = Integer.parseInt(configMap.get("ipSameCount"));
        if(intCount > ipSameCount){//校验同IP登录次数大于预设值，锁定用户
            riskLockUser(dyzUser,"313","系统判定登录IP限制",getTipsMsg());
        }
    }

    /**
     * 根据appId查询应用配置模版
     */
    @Override
    public Result<RiskTemplateView> getAppConfig(String appId) {
        return Result.resultObjOk(configMapper.getAppConfig(appId));
    }

    /**
     * 根据风控编码获取风控配置
     */
    @Override
    public Result<RiskTemplateView> getRiskByCode(String code) {
        return Result.resultObjOk(configMapper.getByCode(code));
    }

    /**
     * 校验广告的默认风控配置
     */
    @Override
    public Result<?> checkAdRisk(YtDyzUser dyzUser) {
        //查询当前用户今日有被解封则直接放行
        List<RiskDeblockingListView> vo = riskManageMapper.queryTodayDeblock(dyzUser.getUserId());
        if(CollUtil.isNotEmpty(vo)){
            return Result.resultOk(RepMessage.QUERY_SUCCESS);
        }
        YtApp ytApp = appMapper.selectRiskApp(dyzUser.getAppId());
        YtPlatformUserApp userApp =  appMapper.selectParentApp(ytApp.getSuperiorId());
        Object o = feignInvoker.invoke(userApp.getServiceName(),"adRecords",dyzUser.getUserId(),AdSourceTypeEnum.rewarded_video.getAdSourceType());
        JSONObject object = JSON.parseObject(JSON.toJSONString(o));
        List<YtDyzAdRecord> adRecords = JSONArray.parseArray(object.getString("data"), YtDyzAdRecord.class);
        if(CollUtil.isEmpty(adRecords)){
            return Result.resultOk(RepMessage.QUERY_SUCCESS);
        }
        //过滤出当日的激励视频数据 按照时间正序排以便筛选每日前几条激励视频
        adRecords = adRecords.stream().filter(s->
            DateUtil.isSameDay(DateUtil.parse(s.getFinishTime()), new Date())
        ).sorted(Comparator.comparing(YtDyzAdRecord::getFinishTime)).collect(Collectors.toList());
        //校验风控742规则
        RiskTemplateView ecpmLimit= configMapper.getByCode(dyzUser.getAppId()+"-742");
        checkRisk742(ecpmLimit,dyzUser,adRecords);
        //校验风控746规则
        if(!adRecords.isEmpty() && adRecords.size()>1){
            checkRisk746(dyzUser,adRecords);
        }
        return Result.resultOk(RepMessage.QUERY_SUCCESS);
    }

    /**
     * 校验用户自定义风控规则
     */
    private void checkCustomRisk(YtDyzUser dyzUser, Integer node, List<YtDyzAdRecord> data) {
        List<RiskTemplateView> templateList = configMapper.getCustomTempConfig(
                dyzUser.getAppId(), node);
        if(CollUtil.isNotEmpty(templateList)){
            //校验用户的其他规则配置
            for (RiskTemplateView templateView : templateList) {
                if(EffectNodeEnum.LOGIN.getNode().equals(node)){
                    checkCondition(dyzUser, templateView);
                }else{
                    for (YtDyzAdRecord datum : data) {
                        checkCondition(datum, templateView);
                    }
                }
            }
        }
    }

    /**
     * 校验默认风控规则746
     */
    private void checkRisk746(YtDyzUser dyzUser, List<YtDyzAdRecord> records) {
        RiskTemplateView revenue = configMapper.getByCode(dyzUser.getAppId()+"-746");
        if(revenue.getEnabled()!=1)return;
        Map<String, String> revenueMap = revenue.getConfigList().stream().collect(
                Collectors.toMap(RiskConfigView::getFieldName, RiskConfigView::getConfigVal));
        List<YtDyzAdRecord> revenues = records.stream().filter(
                s -> Objects.nonNull(s.getRevenue())&&(s.getRevenue().compareTo(BigDecimal.ZERO)) > 0).collect(Collectors.toList());
        int incomeCount = 0;
        incomeCount = revenues.isEmpty()?incomeCount:records.size();
        //判断当日获得收益的广告达到预设数值，触发风控规则
        int rewardCount = Integer.parseInt(revenueMap.get("rewardCount"));
        if(incomeCount>=rewardCount){
            BigDecimal income = new BigDecimal(revenueMap.get("income"));
            //获取最先的两条
            BigDecimal reduce = revenues.stream().map(YtDyzAdRecord::getRevenue).reduce(BigDecimal.ZERO, BigDecimal::add);
            if(reduce.compareTo(income)<0){
                riskLockUser(dyzUser, "746","系统判定小于最低收益限制",getTipsMsg());
            }
        }
    }

    /**
     * 校验默认风控规则742
     */
    private void checkRisk742(RiskTemplateView ecpmLimit,YtDyzUser dyzUser,List<YtDyzAdRecord> records) {
        if(ecpmLimit.getEnabled()!=1)return;
        Map<String, String> limitMap = ecpmLimit.getConfigList().stream().collect(
                Collectors.toMap(RiskConfigView::getFieldName, RiskConfigView::getConfigVal));
        int adCount = 0;
        adCount = records.isEmpty()?adCount:records.size();
        ++adCount;
        //判断当日观看视频数已经达到风控条件预设的视频数
        int firstAdCount = Integer.parseInt(limitMap.get("firstAdCount"));
        if(adCount>=firstAdCount){
            //过滤出ecpm值小于预设值的视频数
            int ecpm = Integer.parseInt(limitMap.get("ecpm"));
            long count = records.stream().filter(
                    s -> Objects.nonNull(s.getEcpm())&&(s.getEcpm().compareTo(BigDecimal.valueOf(ecpm))) < 0).count();
            int exact = Math.toIntExact(count);
            //判断小于预设值的视频数超出预设次数
            int haveCount = Integer.parseInt(limitMap.get("haveCount"));
            if(exact>haveCount){
                riskLockUser(dyzUser,"742","系统判定激励视频ecpm值过低",getTipsMsg());
            }
        }
    }

    /**
     * 风控锁定用户
     */
    private void riskLockUser(YtDyzUser dyzUser, String riskCode, String tempName, String errMsg) {
        //增加用户风控记录
        RiskBannedParam param = new RiskBannedParam();
        param.setUserId(dyzUser.getUserId());
        param.setAppId(dyzUser.getAppId());
        param.setDitChId(dyzUser.getDitchId());
        param.setBannedLimit(24);
        param.setOperator("系统风控");
        param.setBannedReason(tempName);
        param.setOperatorName("系统风控");
        param.setAgentId(configMapper.getApplicationOwner(dyzUser.getAppId()));
        addBannedRecord(Collections.singletonList(dyzUser.getUserId()),param);
        //修改为解锁用户存入redis 24小时后进行解锁
        redisService.setTimeOutHoursStr("unlock_"+dyzUser.getUserId(),dyzUser.getAppId(), 24);
        throw new CustomerException(errMsg);
    }

    /**
     * 修改用户信息
     */
    private void modifyAppUserInfo(String userId, RiskUserStatusParam param) {
        YtDyzUser appUser = new YtDyzUser();
        appUser.setUserId(param.getUserId());
        appUser.setUserStatus(param.getUserStatus());
        switch (param.getUserStatus()){
            case 2:
                appUser.setRiskReason(param.getReason());
                //1s锁定用户，并设置 24小时后进行解锁
                redisService.setTimeOutStr("lock_"+userId,param.getAppId(),1000);
                redisService.setTimeOutHoursStr("unlock_"+userId,param.getAppId(),24);
                break;
            case 3: //增加封禁记录
                RiskBannedParam bannedParam = new RiskBannedParam();
                BeanUtil.copyProperties(param, bannedParam);
                bannedParam.setUserId(param.getUserId());
                bannedParam.setBannedReason(param.getReason());
                appUser.setRiskReason(param.getReason());
                addBannedRecord(Collections.singletonList(userId),bannedParam);
                //1s锁定用户，并设置 24小时后进行解锁
                redisService.setTimeOutStr("lock_"+userId,param.getAppId(),1000);
                redisService.setTimeOutHoursStr("unlock_"+userId,param.getAppId(),param.getBannedLimit()*24L);
                break;
            default: //解禁
                YtPlatformBanned banned = riskManageMapper.getLastBanned(userId);
                if(Objects.nonNull(banned)){
                    addDeblockingRecord(banned,param);
                }
                redisService.setTimeOutStr("unlock_"+userId,param.getAppId(),1000);
        }
    }

    /**
     * 增加解禁记录
     */
    private void addDeblockingRecord(YtPlatformBanned banned, RiskUserStatusParam param) {
        YtPlatformDeblocking deblocking = new YtPlatformDeblocking();
        deblocking.setDeblockingId(IdUtil.fastSimpleUUID());
        deblocking.setUserId(banned.getUserId());
        deblocking.setAppId(banned.getAppId());
        deblocking.setAgentId(param.getAgentId());
        deblocking.setOperator(param.getOperator());
        deblocking.setOperatorName(param.getOperatorName());
        deblocking.setBannedId(banned.getBannedId());
        deblocking.setDeblockingReason(param.getReason());
        deblocking.setDeblockingTime(new Date());
        riskManageMapper.addDeblockingRecord(deblocking);
    }

    /**
     * 增加封禁记录
     */
    private void addBannedRecord(List<String> userIdList,RiskBannedParam param) {
        YtPlatformBanned banned;
        for (String userId : userIdList) {
            banned = new YtPlatformBanned();
            banned.setBannedId(IdUtil.fastSimpleUUID());
            banned.setUserId(userId);
            banned.setAppId(param.getAppId());
            banned.setAgentId(param.getAgentId());
            if(Objects.nonNull(param.getDitChId())){
                banned.setChannelId(param.getDitChId().toString());
            }
            banned.setBannedLimit(Objects.isNull(param.getBannedLimit())?defaultLimit:param.getBannedLimit());
            banned.setBannedReason(StrUtil.isBlank(param.getBannedReason())?defaultReason:param.getBannedReason());
            banned.setBannedType(BannedTypeEnum.CHANNEL.getCode());
            banned.setBannedTime(new Date());
            banned.setOperator(param.getOperator());
            banned.setOperatorName(param.getOperatorName());
            riskUserMapper.addBannedRecord(banned);
        }
    }

    /**
     * 校验风控规则
     */
    private void checkCondition(Object obj,RiskTemplateView data) {
        List<RiskConfigView> configList = data.getConfigList();
        for (RiskConfigView configView : configList) {
            //校验配置类型对应字段 这里传入的Obj 就是风控粒度对象
            checkConfig(obj,configView);
        }
    }

    /**
     * 逐个校验配置  当前仅有好运答题王的用户
     */
    private void checkConfig(Object obj, RiskConfigView vo) {
        Field[] fields = obj.getClass().getDeclaredFields();
        List<Field> cFields = Arrays.stream(fields).filter(
                s -> s.getName().equals(vo.getFieldName())).collect(Collectors.toList());
        if(CollUtil.isEmpty(cFields)){
            throw new CustomerException("未匹配到准入条件字段请联系管理员！");
        }
        for (Field conditionField : cFields) {
            conditionField.setAccessible(true);
            try{
                //多选校验值包含 单选校验值相等
                Object o = conditionField.get(obj);
                switch (vo.getMulty()){
                    case 1:
                        checkContainsVal(o,vo.getConfigVal(), vo.getFieldDesc());
                        break;
                    case 2:
                        checkSameVal(o, vo.getConfigVal(), vo.getFieldDesc());
                        break;
                    default:
                        checkCompareVal(o, vo.getConfigVal(),vo.getFieldDesc(),vo.getMulty());
                }
            }catch (Exception e){
                throw new CustomerException(e.getMessage());
            }
        }

    }

    /**
     * 校验值大于
     * @param o 校验对象值
     * @param configVal 配置值
     * @param fieldDesc 字段描述
     * @param type 3- o > configVal  4- o < configVal
     */
    private void checkCompareVal(Object o, String configVal, String fieldDesc, int type) {
        BigDecimal a = new BigDecimal(o.toString());
        BigDecimal b = new BigDecimal(configVal);
        if(type == 3 && a.compareTo(b) < 1){
                throw new CustomerException(fieldDesc+"不符合准入条件！");
        }
        if(type == 4 && b.compareTo(a) < 1){
                throw new CustomerException(fieldDesc+"不符合准入条件！");
        }
    }

    /**
     * 校验值包含
     */
    private void checkContainsVal(Object o, String configVal, String fieldDesc) {
        try{
            String[] split = configVal.split(",");
            if(o instanceof Date){
                SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                Date begin = format.parse(split[0]);
                Date end = format.parse(split[1]);
                Date date = (Date) o;
                if(!DateUtil.isIn(date, begin, end)){
                    throw new CustomerException(fieldDesc+"不符合准入条件！");
                }
            }else{
                if(!Arrays.asList(split).contains(o.toString())){
                    throw new CustomerException(fieldDesc+"不符合准入条件！");
                }
            }
        }catch (Exception e){
            throw new CustomerException(e.getMessage());
        }
    }

    /**
     * 校验值相同
     */
    private void checkSameVal(Object o, String configVal,String desc) {
        if(o instanceof Integer && Integer.parseInt(configVal) != (Integer) o){
            throw new CustomerException(desc+"不符合准入条件！");
        }
        if(o instanceof String && !configVal.equals(String.valueOf(o))){
            throw new CustomerException(desc+"不符合准入条件！");
        }
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        try {
            if(o instanceof Date && !format.parse(configVal).equals(o)){
                throw new CustomerException(desc+"不符合准入条件！");
            }
        } catch (ParseException e) {
            throw new CustomerException(e.getMessage());
        }
    }

    @Override
    public List<YtPlatformBanned> queryBannedRecord(Date startTime, Date endTime,List<String> appIdList) {
        return riskManageMapper.queryBannedRecord(startTime, endTime,appIdList);
    }

    /**
     * 分组查询风控
     */
    @Override
    public List<YtPlatformBanned> queryBannedRecordGroupByUserId(Date startTime, Date endTime,List<String> appIdList) {
        return riskManageMapper.queryBannedRecordGroupByUserId(startTime, endTime,appIdList);
    }

    /**
     * 批量审核用户
     */
    @Override
    public void batchAudit(List<YtDyzUser> userList) {
        //查询这些用户当天的激励视频收益是否符合

    }
}
