package com.chinacreator.video.restful.service;

import java.net.URLEncoder;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import com.alibaba.druid.util.StringUtils;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.chinacreator.video.bean.OrderInfo;
import com.chinacreator.video.exception.BussinessException;
import com.chinacreator.video.mapper.ChannelDao;
import com.chinacreator.video.mapper.CommConfDao;
import com.chinacreator.video.mapper.DictionaryDao;
import com.chinacreator.video.restful.dao.CallSendDao;
import com.chinacreator.video.service.CommonService;
import com.chinacreator.video.service.HandleService;
import com.chinacreator.video.util.DesUtil;
import com.chinacreator.video.util.RedisService;
import com.chinacreator.video.util.URLUtil;
import com.chinacreator.video.validate.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * 短信订购
 * @author xu.zhou
 * @date 20220317
 */
@Service
public class CallSendLocalService {
	
    private Logger logger = LoggerFactory.getLogger("callSendco");

    @Autowired
    private TimetampValidate timetampValidate;

    @Autowired
    private IpValidate ipValidate;

    @Autowired
    private SignValidate signValidate;

    @Autowired
    private ChannelValidate channelValidate;

    @Autowired
    private MobValidate mobValidate;
    
    @Autowired
    private ChannelDao channelDao;
    
    @Autowired
    private CallSendDao callSendDao;
    
    @Autowired
    private BusiValidate busiValidate; 

    @Autowired
    private RedisService redisService;
    
	@Autowired
	private CommConfDao commConfDao;
	
	@Autowired
	private DictionaryDao dictionaryDao;
	
    @Autowired
    private HandleService handleService;
    
	@Autowired
	CommonService commonService;

    public void check(OrderInfo orderInfo) throws Exception {
    	//参数验证
    	paramValidate(orderInfo);
        //timetamp验证
        timetampValidate.validate(orderInfo.getTimestamp());
    	//cpid和spid验证
    	busiValidate.valiCpSp(orderInfo);
    	//是否能力平台产品验证
    	hassharespid(orderInfo);
        //渠道验证
        channelValidate.validate(orderInfo.getChannel());
        //IP验证
        ipValidate.volidate(orderInfo,"0");
        //签名验证
        signValidate.validate(orderInfo);
        //手机号码验证
        mobValidate.validate(orderInfo);
        //并发控制
        vistVali(orderInfo);
	    //token验证
        valitoken(orderInfo);     
    }
    
    /**
     * 验证是否为数字
     * @param vcode
     * @return
     */
    private boolean valinumer(String vcode){
    	vcode = vcode.replaceAll("[\\s-]", "");
        if(!vcode.matches("^[0-9]*$")){
        	return false;
        }
        
        return true;
    }
    
	/**
	 * 验证访问限制，1分钟内同一业务只能办理一次
	 * @param orderInfo
	 * @throws Exception
	 */
	private void vistVali(OrderInfo orderInfo) throws Exception {
		if("valicode".equals(orderInfo.getInvokeface())){
			String [] params = new String [5];
			params[0] = orderInfo.getChannel();
			params[1] = orderInfo.getUserid();
			params[2] = orderInfo.getCpid();
			params[3] = orderInfo.getSpid();
			params[4] = orderInfo.getType();
			if(commonService.vistVali2(params, orderInfo.getInvokeface())){
				throw new BussinessException("8001", "指定时间内重复请求");	
			}
		}
	}
    
    //token验证
    private void valitoken(OrderInfo orderInfo) throws Exception{
    	String key = "univideo_smsorder_"+orderInfo.getChannel()+orderInfo.getUserid()+orderInfo.getCpid()+orderInfo.getSpid();
    	//发送验证码
    	if("sendcode".equals(orderInfo.getInvokeface())){   

    	//校验验证码及订购	
    	}else if("valicode".equals(orderInfo.getInvokeface())){
    		/**
    		 * 验证token，以确保调此接口之前在sendcode接口已获取到验证码
    		 * 根据手机号码CPID，SPID获取redis的值，如果为空，可能未调sendcode接口，或者前者调用超过90秒，redis的值已失效
    		 * 微信腾讯渠道TX20_tencent，不比较token是否相同，因为他们没传token
    		 * 判断渠道是否要验证token，如果是，则添加到redis，videoif/order.do流程要验证
    		 */
    		//REDIS存放的token
    		String token = (String)redisService.get(key);
    		//token为空，或者已失效
    		if(StringUtils.isEmpty(token)){
    			throw new BussinessException("8999","验证码失效！");
    		}
    		//微信腾讯渠道没传token
    		if("TX20_tencent".equals(orderInfo.getChannel()) && StringUtils.isEmpty(orderInfo.getToken())){ 
    			orderInfo.setToken(token);
    		}
    		//输入参数token
    		String inputtoken = orderInfo.getToken();
    		//token不相同，
    		if(!inputtoken.equals(token)){
    			throw new BussinessException("8999","验证码失效。");
    		}   		
    	}
    }
    
