package com.wechat.service;

import java.io.IOException;
import java.io.InputStream;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.annotation.Resource;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSONException;
import com.aliyuncs.exceptions.ClientException;
import com.github.qcloudsms.SmsSingleSender;
import com.github.qcloudsms.SmsSingleSenderResult;
import com.github.qcloudsms.httpclient.HTTPException;
import com.wechat.common.utils.MailUtil;
import com.wechat.common.utils.NumberUtils;
import com.wechat.common.utils.StringsUtils;
import com.wechat.global.base.dao.RedisWithExpiryTimeDao;
import com.wechat.global.message.InfoMsg;
import com.wechat.model.dbEntity.MdeUser;
import com.wechat.model.responseDto.ResultEntity;

@Service
public class VerificationCodeService {

	private Logger log = LoggerFactory.getLogger(getClass());

	@Autowired
	private RedisWithExpiryTimeDao captchaRedisDao;

	@Value("#{configProperties['sms.phoneCode.expirationTime']}")
	private String codeExpirationTime;

	@Value("#{configProperties['sms.appID']}")
	private int appid;

	@Value("#{configProperties['sms.appkey']}")
	private String appkey;

	@Value("#{configProperties['sms.templateId']}")
	private int templateId;

	@Value("#{configProperties['sms.templateId_en']}")
	private int templateIdEn;

	@Value("#{configProperties['sms.sign']}")
	private String smsSign;

	@Value("#{configProperties['sms.sign.en']}")
	private String smsSignEn;

	@Value("#{configProperties['deadline_payment']}")
	private String remitDay;

	@Value("#{configProperties['sms.sendRemit.templateId']}")
	private int remitTemplateId; // 汇款短信模板Id

	@Value("#{configProperties['sms.invitation.templateId']}")
	private int invitationTemplated; // 企业邀请模板Id (中国大陆)

	@Value("#{configProperties['sms.international.invitation.templateId']}")
	private int invitationTemplatedEn; // 企业邀请模板Id （国际）

	@Value("#{configProperties['default.openingBank']}")
	private String openingBank; // 开户行

	@Value("#{configProperties['default.account']}")
	private String account; // 账号

	@Value("#{configProperties['default.accountName']}")
	private String accountName; // 账户名
	
    @Value("#{configProperties['sms.interview.cn']}")
    private int smsInterviewCn; // 企业邀请模板Id （国内）
	   
    @Value("#{configProperties['sms.interview.en']}")
    private int smsInterviewEn; // 企业邀请模板Id （国际）   
	

	@Resource
	private MdeUserService mdeUserService;

	@Resource
	private CommonService commonService;

	@Resource
	private MailUtil mailUtil;

