package com.palmnest.service.wechat.impl;

import com.alibaba.fastjson.JSONObject;
import com.palmnest.application.Constants;
import com.palmnest.application.bean.Articles;
import com.palmnest.application.bean.InMessage;
import com.palmnest.application.bean.OutMessage;
import com.palmnest.application.core.util.DateUtils;
import com.palmnest.application.core.util.HttpKit;
import com.palmnest.application.core.util.PropertiesKit;
import com.palmnest.application.core.util.XStreamFactory;
import com.palmnest.model.estateserve.WxPublicno;
import com.palmnest.service.estateserve.PublicNoManager;
import com.palmnest.service.redis.BaseRedisService;
import com.palmnest.service.wechat.MessageProcessingManager;
import com.palmnest.service.wechat.WeChatAccessManager;
import com.thoughtworks.xstream.XStream;

import lombok.extern.slf4j.Slf4j;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;

import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 后台微信处理接口实现类
 *
 * @author Administrator
 */
@Slf4j
@Component("weChatAccessManager")
public class WeChatAccessManagerImpl implements WeChatAccessManager {


	private String updateTokenPower = PropertiesKit.readPropertiesValue("updateTokenPower", "wechat.properties");

	@Autowired
	private MessageProcessingManager messageProcessingManager;
	@Autowired
	private PublicNoManager          publicNoManager;
	@Autowired
	private BaseRedisService baseRedisService;

	@PostConstruct
	@Override
	public void updateAccessToken() {
		try {
			// 更新令牌的开关判断 -测试服务一般是关闭的 生产开的
			if ("on".equals(updateTokenPower)) {
				List<WxPublicno> publicnos = publicNoManager.getAllWxPublicno();
				for (WxPublicno wxPublicno : publicnos) {
					try {
						getToken(wxPublicno);
					} catch (Exception ex) {
						log.error("UpdateAccessTokenTask run() error developid." + wxPublicno.getDevelopId()  + ex.getMessage());
					}
				}
			} else {
				log.warn("updateTokenPower not on ...");
			}
		} catch (Exception e) {
			e.printStackTrace();
			log.error("UpdateAccessTokenTask run() occur error.{}" + e.getCause(), e.getMessage());
		}
	}

	@Override
	public String getAccessToken(String developId) {

		log.info(developId + " getAccessToken.");

		String access_token = "";

		try {

			WxPublicno wxPublicno = publicNoManager.getByDevelopId(developId);
			access_token = getToken(wxPublicno);

		} catch (Exception e) {
			e.printStackTrace();
			log.error("getAccessToken() occur error.{}" + e.getCause(), e.getMessage());
		}

		return access_token;
	}