    /**
     * 设置token
     * @param orderInfo
     */
    private void setToken(OrderInfo orderInfo){
    	String key = "univideo_smsorder_"+orderInfo.getChannel()+orderInfo.getUserid()+orderInfo.getCpid()+orderInfo.getSpid();
    	//发送验证码
    	if("sendcode".equals(orderInfo.getInvokeface())){   
    		/**
    		 * 发送短信验证码成功后在redis预设token，用于调接口凭证，在valicode接口要取出来验证
    		 */
    		String token = UUID.randomUUID().toString().replace("-", "");
    		orderInfo.setToken(token);
    		long expireTime = 6 * 60; //短信验证码的有效时间为5分钟，此处设置为6分钟
    		//把模拟TOKEN设置到redis，90秒的有效期
    		redisService.set(key, token, expireTime);
    	//校验验证码及订购	
    	}else if("valicode".equals(orderInfo.getInvokeface())){
    		//业务调videoif接口是否要token，订购时用
    		if("0".equals(orderInfo.getType())){
    			//查询表tb_istoken_conf是否要验证token
    			int res = callSendDao.isTokenVali(orderInfo.getChannel(), orderInfo.getCpid(), orderInfo.getSpid());
    			if(res == 0){//无配置，videoif/order.do要验证token
	    			//过期时间
	    			long expireTime = 5 * 60;
	    			//调置token到redis，用于videoif订购接口验证
	    			redisService.incr(orderInfo.getToken(), 1, expireTime);
    			}
    		}
    		//删除调用凭证
    		redisService.remove(key);
    	}
    }
    
    /**
     * 是否走能力平台产品
     * @param orderInfo
     * @return
     * @throws Exception 
     */
    private void hassharespid(OrderInfo orderInfo) throws Exception{
    	List<HashMap> dataList = commConfDao.findSpInfo(orderInfo.getSpid());
    	String paytype = dataList.get(0).get("PAYTYPE")+"";
    	if("4".equals(paytype)){
    		orderInfo.setPaytype(Integer.parseInt(paytype));
    	}else{
    		throw new BussinessException("80015", "spid异常");
    	}
    }

    /**
     * 参数验证
     * @param orderInfo
     * @throws Exception
     */
    private void paramValidate(OrderInfo orderInfo) throws Exception {  
    	String errorMsg = "";
    	//公共参数是否为空
        if (StringUtils.isEmpty(orderInfo.getUserid()) 
        		|| StringUtils.isEmpty(orderInfo.getSpid()) 
        		|| StringUtils.isEmpty(orderInfo.getCpid()) 
        		|| StringUtils.isEmpty(orderInfo.getChannel())
        		|| StringUtils.isEmpty(orderInfo.getSignature())
        		) {
        	errorMsg = "参数异常";
        }
          
        //接口标识
        String invokeface = orderInfo.getInvokeface();
        //验证接口
        if("valicode".equals(invokeface)){
			if (!"0".equals(orderInfo.getType()) && !"1".equals(orderInfo.getType())){
				errorMsg = "type参数异常";
			}
			//TX20_tencent不验证token
			if (!"TX20_tencent".equals(orderInfo.getChannel()) && StringUtils.isEmpty(orderInfo.getToken())){
				errorMsg = "token参数异常";
			} 
			if(StringUtils.isEmpty(orderInfo.getVcode()) 
					|| orderInfo.getVcode().trim().length() != 6 
					|| !valinumer(orderInfo.getVcode())){
				errorMsg = "验证码异常";
			}
        }else if("sendcode".equals(invokeface)){
        	orderInfo.setType("");//设置为空串，用于签名验证
        }
        //验证未通过
        if(!"".equals(errorMsg)){
            throw new BussinessException("80015", errorMsg);
        }
    }
    
