package com.zbkj.service.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Maps;
import com.zbkj.common.dto.HuifuWalletTransferDto;
import com.zbkj.common.model.huifu.TaskResidual;
import com.zbkj.common.model.system.SystemUserLevel;
import com.zbkj.common.utils.SpringUtil;
import com.zbkj.service.dao.TaskResidualDao;
import com.zbkj.service.service.TaskResidualService;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;


@Service
public class TaskResidualServiceImpl extends ServiceImpl<TaskResidualDao, TaskResidual> implements TaskResidualService {

    @Resource
    private TaskResidualDao dao;

    private Logger log =  LoggerFactory.getLogger(TaskResidualServiceImpl.class);

    /**
     * <b> 查询所有记录，遍历反射获取方法重新加载，如果接口返回true删除当前记录 </b>
     * 该方法当期用于定时器定时处理，处理时采用异步，另开线程执行该业务
     * @param isNightlyRun 是否夜间执行，是：1，不是：""
     * @author ZXF
     * @create 2018/04/03 0003 15:54
     * @version
     * @注意事项 </b>
     */
    @Override
    public void disposeTaskResidualList(String isNightlyRun){
        Map<String, Object> columnMap = Maps.newHashMap();
        if(StringUtils.isNotEmpty(isNightlyRun)){
            columnMap.put("is_nightly_run",isNightlyRun);
        }
        List<TaskResidual> ctrList = dao.selectByMap(columnMap);
        for (TaskResidual ctr : ctrList){
            try {
                Thread.sleep(300);
                new Thread(()->{ //异步
                    applyReturnBooleanOfClassReflect(ctr);
                }).start();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * <b> 类反射 </b>
     *  只适用于方法返回布尔值的ComTaskResidual用
     *  如果这次跑成功就把该数据从数据库中删除
     *  如果传的是对象则必须只能有一个参数
     * @author ZXF
     * @create 2018/03/19 0019 14:06
     * @version
     * @注意事项 </b>
     */
    @Override
    public void applyReturnBooleanOfClassReflect(TaskResidual ctr){
        ClassLoader cls = Thread.currentThread().getContextClassLoader();
        String errEsg = "";
        try {
            Class c =  cls.loadClass(ctr.getClassName());
            String[] tArr = ctr.getParamTypeArr().split(",");
            String[] vArr = ctr.getParamValueArr().split(",", -1);
            Class[] csArr = new Class[ctr.getParamNum()];
            Object[] otArr = new Object[ctr.getParamNum()];
            for(int i = 0; i<ctr.getParamNum();i++){
                String tp = tArr[i];
                if("String".equals(tp)){
                    csArr[i] = String.class;
                    otArr[i] = String.valueOf(vArr[i]);
                }else if("int".equals(tp)){
                    csArr[i] = int.class;
                    otArr[i] = Integer.parseInt(vArr[i]);
                }else if("BigDecimal".equals(tp)){
                    csArr[i] = BigDecimal.class;
                    otArr[i] = new BigDecimal(vArr[i]);
                }else if("Long".equals(tp)){
                    csArr[i] = Long.class;
                    otArr[i] = Long.parseLong(vArr[i]);
                }else if("com.zbkj.common.dto.HuifuWalletTransferDto".equals(tp)){
                    csArr[i] = HuifuWalletTransferDto.class;
                    otArr[i] = JSONObject.parseObject(ctr.getParamValueArr(),Class.forName(ctr.getParamTypeArr()));
                }else{
                    csArr[i] = Object.class;
                    otArr[i] = JSONObject.parseObject(ctr.getParamValueArr(),Class.forName(ctr.getParamTypeArr()));
                }
            }
            Object o =  SpringUtil.getBean(c);
            Method method = o.getClass().getDeclaredMethod(ctr.getMethodName(),csArr);
            method.setAccessible(true);
            Object r = method.invoke(o, otArr);
            boolean ret = false;
            if (r != null&&r.getClass().equals(Boolean.class)){
                ret = (boolean)r;
            }else if (r != null&&r.getClass().equals(String.class)){
                ret = true;
            }
            if(ret){
                dao.deleteById(ctr.getId());
            }else{
                errEsg = "Apply Method Fail!!--------------------------";
            }
        } catch (ClassNotFoundException e) {
            errEsg = e.getMessage();
        } catch (IllegalAccessException e) {
            errEsg = e.getMessage();
        } catch (NoSuchMethodException e) {
            errEsg = e.getMessage();
        } catch (SecurityException e) {
            errEsg = e.getMessage();
        } catch (IllegalArgumentException e) {
            errEsg = e.getMessage();
        } catch (InvocationTargetException e) {
            errEsg = e.getMessage();
        }
        if(StringUtils.isNotEmpty(errEsg)){
            log.info("----------TaskResidual未成功任务反射执行（"+ctr.getAnnotation()+"）,ExceptionMessage："+errEsg);
        }
    }

    /**
     * <b> 创建一条接口为成功数据，等待定时器跑 </b>
     * @param methodName 方法名
     * @param annotation 注释
     * @param className 所在类的全路径
     * @param paramNum 参数个数
     * @param paramTypeArr 参数类型（多个用,隔开）
     * @param paramValueArr 参数值（多个用,隔开）
     * @author ZXF
     * @create 2018/04/03 0003 14:49
     * @version
     * @注意事项 </b>
     */
    @Override
    public void saveTaskResidual(String methodName, String annotation, String className, int paramNum, String paramTypeArr, String paramValueArr) {
        LambdaQueryWrapper<TaskResidual> taskResidualQueryWrapper = new LambdaQueryWrapper<>();
        taskResidualQueryWrapper.eq(TaskResidual::getMethodName, methodName);
        taskResidualQueryWrapper.eq(TaskResidual::getParamValueArr, paramValueArr);
        List<TaskResidual> list = dao.selectList(taskResidualQueryWrapper);

        if(list.size()>0){
            System.out.println("=======> 打回打回");
            return;
        }
        TaskResidual ctr = new TaskResidual(methodName
                ,annotation
                ,className
                ,paramNum
                ,paramTypeArr
                ,paramValueArr
                ,"0"
        );
        new Thread(()->{ //异步记录接口传输失败的接口信息，用于后续定时器从新跑接口，不参与实际业务所以另开线程处理
            try {
                dao.insert(ctr);
            }catch (Exception e){
                e.printStackTrace();
            }
        }).start();
    }

    /**
     * <b> 创建一条接口为成功数据，等待定时器跑(专用于晚间执行的定时任务) </b>
     * @param methodName 方法名
     * @param annotation 注释
     * @param className 所在类的全路径
     * @param paramNum 参数个数
     * @param paramTypeArr 参数类型（多个用,隔开）
     * @param paramValueArr 参数值（多个用,隔开）
     * @author ZXF
     * @create 2018/04/03 0003 14:49
     * @version
     * @注意事项 </b>
     */
    @Override
    public void saveTaskResidual2(String methodName, String annotation, String className, int paramNum, String paramTypeArr, String paramValueArr) {
        TaskResidual ctr = new TaskResidual(methodName
                ,annotation
                ,className
                ,paramNum
                ,paramTypeArr
                ,paramValueArr
                ,"1"
        );
        new Thread(()->{ //异步记录接口传输失败的接口信息，用于后续定时器从新跑接口，不参与实际业务所以另开线程处理
            try {
                dao.insert(ctr);
            }catch (Exception e){
                e.printStackTrace();
            }
        }).start();
    }

    public static void main(String[] args) {
        TaskResidualServiceImpl c = new TaskResidualServiceImpl();
        TaskResidual ctr = c.dao.selectById(1026392);
        c.applyReturnBooleanOfClassReflect(ctr);
        /*ComTaskResidual ctr = new ComTaskResidual("testReflect"
                ,"测试方法"
                ,"com.bcxin.ins.service.order.PolicyService"
                ,3
                ,"String"
                ,"呵呵"
        );*/
//        applyReturnBooleanOfClassReflect(ctr);
    }
}