	private String getToken(WxPublicno wxPublicno)
			throws NoSuchAlgorithmException, NoSuchProviderException, IOException, KeyManagementException {

		String access_token = "";

		if (wxPublicno != null) {

			if (StringUtils.isNotEmpty(wxPublicno.getGetAccessTokenUrl())) {

				access_token = getTokenWithOuterUrl(wxPublicno);

			} else {

				// String jsonStr = HttpKit.get(Constants.ACCESSTOKEN_URL.concat("&appid=") + wxPublicno.getAppId() + "&secret=" + wxPublicno.getAppSecret());
				Map<String, Object> paramMap = new HashMap<>();
				paramMap.put("grant_type", "client_credential");
				paramMap.put("appid", wxPublicno.getAppId());
				paramMap.put("secret", wxPublicno.getAppSecret());
				String jsonStr = HttpKit.HttpClientPost(JSONObject.toJSONString(paramMap), Constants.STABLE_ACCESS_TOKEN_URL);

				log.info(DateUtils.getDate("yyyy-MM-dd HH:mm:ss") + " getAccessToken,developid." + wxPublicno.getDevelopId() + "," + wxPublicno.getName());
				log.info("#jsonStr1:" + jsonStr);

				Map<String, Object> map = JSONObject.parseObject(jsonStr);

				if (map.get("access_token") != null) {

					//存储消息令牌
//					Constants.CacheMap.put(wxPublicno.getDevelopId(), map.get("access_token").toString());
					baseRedisService.set(Constants.JSAPI_ACCESS_TOKEN+wxPublicno.getDevelopId(), map.get("access_token").toString(),Constants.TOKEN_TIME);
					
					access_token = map.get("access_token").toString();

					// jsapi_ticket
					jsonStr = HttpKit.get(Constants.JSAPI_URL + map.get("access_token").toString());
					Map<String, Object> jsApiMap = JSONObject.parseObject(jsonStr);
					log.info("#jsonStr2:" + jsonStr);

					//lmz 2021-03-29 写的，但由于不清楚别的地方调用的逻辑，暂时不做这个的判断
//					if(jsApiMap.containsKey("errcode") && null != jsApiMap.get("errcode") && StringUtils.isNotBlank(jsApiMap.get("errcode").toString()) && 0 == Integer.parseInt(jsApiMap.get("errcode").toString()) ){
//						// 存储 jsapi_ticket
//						Constants.CacheMap.put("jsapi_" + wxPublicno.getDevelopId(), jsApiMap.get("ticket").toString());
//					}else{
//						//token不能用的时候没必要往下走
//						return "";
//					}
					
					baseRedisService.set(Constants.JSAPI+wxPublicno.getDevelopId(), jsApiMap.get("ticket").toString(),Constants.TOKEN_TIME);
//					Constants.CacheMap.put("jsapi_" + wxPublicno.getDevelopId(), jsApiMap.get("ticket").toString());
					
				}
			}
		}

		return access_token;
	}

	@Override
	public String getJsApiTicket(String developId) {

		log.info(developId + " getJsApiTicket.");
		String jsApiTicket = "";

		try {

			// jsapi_ticket
//			String              jsonStr  = HttpKit.get(Constants.JSAPI_URL + Constants.CacheMap.get(developId));
			String rs=baseRedisService.get(Constants.JSAPI_ACCESS_TOKEN+developId);;
			String jsonStr  =HttpKit.get(Constants.JSAPI_URL + rs);
			
			Map<String, Object> jsApiMap = JSONObject.parseObject(jsonStr);

			log.info("#jsonStr2:" + jsonStr);

			// 存储 jsapi_ticket
//			Constants.CacheMap.put("jsapi_" + developId, jsApiMap.get("ticket").toString());
			baseRedisService.set(Constants.JSAPI+developId, jsApiMap.get("ticket").toString(),Constants.TOKEN_TIME);

			jsApiTicket = jsApiMap.get("ticket").toString();

		} catch (Exception e) {
			e.printStackTrace();
			log.error("getJsApiTicket() occur error.{}" + e.getCause(), e.getMessage());
		}
		return jsApiTicket;
	}

	@Override
	public String saveProcessing(String responseInputString) throws Exception {
		InMessage  inMessage = parsingInMessage(responseInputString);
		OutMessage oms       = null;
		String     xml       = "success";
		try {
			//取得消息类型
			String type          = inMessage.getMsgType();
			Method getOutMessage = messageProcessingManager.getClass().getMethod("getOutMessage");
			//Method alMt = messageProcessingManager.getClass().getMethod("allType", InMessage.class);
			Method mt = messageProcessingManager.getClass().getMethod(type + "TypeMsg", InMessage.class);
			//默认执行类型方法执行
			//alMt.invoke(messageProcessingManager, inMessage);
			//具体业务类型方法执行
			if (mt != null) {
				mt.invoke(messageProcessingManager, inMessage);
			}
			//获取处理返回信息
			Object obj = getOutMessage.invoke(messageProcessingManager);
			if (obj != null) {
				oms = (OutMessage) obj;
				setMsgInfo(oms, inMessage);
			}
		} catch (Exception e) {
			log.error("processing occur error.{}" + e + e.getMessage());
			throw new RuntimeException(e);
		}
		if (oms != null) {
			// 把发送对象转换为xml输出
			XStream xs = XStreamFactory.init(true);
			xs.alias("xml", oms.getClass());
			xs.alias("item", Articles.class);
			xml = xs.toXML(oms);
		}
		return xml;
	}