	/**
	 * 个人注册 短信验证码取得
	 * 
	 * @param phoneNo 不带国际区分的手机号
	 * @param imageCode 图形验证码
	 * @param phoneCode 国际区分
	 * @return
	 */
	public ResultEntity<String> getPersonVerifyCode(String phoneNo, String imageCode, Cookie[] cookies,
			String phoneCode) {

		// 图形验证码值
		String imageCodeKey = null;
		if (cookies != null) {
			for (Cookie cookie : cookies) {
				if ("uuid".equals(cookie.getName())) {
					imageCodeKey = cookie.getValue();
				}
			}
		}
		if (StringsUtils.isEmpty(phoneCode)) {
			return new ResultEntity<>(InfoMsg.ERROR_PARAMS_ERROR);
		}

		//获取国际手机号区分
		String[] phoneCodeSplit = phoneCode.split("-");
		if (phoneCodeSplit == null || phoneCodeSplit.length != 3) {
			return new ResultEntity<>(InfoMsg.ERROR_PHONECODE_ERROR);
		}
		// 国家手机区号码
		String phoneCodeStr = phoneCodeSplit[0].trim();
		// 完整的手机号 非中国带国际区号
		String fullPhoneNo =phoneNo;
		if (!phoneCodeStr.equals("86")) {
			fullPhoneNo = "+" + phoneCodeStr + phoneNo;
		}
		
		// 国际手机号验证 
		int lenth = internationalPhoneCheck(phoneNo, phoneCodeSplit);
		// 手机号有误
		if (lenth != 0) {
			// 国内手机号验证失败
			return new ResultEntity<>(InfoMsg.ERROR_PHONE_ERROR);
		}

		String redisImageCode = captchaRedisDao.select(imageCodeKey);
		// 验证图形码
		if (StringsUtils.isEmpty(imageCode) || !imageCode.equalsIgnoreCase(redisImageCode)) {
			return new ResultEntity<>(InfoMsg.ERROR_IMAGECODE_ERROR);
		}
		
		// 验证是否注册过
		MdeUser mdeUser = mdeUserService.checkUserNameIsRegester(fullPhoneNo);
		if (mdeUser != null) {
			return new ResultEntity<>(InfoMsg.ERROR_PHONE_IS_EXSIT);
		}
		
		// 获取要发送的验证码 当已经发送并未过期的时候验证码一致
		String code = captchaRedisDao.select(fullPhoneNo);
		if(StringsUtils.isEmpty(code))
		{
			code = StringsUtils.getRandomNum(6);
		}

		// 发送短信 （中国大陆）
		if (phoneCodeStr.equals("86")) {
			sendPhoneCode(phoneNo, code);
		} else {
			if (phoneNo.startsWith("0")) {
				phoneNo = phoneNo.substring(1, phoneNo.length());
			}
			
			// 国际短信
			sendRegisterInternationalPhoneCode(phoneCodeStr, phoneNo, code);
		}
		// 以用户名为key，验证码为value，并且有效时间为captchaExpirationTime的记录存入redis缓存中
		captchaRedisDao.insert(fullPhoneNo, code, NumberUtils.stringToInt(codeExpirationTime, 300));
		return new ResultEntity<>(InfoMsg.SUCCESS_REQUEST);
	}

	/**
	 * 企业注册 短信验证码取得
	 * 
	 * @param map
	 * @param cookies
	 * @return
	 */
	public ResultEntity<String> getEnterpriseVerifyCode(String userName, String imageCode, String entPhone,
			Cookie[] cookies) {

		// 图形验证码值
		String imageCodeKey = null;
		if (cookies != null) {
			for (Cookie cookie : cookies) {
				if ("uuid".equals(cookie.getName())) {
					imageCodeKey = cookie.getValue();
				}
			}
		}

		String redisImageCode = captchaRedisDao.select(imageCodeKey);
		// 验证图形码
		if (StringsUtils.isEmpty(imageCode) || !imageCode.equalsIgnoreCase(redisImageCode)) {
			return new ResultEntity<>(InfoMsg.ERROR_IMAGECODE_ERROR);
		}
		if (StringsUtils.isEmpty(entPhone)) {
			return new ResultEntity<>(InfoMsg.ERROR_ENTPHONE_ERROR);
		}
		// 验证是否注册过
		MdeUser mdeUser = mdeUserService.checkUserNameIsRegester(userName);
		if (mdeUser != null) {
			return new ResultEntity<>(InfoMsg.ERROR_REGESITER_FIELD);
		}
		if (checkPhone(entPhone)) {
			// 获取要发送的验证码 当已经发送并未过期的时候验证码一致
			String code = captchaRedisDao.select(entPhone);
			if(StringsUtils.isEmpty(code))
			{
				code = StringsUtils.getRandomNum(6);
			}
			// 发送短信
			sendPhoneCode(entPhone, code);
			// 以用户名为key，验证码为value，并且有效时间为captchaExpirationTime的记录存入redis缓存中
			captchaRedisDao.insert(entPhone, code, NumberUtils.stringToInt(codeExpirationTime, 300));
			return new ResultEntity<>(InfoMsg.SUCCESS_REQUEST);
		} else {
			return new ResultEntity<>(InfoMsg.ERROR_SEND_MESSAGE_FAIL);
		}

	}

