package com.chinacreator.video.restful.service;

import java.net.URLEncoder;
import java.util.Arrays;
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.AreaInfo;
import com.chinacreator.video.bean.OrderInfo;
import com.chinacreator.video.exception.BussinessException;
import com.chinacreator.video.mapper.ChannelDao;
import com.chinacreator.video.mapper.DictionaryDao;
import com.chinacreator.video.restful.dao.CallSendDao;
import com.chinacreator.video.restful.dao.QueryCapOrderDao;
import com.chinacreator.video.service.HandleService;
import com.chinacreator.video.util.AreaUtil;
import com.chinacreator.video.util.DesUtil;
import com.chinacreator.video.util.MD5;
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;

@Service
public class CallSendcoService {
	
    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 RedisService redisService;
    
    @Autowired
    private DictionaryDao dictionaryDao;
    
    @Autowired
    private HandleService handleService;
    
    @Autowired
    private CallSendDao callSendDao;

    public void check(OrderInfo orderInfo) throws Exception {
    	//参数验证
    	paramValidate(orderInfo);
        //timetamp验证
        timetampValidate.validate(orderInfo.getTimestamp());
        //渠道验证
        channelValidate.validate(orderInfo.getChannel());
        //ip验证
        //ipValidate.volidate(orderInfo,"0");
        //渠道验证，如果是二级渠道，包含了IP验证
/*        if ("0".equals(type)){
            boolean hasChannelBuild = channelValidate.validate(orderInfo);
            //非二级渠道，要另外进行IP验证
            if(!hasChannelBuild){
                //ip验证
                ipValidate.volidate(orderInfo,"0");
            }
        }else {
            ipValidate.volidate(orderInfo,"0");
        }*/
        ipValidate.volidate(orderInfo,"0");
        //签名验证
        signValidate.validate(orderInfo);
        //手机号码验证
        mobValidate.validate(orderInfo);
        //验证渠道的省份是否有订购限制
        valiProvLimit(orderInfo);
        //验证订购凭证
        valitoken(orderInfo);
    }
    
    /**
     * 验证渠道的省份是否有订购限制
     * @param orderInfo
     * @throws Exception
     */
    private void valiProvLimit(OrderInfo orderInfo) throws Exception{
    	boolean pass = true;
    	//获取要限制的渠道
    	String callSendcoLimitProvChannel = dictionaryDao.getValue("callSendcoLimitProvChannel");
    	//获取要限制的省份
    	String callSendcoLimitProvName = dictionaryDao.getValue("callSendcoLimitProvName");
    	//都有配置
    	if(!StringUtils.isEmpty(callSendcoLimitProvName) && !StringUtils.isEmpty(callSendcoLimitProvChannel)){
    		List<String> channelList =  Arrays.asList(callSendcoLimitProvChannel.split(","));
    		List<String> provList =  Arrays.asList(callSendcoLimitProvName.split(","));
    		String channel = orderInfo.getChannel();
    		//渠道有匹配
    		if(channelList.contains(channel)){
    			//获取地市信息
            	AreaInfo areaInfo = AreaUtil.getAreaInfoByUserid(orderInfo.getUserid());
            	if(areaInfo != null){
            		String prov = areaInfo.getProvince();
            		//省份有匹配
            		if(provList.contains(prov)){
            			orderInfo.setProvince(prov);
            			pass = false;           			
            		}
            	}
    		}
    	}
    	
    	if(!pass){
    		throw new BussinessException("80016", "抱歉，您当前暂不能参加此活动");
    	}
    }
    
    /**
     * 验证是否为数字
     * @param vcode
     * @return
     */
    private boolean valinumer(String vcode){
    	vcode = vcode.replaceAll("[\\s-]", "");
        if(!vcode.matches("^[0-9]*$")){
        	return false;
        }
        
        return true;
    }

    /**
     * 参数验证
     * @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("checkCapSmsCode".equals(invokeface)){
			if (!"0".equals(orderInfo.getType()) && !"1".equals(orderInfo.getType())){
				errorMsg = "type参数异常";
			}
			if(StringUtils.isEmpty(orderInfo.getVcode()) 
					|| orderInfo.getVcode().trim().length() != 6 
					|| !valinumer(orderInfo.getVcode())){
				errorMsg = "验证码异常";
			}
        }else if("sendCapSmsCode".equals(invokeface)){//发送短信接口
        	orderInfo.setType("");//设置为空串，用于签名验证
        }
        //验证未通过
        if(!"".equals(errorMsg)){
            throw new BussinessException("80015", errorMsg);
        }
    }
    
    /**
     * token验证
     * @param orderInfo
     * @return 当调校验接口时返回临时凭证
     * @throws Exception
     */
    public void valitoken(OrderInfo orderInfo) throws Exception{
    	String key = "univideo_smscaporder_"+orderInfo.getChannel()+orderInfo.getUserid()+orderInfo.getCpid()+orderInfo.getSpid();
    	//发送验证码
    	if("sendCapSmsCode".equals(orderInfo.getInvokeface())){   

    	//校验验证码及订购	
    	}else if("checkCapSmsCode".equals(orderInfo.getInvokeface())){
    		/**
    		 * 验证token，以确保调此接口之前在sendcode接口已获取到验证码
    		 * 根据手机号码CPID，SPID获取redis的值，如果为空，可能未调sendcode接口，或者前者调用超时，redis的值已失效
    		 */
    		//REDIS存放的接口调用凭证模拟token
    		String token = (String)redisService.get(key);
    		//token为空，或者已失效
    		if(StringUtils.isEmpty(token)){
    			throw new BussinessException("8999","验证码失效！");
    		}
    		
    		orderInfo.setInvokeToken(token);
    	}
    }