    /**
     * 业务处理
     * @param orderInfo
     * @throws Exception
     */
    public void process(OrderInfo orderInfo) throws Exception {   	
    	//日志表数据
		Map<String, String> logMap = new HashMap<String, String>();
		String resultcode = "-1";
		String errorinfo = "处理中";
		String result = "";
		String invokeUrl = "";
    	try {
			logMap.put("USERID", orderInfo.getUserid());
			logMap.put("CPID", orderInfo.getCpid());
			logMap.put("SPID", orderInfo.getSpid());
			logMap.put("CHANNEL", orderInfo.getChannel());
			logMap.put("TYPE", orderInfo.getType());
			logMap.put("INVOKEFACE", orderInfo.getInvokeface());
			//接口地址
			invokeUrl = dictionaryDao.getValue("commonOrderUrl");
			//渠道加密密码
		    String pwd = channelDao.queryChannel(orderInfo.getChannel()).getPassword();
		    String cpid = orderInfo.getCpid();
		    String userid = orderInfo.getUserid();
		    String spid = orderInfo.getSpid();
		    String channel = orderInfo.getChannel();
	        String entype = "1"; //1为渠道方接入，按渠道密钥加密，0为CP方接入，按cpid密钥加密
		    userid = DesUtil.encode(userid,pwd); 
			//发送验证码
			if("sendcode".equals(orderInfo.getInvokeface())){ 
		    	//设置token
		    	setToken(orderInfo);
			    String flag = "";        
			    invokeUrl += "sendSmsCode.do?cpid="+cpid+"&spid="+spid+"&channel="+channel+"&flag="+flag+"&entype="+entype+"&userid="+URLEncoder.encode(userid,"utf-8")+"&apptype=2";
			    result = URLUtil.get(invokeUrl, 30000);
			    JSONObject resObj = new JSONObject().parseObject(result);
			    if("0".equals(resObj.getString("resultcode"))){
					resultcode = "0";
					errorinfo = "ok";
			    }else{
			    	resultcode = resObj.getString("resultcode");
			    	errorinfo =  resObj.getString("errorinfo");
			    	throw new BussinessException(resultcode, errorinfo);
			    }
			//校验验证码及订购	
			}else if("valicode".equals(orderInfo.getInvokeface())){
		        String vcode = orderInfo.getVcode();
		        invokeUrl += "smsNumber.do?cpid="+cpid+"&vcode="+vcode+"&channel="+channel+"&entype="+entype+"&userid="+URLEncoder.encode(userid,"utf-8")+"&apptype=2";
		        result = URLUtil.get(invokeUrl, 30000);
		        JSONObject resObj = new JSONObject().parseObject(result);
		        String resuserid = resObj.getString("userid");
		        //当返回0时，不一定是验证成功，可能在5分钟内确实有下发过验证码，验证码错误，也会返回0，同时userid返回空，只有验证成功才会返回加密的userid，与输入参数相同
			    if("0".equals(resObj.getString("resultcode"))){
			    	if(userid.equals(resuserid)){//验证成功
				    	//设置token并移除调用接口凭证
				    	setToken(orderInfo);
				    	orderInfo.setAccess("1");
				    	orderInfo.setSubtype("2"); //1为CAP短信接口，2为自有短信接口
				    	//调办理接口
			            handleService.handle(orderInfo);
						resultcode = "0";
						errorinfo = "ok";
			    	}else{//失败
			    		throw new BussinessException("8999", "验证码已失效");
			    	}
			    }else{
			    	resultcode = resObj.getString("resultcode");
			    	errorinfo =  resObj.getString("errorinfo");
			    	throw new BussinessException(resultcode, errorinfo);
			    }
			}else{
				throw new BussinessException("8000", "无业务办理配置");
			}
		} catch (Exception e) {
            if (e instanceof BussinessException) {
                resultcode = ((BussinessException) e).getCode();
                errorinfo = e.getMessage();
            } else {
    			e.printStackTrace();
                resultcode = "8000";
                errorinfo = "办理业务出现异常，"+e.getMessage();
    			logger.info("办理业务出现异常，"+e.getMessage(),e);
            }
			throw e;
		} finally {
			logMap.put("TOKEN", orderInfo.getToken());
			logMap.put("INVOKEURL", invokeUrl);
			logMap.put("RESULT", result);
			logMap.put("RESULTCODE", resultcode);
			logMap.put("ERRORINFO", errorinfo);
			
			try{
				if(errorinfo != null && errorinfo.length()>500){
					errorinfo = errorinfo.substring(0,500);
					logMap.put("ERRORINFO", errorinfo);
				}
				//发送验证码
				if("sendcode".equals(orderInfo.getInvokeface())){ 
					//写日志
					callSendDao.addSmsorderLog(logMap);
					//校验验证码及订购	
				}else if("valicode".equals(orderInfo.getInvokeface())){
					callSendDao.updSmsorderLog(logMap);
				}
				logMap.put("入库日志", "成功");
			}catch(Exception e2){
				e2.printStackTrace();
				logger.error("记录日志出现异常，"+e2.getMessage(),e2);
				logMap.put("入库日志", "失败，"+e2.getMessage());
			}
			
			logger.info(JSON.toJSONString(logMap));
		}
    	
		if("-1".equals(resultcode)){
			throw new BussinessException("8000", "业务处理出现错误");
		}
    }
}