	/**
	 * 忘记密码 短信验证码取得
	 * 
	 * @param userName 带国际区分的完整手机号 或企业邮箱
	 * @param imageCode 图形验证码
	 * @param cookies
	 * @return
	 */
	public ResultEntity<String> getForgetVerifyCode(String userName, String imageCode, Cookie[] cookies,
			HttpServletRequest req) {

		// 图形验证码值
		String imageCodeKey = null;
		String lang = commonService.getLanguage(req); // 语言
		if (cookies != null) {
			for (Cookie cookie : cookies) {
				if ("uuid".equals(cookie.getName())) {
					imageCodeKey = cookie.getValue();
				}

			}
		}
		String redisImageCode = captchaRedisDao.select(imageCodeKey);
		// 验证图形码
		if (StringsUtils.isEmpty(imageCode) || !imageCode.equalsIgnoreCase(redisImageCode)) {
			return new ResultEntity<>(InfoMsg.ERROR_IMAGECODE_ERROR);
		}
		// 验证是否注册过
		MdeUser mdeUser = mdeUserService.checkUserNameIsRegester(userName);
		if (mdeUser == null) {
			if(checkMail(userName)) {
				return new ResultEntity<String>(InfoMsg.ERROR_ENTERPRISE_USER_NOTEXIST);
			}else {
				return new ResultEntity<String>(InfoMsg.ERROR_PERSON_USER_NOTEXIST);
			}
		}
		
		// 获取要发送的验证码 当已经发送并未过期的时候验证码一致
		String code = captchaRedisDao.select(userName);
		if(StringsUtils.isEmpty(code))
		{
			code = StringsUtils.getRandomNum(6);
		}
		
		if (checkPostBox(userName)) {
			// 发送邮件
			InputStream in = null;
			try {
				if (lang.equalsIgnoreCase("en")) {
					in = this.getClass().getClassLoader().getResourceAsStream("template/mdeMailVerification_en.html");
				} else {
					in = this.getClass().getClassLoader().getResourceAsStream("template/mdeMailVerification_cn.html");
				}

				byte[] bytes = new byte[in.available()];
				in.read(bytes);
				String htmlStr = new String(bytes);
				htmlStr = htmlStr.replace("{0}", "密码找回");
				htmlStr = htmlStr.replace("{1}", code);
				Boolean flag = mailUtil.sendCodeMail(htmlStr, userName);
				if (!flag) {
					return new ResultEntity<>(InfoMsg.ERROR_SENDMAIL_PARAM);
				}
			} catch (IOException e) {
				e.printStackTrace();
			}

			// 以用户名为key，验证码为value，并且有效时间为captchaExpirationTime的记录存入redis缓存中
			captchaRedisDao.insert(userName, code, NumberUtils.stringToInt(codeExpirationTime, 300));
			return new ResultEntity<>(InfoMsg.SUCCESS_REQUEST);
		} else {
			ResultEntity<String> result = null;
			String phoneCode = mdeUser.getPhoneCode();
			if (StringsUtils.isEmpty(phoneCode)) {
				return new ResultEntity<>(InfoMsg.ERROR_PHONECODE_ERROR);
			}
			if (!phoneCode.equals("86")) {
				// 国际手机号
				String phoneNum = userName.substring(phoneCode.length() + 1, userName.length());

				if (phoneNum.startsWith("0")) {
					phoneNum = phoneNum.substring(1, phoneNum.length());
				}
				// 发送短信 （国际）
				result = sendRegisterInternationalPhoneCode(phoneCode, phoneNum, code);
			} else {
				// 发送短信 （中国大陆）
				result = sendPhoneCode(userName, code);
			}
			// 以用户名为key，验证码为value，并且有效时间为captchaExpirationTime的记录存入redis缓存中
			captchaRedisDao.insert(userName, code, NumberUtils.stringToInt(codeExpirationTime, 300));
			return result;
		}

	}
	/**
	 * 邮箱验证
	 * 
	 * @param userName
	 * @return
	 */
	public boolean checkMail(String mail) {
		boolean flag = false;
		try {
			String check = "^([a-z0-9A-Z]+[-|_|\\.]?)+[a-z0-9A-Z]@([a-z0-9A-Z]+(-[a-z0-9A-Z]+)?\\.)+[a-zA-Z]{2,}$";
			Pattern regex = Pattern.compile(check);
			Matcher matcher = regex.matcher(mail);
			flag = matcher.matches();
		} catch (Exception e) {
			log.info(e.getMessage());
			return flag;
		}
		return flag;
	}
	/**
	 * 发送手机验证码 （国内）
	 * 
	 * @param phoneCode
	 * @param phoneNo
	 * @param code
	 * @return
	 */
	public ResultEntity<String> sendPhoneCode(String phoneNo, String code) {
		try {
			String expirationTime = String.valueOf((Integer.parseInt(codeExpirationTime) / 60));
			String[] params = { code, expirationTime};
			// 发送短信 （中国大陆 86）
			sendSms("86", phoneNo, appid, appkey, templateId, params, smsSign);
			return new ResultEntity<>(InfoMsg.SUCCESS_REQUEST);
		} catch (ClientException e) {
			log.info("短信发送失败" + e.getMessage());
		}
		return new ResultEntity<>(InfoMsg.ERROR_SEND_MESSAGE_FAIL);
	}

