package com.sifang.modules.esign.utils;

import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.jfinal.plugin.activerecord.Db;
import com.sifang.modules.sys.common.utils.DateUtils;
import com.sifang.modules.sys.common.utils.StringUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 思方短信服务 测试使用
 */
public class SfSmsNUtils {
	private static Logger logger = LoggerFactory.getLogger(SfSmsNUtils.class);

	//短信类型 A.通知类 B.营销类
	public static String SMS_TYPE_A = "765887";
	public static String SMS_TYPE_B = "455855";

	public static final String account = "202302161";
	public static final String password = "Ahsf123456";

	//群发短信前缀
	private static String sendMsgPrefix = "http://1.116.132.5:9511/api/sub/send-sms-batch";
	//单发短信前缀
	private static String singleSendMsgPrefix = "http://1.116.132.5:9511/api/sub/send-sms-single";
	//短信发送状态
	public static final String reportMsgPrefix = "http://1.116.132.5:9511/api/sub/report";
	//短信回复
	public static final String replyMsgPrefix = "http://1.116.132.5:9511/api/sub/reply";


	private static int connectTimeout = 60000;
	private static int readTimeout = 30000;


	/**
	 * 发送短信接口
	 *
	 * @param mobile
	 * @param content
	 * @param sign
	 * @return 返回结果 successNum=0表示本次发送失败，手机号码作为KEY值 VALUE值存短信记录id或者发送失败字样-fail
	 * 范例：{successNum=1, resResults=[]}
	 */
	public static Map<String, Object> sendBatchMsg(String mobile, String content, String sign, String ext, String type) {
		Map<String, Object> respMap = new HashMap<>();
		int successNum = 0;
		respMap.put("successNum", successNum);
		try {
			content = String.format("【%s】%s", sign, content);
			String result;
			String[] mobileS = mobile.split(",");
			if (mobileS.length > 1) {
				result = sendBatchMsgPost(mobile, content, ext, type);
			} else {
				result = sendSingleMsgPost(mobile, content, ext, type);
			}
			JsonObject obj = convertStringToJsonObject(result);
			// {"code":0,"msg":"success","msg_id":100000011,"failed_data":{"13955174824":"WL:MQM"}}
			if (obj != null && obj.has("code") && !"0".equals(obj.get("code").getAsString())) {
				return respMap;
			}
			String msgId = obj.get("msg_id").getAsString();
			JsonObject failedData = null;
			if (obj.get("failed_data") != null) {
				try {
					failedData = obj.get("failed_data").getAsJsonObject();
				} catch (Exception e) {
					// {"code":0,"msg":"success","msg_id":100000038,"failed_data":[]}
					// 出现[]时 表示所有手机号 短信发送 都提交成功
					logger.error(e.getMessage(), e);
					logger.error("failed_data : {}", obj.get("failed_data"));
				}
			}
			List<ResResult> resResults = new ArrayList<>();
			for (String mob : mobileS) {
				ResResult resResult;
				if (failedData != null && failedData.get(mob) != null) {
					resResult = new ResResult(mob, false, failMsgMap.get(failedData.get(mob).getAsString()));
				} else {
					resResult = new ResResult(mob, true, msgId);
					successNum++;
				}
				resResults.add(resResult);
			}
			respMap.put("resResults", resResults);
			respMap.put("successNum", successNum);
			logger.info("respMap : [{}]", respMap);
		} catch (Exception e) {
			e.printStackTrace();
			respMap.put("successNum", 0);
			logger.info("respMap : [{}]", respMap);
			return respMap;
		}
		return respMap;
	}