	/**
	 * 消息体转换
	 *
	 * @param responseInputString
	 * @return
	 */
	private static InMessage parsingInMessage(String responseInputString) {
		//转换微信post过来的xml内容
		XStream xs = XStreamFactory.init(false);
		xs.ignoreUnknownElements();
		xs.alias("xml", InMessage.class);
		InMessage msg = (InMessage) xs.fromXML(responseInputString);
		return msg;
	}

	public void setMsgInfo(OutMessage oms, InMessage msg) throws Exception {
		if (oms != null) {
			Class<?> outMsg       = oms.getClass().getSuperclass();
			Field    CreateTime   = outMsg.getDeclaredField("CreateTime");
			Field    ToUserName   = outMsg.getDeclaredField("ToUserName");
			Field    FromUserName = outMsg.getDeclaredField("FromUserName");

			ToUserName.setAccessible(true);
			CreateTime.setAccessible(true);
			FromUserName.setAccessible(true);
			CreateTime.set(oms, new Date().getTime());
			ToUserName.set(oms, msg.getFromUserName());
			FromUserName.set(oms, msg.getToUserName());
		}
	}

	@Override
	public void updateAccessTokenWithOuterUrl() {
		try {
			//更新令牌的开关判断 -测试服务一般是关闭的 生产开的
			if ("on".equals(updateTokenPower)) {
				List<WxPublicno> publicnos = publicNoManager.getAllWxPublicnoWithOuterUrl();
				for (WxPublicno wxPublicno : publicnos) {
					getTokenWithOuterUrl(wxPublicno);
				}
			} else {
				log.warn("updateTokenPower not on ...");
			}
		} catch (Exception e) {
			e.printStackTrace();
			log.error("UpdateAccessTokenTask run() occur error.{}" + e.getCause(), e.getMessage());
		}
	}

	private String getTokenWithOuterUrl(WxPublicno wxPublicno) throws KeyManagementException, NoSuchAlgorithmException, NoSuchProviderException, IOException {

		String access_token = "";

		if (wxPublicno != null && StringUtils.isNotEmpty(wxPublicno.getGetAccessTokenUrl())) {

			String jsonStr = HttpKit.Post("developId=" + wxPublicno.getDevelopId(), wxPublicno.getGetAccessTokenUrl());

			log.info(DateUtils.getDate("yyyy-MM-dd HH:mm:ss") + " getAccessToken,developid." + wxPublicno.getDevelopId() + "," + wxPublicno.getName());
			log.info("#jsonStr1:" + jsonStr);

			Map<String, Object> map = JSONObject.parseObject(jsonStr);
			if (map != null && map.get("returnDTO") != null) {
				String json = map.get("returnDTO").toString();
				//System.out.println("json:"+json);
				map = JSONObject.parseObject(json);
			}

			if (map != null && map.get("accessToken") != null) {
				//存储消息令牌
//				Constants.CacheMap.put(wxPublicno.getDevelopId(), map.get("accessToken").toString());
				baseRedisService.set(Constants.JSAPI_ACCESS_TOKEN+wxPublicno.getDevelopId(), map.get("accessToken").toString(),Constants.TOKEN_TIME);
				access_token = map.get("accessToken").toString();
				//System.out.println("access_token"+access_token);
				//System.out.println("access_token:"+access_token);
				//jsapi_ticket
				jsonStr = HttpKit.get(Constants.JSAPI_URL + map.get("accessToken").toString());
				Map<String, Object> jsApiMap = JSONObject.parseObject(jsonStr);
				log.info("#jsonStr2:" + jsonStr);
				//System.out.println("#jsonStr2:" + jsonStr);
				//存储jsapi票据
				if (jsApiMap.get("ticket") != null) {
//					Constants.CacheMap.put("jsapi_" + wxPublicno.getDevelopId(), jsApiMap.get("ticket").toString());
					baseRedisService.set(Constants.JSAPI+wxPublicno.getDevelopId(), jsApiMap.get("ticket").toString(),Constants.TOKEN_TIME);
				}
			}

		} else {
			log.info("wxPublicno为空或者获取token链接为空");
		}
		return access_token;
	}
}