	/**
	 * 发送手机验证码 （国际）
	 * 
	 * @param phoneCode
	 *            国际区号码
	 * @param phoneNo
	 * @param code
	 * @return
	 */
	public ResultEntity<String> sendRegisterInternationalPhoneCode(String phoneCode, String phoneNo, String code) {
		try {
			if (StringsUtils.isEmpty(phoneCode)) {
				phoneCode = "86";
			}
			String expirationTime = String.valueOf((Integer.parseInt(codeExpirationTime) / 60));
			String[] params = { code, expirationTime };
			// 国际短信
			sendSms(phoneCode, phoneNo, appid, appkey, templateIdEn, params, smsSignEn);
			return new ResultEntity<>(InfoMsg.SUCCESS_REQUEST);
		} catch (ClientException e) {
			log.info("短信发送失败" + e.getMessage());
		}
		return new ResultEntity<>(InfoMsg.ERROR_SEND_MESSAGE_FAIL);
	}

	/**
	 * 发送企业汇款短信
	 * 
	 * @param phoneNo
	 *            手机号
	 * @param accountName
	 *            账户名
	 * @param taxNo
	 *            税号
	 * @param banking
	 *            开户行
	 * @param account
	 *            账户
	 * @param orderId
	 *            识别码
	 * @return
	 */
	public ResultEntity<String> sendRemit(String phoneNo, String orderId) {
		// 验证手机号是否合法
		if (!checkPhone(phoneNo)) {
			return new ResultEntity<>(InfoMsg.ERROR_PHONE_ERROR);
		}

		try {
			String[] params = { accountName, "", openingBank, account, orderId, remitDay };
			sendSms("86", phoneNo, appid, appkey, remitTemplateId, params, smsSign);
			return new ResultEntity<>(InfoMsg.SUCCESS_REQUEST);
		} catch (ClientException e) {
			log.info("短信发送失败" + e.getMessage());

		}
		return new ResultEntity<>(InfoMsg.ERROR_SEND_MESSAGE_FAIL);
	}