    /**
     * 设置token，获取验证码时设置临时凭证，校验验证码时移除临时凭证并设置真正token到redis
     * @param orderInfo
     * @param tmptoken 临时凭证
     * @return 当调下发接口时返回临时凭证
     */
    public void setToken(OrderInfo orderInfo){
    	String key = "univideo_smscaporder_"+orderInfo.getChannel()+orderInfo.getUserid()+orderInfo.getCpid()+orderInfo.getSpid();
    	//发送验证码
    	if("sendCapSmsCode".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("checkCapSmsCode".equals(orderInfo.getInvokeface())){
			//过期时间
			long expireTime = 5 * 60;
			//调置token到redis，用于videoif订购接口验证
			redisService.incr(orderInfo.getToken(), 1, expireTime);

    		//删除调用凭证
    		//redisService.remove(key);
    	}
    }
    
    /**
     * 订购成功后移除redis接口调用凭证
     * @param orderInfo
     */
    private void removeRedisCert(OrderInfo orderInfo){
    	String key = "univideo_smscaporder_"+orderInfo.getChannel()+orderInfo.getUserid()+orderInfo.getCpid()+orderInfo.getSpid();
		//删除调用凭证
		redisService.remove(key);
    }

    /**
     * 业务处理
     * @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 = "";
		String invokeToken = ""; //调接口发送短信验证码凭证
    	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());
			
			//发送验证码
			if("sendCapSmsCode".equals(orderInfo.getInvokeface())){ 
				//设置调用接口临时凭证
				setToken(orderInfo);
				invokeUrl = dictionaryDao.getValue("callSendcoUrl");
				invokeUrl = invokeUrl + "?usermob=" + orderInfo.getUserid() + "&cpid=" + orderInfo.getCpid() + "&spid=" + orderInfo.getSpid();
				result = URLUtil.get(invokeUrl, 30000);
	
			    JSONObject resObj = new JSONObject().parseObject(result);
		    	resultcode = resObj.getString("resultcode");
		    	errorinfo =  resObj.getString("errorinfo");
		    	
		    	//失败
			    if(!"0".equals(resultcode)){
			    	throw new BussinessException(resultcode, errorinfo);
			    }
			//校验验证码及订购	
			}else if("checkCapSmsCode".equals(orderInfo.getInvokeface())){
				invokeToken = orderInfo.getInvokeToken();
		        invokeUrl = dictionaryDao.getValue("callCheckactUrl");
		        invokeUrl = invokeUrl + "?usermob=" + orderInfo.getUserid() + "&cpid=" + orderInfo.getCpid() + "&spid=" + orderInfo.getSpid() + "&vcode=" + orderInfo.getVcode();
		        result = URLUtil.get(invokeUrl,30000);
		        
		        JSONObject resObj = new JSONObject().parseObject(result);
		        resultcode = resObj.getString("resultcode");
		        errorinfo = resObj.getString("errorinfo");
		        String token = resObj.getString("token");
		        
		        //cap返回token为空
	            if (StringUtils.isEmpty(token)) {
	                throw new BussinessException(resultcode, "短信校验出现问题{token}为空->" + errorinfo);
	            }else{		        
	            	//判断token是否使用过
	                long num = redisService.incr("token" + token, 1, 300);
	                if (num == 1){//只使用过一次
		                orderInfo.setToken(token);
		                orderInfo.setAccess("1");
		                orderInfo.setSubtype("1"); //1为CAP短信接口，2为自有短信接口
	                	//设置videoif/order.do的token并移除调用接口凭证
	                	setToken(orderInfo);
	    		    	//调办理接口
	    	            handleService.handle(orderInfo);
	    				resultcode = "0";
	    				errorinfo = "ok";
	    				//办理成功后移除接口调用凭证
	    				removeRedisCert(orderInfo);
	                }else{
	                	throw new BussinessException("8000", "CAP重复TOKEN");
	                }
	            }
			}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("sendCapSmsCode".equals(orderInfo.getInvokeface())){ 
					logMap.put("TOKEN", orderInfo.getToken()); //调发送短信验证码接口的凭证
					//写日志
					callSendDao.addSmsorderLog(logMap);
					//校验验证码及订购	
				}else if("checkCapSmsCode".equals(orderInfo.getInvokeface())){
					logMap.put("TOKEN", invokeToken); //调发送短信验证码接口的凭证
					logMap.put("SMSTOKEN", orderInfo.getToken());//调videoif的token
					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", "业务处理出现错误");
		}
    }
}