	/**
	 * 单条发送短信接口
	 *
	 * @param mobile
	 * @param content
	 * @param sign
	 * @return 成功返回记录id 失败则返回空
	 */
	public static String sendMsg(String mobile, String content, String sign, String type) {
		String stime = "";
		try {
			String result = sendSingleMsgPost(mobile, sign + content, null, type);
			JsonObject obj = convertStringToJsonObject(result);
			if (obj != null && obj.has("code") && !"0".equals(obj.get("code").getAsString())) {
				return "";
			}
			return obj.get("msg_id").getAsString();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return "";
	}


	/**
	 * 将字符串转换成JsonObject对象
	 *
	 * @param result
	 * @return
	 */
	public static JsonObject convertStringToJsonObject(String result) {
		Gson gson = new Gson();
		JsonObject obj = gson.fromJson(result, JsonObject.class);

		return obj;
	}

	public static boolean sendCode(String code, String mobile, String sign, String ext, String type) {
		// 内容字符串
		StringBuilder contextString = new StringBuilder("您的验证码是：" + code
				+ "，在5分钟内有效。如非本人操作请忽略本短信。");
		try {
			Map<String, Object> result = sendBatchMsg(mobile, contextString.toString(), sign, ext, type);
			if (result != null && (Integer) result.get("successNum") > 0) {
				return true;
			} else {
				return false;
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return false;
	}

	public static boolean sendCode(String code, String mobile) {
		return sendCode(code, mobile, "能辉光伏", null, SMS_TYPE_A);
	}

	public static boolean sendCode(String code, String mobile, String sign, String type) {
		return sendCode(code, mobile, sign, null, type);
	}

	public static String toUtf8(String value) throws Exception {
		return java.net.URLEncoder.encode(value, "UTF-8");
	}

	public static String specialUrlEncode(String value) {
		return value.replace("+", "%20").replace("*", "%2A").replace("%7E", "~");
	}

	public static String getSignature(String data, String key) throws Exception {
		byte[] keyBytes = key.getBytes();
		SecretKeySpec signingKey = new SecretKeySpec(keyBytes, "HmacSHA1");
		Mac mac = Mac.getInstance("HmacSHA1");
		mac.init(signingKey);
		byte[] rawHmac = mac.doFinal(data.getBytes());
		String hexBytes = byte2hex(rawHmac);
		return new sun.misc.BASE64Encoder().encode(hexBytes.getBytes());
	}

	private static String byte2hex(final byte[] b) {
		String hs = "";
		String stmp = "";
		for (int n = 0; n < b.length; n++) {
			stmp = (Integer.toHexString(b[n] & 0xFF));
			if (stmp.length() == 1) {
				hs = hs + "0" + stmp;
			} else {
				hs = hs + stmp;
			}
		}
		return hs;
	}

	/**
	 * 此为单条短信发送
	 *
	 * @param mobileString  手机号码
	 * @param contextString 短信内容格式： 【测试】验证码123
	 * @return 只有返回是0表示提交成功  范例：{"code":0,"msg":"success","msg_id":100000009}
	 */
	public static String sendSingleMsgPost(String mobileString, String contextString, String ext, String type) {
		HttpParamers paramers = HttpParamers.httpPostParamers();
		paramers.addParam("sp_id", type);
		paramers.addParam("account", account);
		paramers.addParam("password", password);
		paramers.addParam("mobile", mobileString);
		if (StringUtil.isNotBlank(ext)) {
			paramers.addParam("ext", ext);
		}
		paramers.addParam("content", contextString);
		return doService(singleSendMsgPrefix, paramers);
	}

	/**
	 * 此为批量发送短信  一次最多提交一万条
	 *
	 * @param mobileString  多个手机号码 用逗号隔开
	 * @param contextString 短信内容格式： 【测试】验证码123
	 * @return 只有返回是0表示提交成功 范例：{"code":0,"msg":"success","msg_id":100000008,"failed_data":[]}
	 */
	public static String sendBatchMsgPost(String mobileString, String contextString, String ext, String type) {
		HttpParamers paramers = HttpParamers.httpPostParamers();
		paramers.addParam("sp_id", type);
		paramers.addParam("account", account);
		paramers.addParam("password", password);
		paramers.addParam("mobiles", mobileString);
		if (StringUtil.isNotBlank(ext)) {
			paramers.addParam("ext", ext);
		}
		paramers.addParam("content", contextString);

		return doService(sendMsgPrefix, paramers);
	}

	private static String doService(String urlStr, HttpParamers params) {
		try {
			logger.info("HttpParameters：[{}]", params);
			String response = HttpClient.doService(urlStr, params, null, connectTimeout, readTimeout);
			logger.info("response : {}", response);
			return response;
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
			return "";
		}
	}


	private static void updateSMS(String sendid, String mobile, String time, String status) {
		String[] mobiles = mobile.indexOf(",") != -1 ? mobile.split(",") : null;
		if (mobiles == null) {
			//单个mobile处理
			String date = DateUtils.formatDate(DateUtils.parseDate(time), "yyyy-MM-dd HH:mm:ss");
			Db.update("update crm_sended_sms set status = '" + status + "', receive_time = '" + date + "' where sendid = ? and mobile = ?"
					, sendid, mobile);
		} else {
			StringBuilder insb = new StringBuilder();
			String date = DateUtils.formatDate(DateUtils.parseDate(time), "yyyy-MM-dd HH:mm:ss");
			for (int i = 0; i < mobiles.length; i++) {
				insb.append("'" + mobiles[i] + "'").append(i != mobiles.length - 1 ? "," : "");
			}
			Db.update("update crm_sended_sms set status = '" + status + "', receive_time = '" + date + "' where sendid = ? and mobile in (" + insb.toString() + ") ", sendid);
		}
	}

	public static void main(String[] args) throws Exception {
		sendCode("8877", "13955174824");
//		getSmsReport(SMS_TYPE_A);
//		getSmsDeliver(SMS_TYPE_A);
//		addTemplate("测试模板炸弹", "测试签名第三十二条测试签名第三十二条");
//		addSign("测试网点线下", SMS_TYPE_A);
//		getSignStatus("7");
// 		String tempId = addTemplate("测试模板炸弹", "测试");
//		getTemplateStatus(tempId);

//		try {
//			String decode = URLDecoder.decode("%E5%A5%BD%E7%9A%84", "utf-8");
//			System.out.println(decode);
//		} catch (UnsupportedEncodingException e) {
//			e.printStackTrace();
//		}

	}

	/**
	 * 手机号 短信发送失败的错误码解析
	 */
	public static Map<String, String> failMsgMap;

	/**
	 * 短信发送提交失败的code 解析
	 */
	public static Map<String, String> failCodeMap;

	static {
		failMsgMap = new HashMap<>();
		failMsgMap.put("WL:MBLJ", "短信内容匹配到了模板，并且此模板类型是拦截");
		failMsgMap.put("WL:MBSH", "命中审核模板");
		failMsgMap.put("WL:NMLJ", "短信内容没有匹配到模板，并且用户的模板审核方式是未匹配到就进拦截");
		failMsgMap.put("WL:NMSH", "短信内容没有匹配到模板，并且用户的模板审核方式是未匹配到就进审核");
		failMsgMap.put("WL:KHLJ", "命中空号，进拦截");
		failMsgMap.put("WL:QHLJ", "命中用户签名黑名单，进拦截");
		failMsgMap.put("WL:SHLJ", "命中用户SPID黑名单，进拦截");
		failMsgMap.put("WL:CHLJ", "命中系统产品黑名单，进拦截");
		failMsgMap.put("WL:CWHM", "错误号码");
		failMsgMap.put("WL:QWBB", "签名未报备，进拦截");
		failMsgMap.put("WL:MQM", "需要签名但没有，进拦截");
		failMsgMap.put("WL:CS", "超过限速了");
		failMsgMap.put("WL:ZJLJ", "不匹配任何模板，直接拦截");
		failMsgMap.put("WL:CMT", "产品未配置相应通道，进拦截");
		failMsgMap.put("WL:CDQC", "通道不支持该地区发送，进拦截");
		failMsgMap.put("WL:CGMT", "产品通道池中没有相应通道，进拦截");
		failMsgMap.put("WL:CNH", "所选的通道不健康，进拦截");
		failMsgMap.put("WL:TCLJ", "不在发送时间段，进拦截");
		failMsgMap.put("WL:TCSH", "不在发送时间段，进审核");
		failMsgMap.put("WL:CPL", "超频限制");

		failCodeMap = new HashMap<>();
		failCodeMap.put("10000", "服务出错，请稍后再试");
		failCodeMap.put("10001", "参数错误，请确认");
		failCodeMap.put("10008", "账号被锁定，请联系管理员确认");
		failCodeMap.put("10011", "余额不足，请尽快充值");
		failCodeMap.put("10100", "签名校验失败");
		failCodeMap.put("10101", "您的ip不在白名单内，请确认");
		failCodeMap.put("10102", "密码错误，请确认");
		failCodeMap.put("10200", "产品sp_id必须填写");
		failCodeMap.put("10201", "手机号必须填写");
		failCodeMap.put("10202", "短信内容必须填写");
		failCodeMap.put("10203", "发送时间格式必须为UNIX时间戳");
		failCodeMap.put("10208", "短信进拦截，具体原因参考data字段");
		failCodeMap.put("10209", "触发防刷，请调整配置");
	}
}