	/**
	 * 发送短信 (企业邀请成功 中国大陆)
	 * 
	 * @param countrtCode
	 * @param phoneNo
	 * @param name
	 * @param foreignName
	 * @return
	 */
	public ResultEntity<String> sendInvitation(String phoneNo, String name, String foreignName) {
		try {
			String[] params = { name, foreignName };
			System.out.println(11);
			sendSms("86", phoneNo, appid, appkey, invitationTemplated, params, smsSign);
			return new ResultEntity<>(InfoMsg.SUCCESS_REQUEST);
		} catch (ClientException e) {
			log.info("短信发送失败" + e.getMessage());
		}
		return new ResultEntity<>(InfoMsg.ERROR_SEND_MESSAGE_FAIL);
	}

	/**
	 * 发送短信 (企业邀请成功 国际短信)
	 * 
	 * @param countrtCode
	 * @param phoneNo
	 * @param name
	 * @param foreignName
	 * @return
	 */
	public ResultEntity<String> sendInternationalInvitation(String countrtCode, String phoneNo, String name) {
		try {
			String[] params = { name };
			System.out.println(11);
			sendSms(countrtCode, phoneNo, appid, appkey, invitationTemplatedEn, params, smsSignEn);
			return new ResultEntity<>(InfoMsg.SUCCESS_REQUEST);
		} catch (ClientException e) {
			log.info("短信发送失败" + e.getMessage());
		}
		return new ResultEntity<>(InfoMsg.ERROR_SEND_MESSAGE_FAIL);
	}
	
	 /**
     * 发送短信 (企业邀请面试  中国大陆)
     * 
     * @param countrtCode
     * @param phoneNo
     * @param name
     * @return
     */
    public ResultEntity<String> sendInterviewCn(String phoneNo, String name) {
        try {
            String[] params = { name };
            sendSms("86", phoneNo, appid, appkey, smsInterviewCn, params, smsSign);
            return new ResultEntity<>(InfoMsg.SUCCESS_REQUEST);
        } catch (ClientException e) {
            log.error("企业邀请面试  中国大陆 短信发送失败" + e.getMessage());
        }
        return new ResultEntity<>(InfoMsg.ERROR_SEND_MESSAGE_FAIL);
    }

    /**
     * 发送短信 (企业邀请面试 国际短信)
     * 
     * @param countrtCode
     * @param phoneNo
     * @param name
     * @return
     */
    public ResultEntity<String> sendInterviewEn(String countrtCode, String phoneNo, String name) {
        try {
            String[] params = { name };
            sendSms(countrtCode, phoneNo, appid, appkey, smsInterviewEn, params, smsSignEn);
            return new ResultEntity<>(InfoMsg.SUCCESS_REQUEST);
        } catch (ClientException e) {
            log.error("企业邀请面试 国际短信 发送失败" + e.getMessage());
        }
        return new ResultEntity<>(InfoMsg.ERROR_SEND_MESSAGE_FAIL);
    }

    /**
	     * 发送短信 1个参数
	 * 
	 * @param countrtCode
	 * @param phoneNo
	 * @param name
	 * @return
	 */
	public boolean sendSms1Pam(String countrtCode, String phoneNo, int templateId, String pam1) {
		 try {
	         String[] params = { pam1 };
	         if("86".equals(countrtCode) || StringsUtils.isEmpty(countrtCode)) {
	        	 sendSms("86", phoneNo, appid, appkey, templateId, params, smsSign);
	         } else {
	        	// 国际
	             phoneNo = phoneNo.substring(countrtCode.length() + 1, phoneNo.length()); // 截取手机号
	             // 手机号 开头为0 去掉
	             if (phoneNo.startsWith("0")) {
	                 phoneNo = phoneNo.substring(1, phoneNo.length());
	             }
		         sendSms(countrtCode, phoneNo, appid, appkey, templateId, params, smsSignEn); 
	         }
	         return true;
	     } catch (ClientException e) {
	         log.error("*************短信发送失败："+templateId+"*************" + e.getMessage());
	     }
	     return false;
	}
	
    /**
	  * 发送短信 2个参数
	 * 
	 * @param countrtCode
	 * @param phoneNo
	 * @param name
	 * @return
	 */
	public boolean sendSms2Pam(String countrtCode, String phoneNo, int templateId, String pam1, String pam2) {
		 try {
	         String[] params = { pam1, pam2};
	         if("86".equals(countrtCode) || StringsUtils.isEmpty(countrtCode)) {
	        	 sendSms("86", phoneNo, appid, appkey, templateId, params, smsSign);
	         } else {
	        	// 国际
	             phoneNo = phoneNo.substring(countrtCode.length() + 1, phoneNo.length()); // 截取手机号
	             // 手机号 开头为0 去掉
	             if (phoneNo.startsWith("0")) {
	                 phoneNo = phoneNo.substring(1, phoneNo.length());
	             }
		         sendSms(countrtCode, phoneNo, appid, appkey, templateId, params, smsSignEn); 
	         }
	         return true;
	     } catch (ClientException e) {
	         log.error("*************短信发送失败："+templateId+"*************" + e.getMessage());
	     }
	     return false;
	}

	/**
	 * 发送短信
	 * 
	 * @param phoneNo
	 * @param appid
	 * @param appkey
	 * @param templateId
	 * @param params
	 * @throws ClientException
	 */
	public void sendSms(String countryCode, String phoneNo, int appid, String appkey, int templateId,
			String[] params, String smsSign) throws ClientException {
		try {
			SmsSingleSender ssender = new SmsSingleSender(appid, appkey);
			// 发送
			if(!"86".equals(countryCode))
			{
				smsSign = smsSignEn;
			}
			SmsSingleSenderResult result = ssender.sendWithParam(countryCode, phoneNo, templateId, params, smsSign, "","");
			//短信发送异常
			if(result.result != 0)
			{
				log.error("***************短信发送异常！【"+countryCode+"+"+phoneNo+"】************************");
				log.error("--result："+result.result+"--errmsg："+result.errMsg);
			}
		} catch (HTTPException e) {
			// HTTP响应码错误
			log.error("HTTP响应码错误",e);
		} catch (JSONException e) {
			// json解析错误
			log.error("json解析错误",e);
		} catch (IOException e) {
			// 网络IO错误
			log.error("网络IO错误",e);
		}
	}

	/**
	 * 手机号验证
	 * 
	 * @param userName
	 * @return
	 */
	public boolean checkPhone(String userName) {
		boolean flag = false;
		try {
			Pattern regex = Pattern.compile("^1[23456789]\\d{9}$");
			Matcher matcher = regex.matcher(userName);
			flag = matcher.matches();
		} catch (Exception e) {
			log.info(e.getMessage());
		}
		return flag;
	}

	/**
	 * 邮箱验证
	 * 
	 * @param userName
	 * @return
	 */
	public boolean checkPostBox(String userName) {
		boolean flag = false;
		try {
			String check = "^([a-z0-9A-Z]+[-|_|\\.]?)+[a-z0-9A-Z]@([a-z0-9A-Z]+(-[a-z0-9A-Z]+)?\\.)+[a-zA-Z]{2,}$";
			Pattern regex = Pattern.compile(check);
			Matcher matcher = regex.matcher(userName);
			flag = matcher.matches();
		} catch (Exception e) {
			log.info(e.getMessage());
			return flag;
		}
		return flag;
	}

	/**
	 * 国际手机号验证
	 * 
	 * @param phone
	 * @param phoneCodeSplit
	 * @return
	 */
	public int internationalPhoneCheck(String phone, String[] phoneCodeSplit) {
		int i = 0; // 成功
		try {
			if (phoneCodeSplit[0].equals("86")) {
				// 中国大陆 （手机号）
				Pattern regex = Pattern.compile("^1[23456789]\\d{9}$");
				Matcher matcher = regex.matcher(phone);
				if (matcher.matches()) {
					i = 0;
				} else {
					i = -1;
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
			i = -1;
		}
		return i;
	}

}
