package tech.glinfo.enbao.common.controller;

import com.alibaba.fastjson.JSON;
import com.alipay.api.AlipayApiException;
import com.alipay.api.domain.AlipayTradeAppPayModel;
import com.alipay.api.internal.util.AlipaySignature;
import tech.glinfo.enbao.common.pay.alipay.AliPayApi;
import tech.glinfo.enbao.common.pay.alipay.AliPayApiConfig;
import tech.glinfo.enbao.common.pay.alipay.AliPayApiConfigKit;
import tech.glinfo.enbao.common.pay.common.enums.SignType;
import tech.glinfo.enbao.common.pay.common.enums.TradeType;
import tech.glinfo.enbao.common.pay.common.kit.HttpKit;
import tech.glinfo.enbao.common.pay.common.kit.IpKit;
import tech.glinfo.enbao.common.pay.common.kit.WxPayKit;
import tech.glinfo.enbao.common.pay.entity.AliPayBean;
import tech.glinfo.enbao.common.pay.entity.WxPayBean;
import tech.glinfo.enbao.common.pay.wx.WxPayApi;
import tech.glinfo.enbao.common.pay.wx.model.UnifiedOrderModel;
import tech.glinfo.enbao.common.utils.HttpContextUtils;
import tech.glinfo.enbao.common.utils.R;
import tech.glinfo.enbao.common.utils.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;

import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;

/**
 * Controller公共组件
 *
 * @author Mark linzhenjie@gltech.com
 */
public abstract class AbstractPayController {
	protected Logger logger = LoggerFactory.getLogger(getClass());

	@Autowired
	private WxPayBean wxPayBean;
	@Autowired
	private AliPayBean aliPayBean;
	@Value("${pay.domain}")
	private String domain;

	/**
	 * 微信支付
	 * @param params
	 * @return
	 */
	public R wpay(Map<String, String> params) {

		HttpServletRequest request = HttpContextUtils.getHttpServletRequest();
		String ip = IpKit.getRealIp(request);
		if (StringUtils.isBlank(ip)) {
			ip = "127.0.0.1";
		}

		Map<String, String> buildParams = UnifiedOrderModel
				.builder()
				.appid(wxPayBean.getAppId())
				.mch_id(wxPayBean.getMchId())
				.nonce_str(WxPayKit.generateStr())
				.body("众物共享-微信支付")
				.detail(params.get("detail"))
				.attach(params.get("orderId"))//附加数据，在查询API和支付通知中原样返回，该字段主要用于商户携带订单的自定义数据
				.out_trade_no(params.get("outTradeNo"))//商户订单号
				.total_fee(params.get("money"))
				.spbill_create_ip(ip)
				.notify_url(domain+params.get("notifyUrl"))
				.trade_type(TradeType.APP.getTradeType())
				.build()
				.createSign(wxPayBean.getPartnerKey(), SignType.HMACSHA256);

		String xmlResult = WxPayApi.pushOrder(false, buildParams);

		logger.info(xmlResult);
		Map<String, String> result = WxPayKit.xmlToMap(xmlResult);

		String returnCode = result.get("return_code");
		String returnMsg = result.get("return_msg");
		if (!WxPayKit.codeIsOk(returnCode)) {
			return R.error(returnMsg);
		}
		String resultCode = result.get("result_code");
		if (!WxPayKit.codeIsOk(resultCode)) {
			return R.error(returnMsg);
		}
		// 以下字段在 return_code 和 result_code 都为 SUCCESS 的时候有返回
		String prepayId = result.get("prepay_id");

		Map<String, String> packageParams = WxPayKit.appPrepayIdCreateSign(wxPayBean.getAppId(), wxPayBean.getMchId(), prepayId,
				wxPayBean.getPartnerKey(), SignType.HMACSHA256);

		String jsonStr = JSON.toJSONString(packageParams);
		logger.info("返回apk的参数:" + jsonStr);
		Map<String, Object> rtn = new HashMap<>();
		rtn.put("data", jsonStr);
		return R.ok(rtn);
	}

	/**
	 * 支付宝支付
	 * @param params
	 * @return
	 */
	public R alipay(Map<String, String> params) {

		try {
			initApiConfig();
		} catch (AlipayApiException e) {
			return R.error(e.getErrMsg());
		}

		AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
		model.setBody("众物共享-支付宝");
		model.setSubject(params.get("detail"));
		model.setOutTradeNo(params.get("outTradeNo"));//商户网站唯一订单号
		model.setTimeoutExpress("30m");
		model.setTotalAmount(params.get("money"));
		model.setPassbackParams(params.get("orderId"));
		model.setProductCode("QUICK_MSECURITY_PAY");

		try {
			String orderInfo = AliPayApi.appPayToResponse(model, domain + params.get("notifyUrl")).getBody();
			logger.info("返回apk的参数:" + orderInfo);
			Map<String, Object> rtn = new HashMap<>();
			rtn.put("data", orderInfo);
			return R.ok(rtn);
		} catch (AlipayApiException e) {
			e.printStackTrace();
			return R.error(e.getErrMsg());
		}
	}

	/**
	 * 初始化
	 * @return
	 * @throws AlipayApiException
	 */
	private AliPayApiConfig initApiConfig() throws AlipayApiException {
		AliPayApiConfig aliPayApiConfig;
		try {
			aliPayApiConfig = AliPayApiConfigKit.getApiConfig(aliPayBean.getAppId());
		} catch (Exception e) {
			aliPayApiConfig = AliPayApiConfig.builder()
					.setAppId(aliPayBean.getAppId())
					.setAliPayPublicKey(aliPayBean.getPublicKey())
					.setAppCertPath(aliPayBean.getAppCertPath())
					.setAliPayCertPath(aliPayBean.getAliPayCertPath())
					.setAliPayRootCertPath(aliPayBean.getAliPayRootCertPath())
					.setCharset("UTF-8")
					.setPrivateKey(aliPayBean.getPrivateKey())
					.setServiceUrl(aliPayBean.getServerUrl())
					.setSignType("RSA2")
					// 普通公钥方式
					//.build();
					// 证书模式
					.buildByCert();
			//放入threadlocal
			AliPayApiConfigKit.setThreadLocalAliPayApiConfig(aliPayApiConfig);
	}
		return aliPayApiConfig;
	}

	/**
	 * 微信支付异步通知
	 * @return
	 */
	public Map<String, String> wnotify() {
		HttpServletRequest request = HttpContextUtils.getHttpServletRequest();
		String xmlMsg = HttpKit.readData(request);
		logger.info("支付通知=" + xmlMsg);
		Map<String, String> params = WxPayKit.xmlToMap(xmlMsg);

		String returnCode = params.get("return_code");
		String orderId = params.get("attach");//订单ID
		// 商户订单号
		final String out_trade_no = params.get("out_trade_no");
		// 微信支付订单号
		String transaction_id = params.get("transaction_id");
		// 注意重复通知的情况，同一订单号可能收到多次通知，请注意一定先判断订单状态
		// 注意此处签名方式需与统一下单的签名类型一致
		if (WxPayKit.verifyNotify(params, wxPayBean.getPartnerKey(), SignType.HMACSHA256)) {
			if (WxPayKit.codeIsOk(returnCode)) {
				Map<String, String> rtn = new HashMap<>();
				rtn.put("orderId", orderId);
				rtn.put("outTradeNo", out_trade_no);
				rtn.put("transactionId", transaction_id);
				return rtn;
			}
		}
		return null;
	}

	/**
	 * 支付宝异步通知
	 * @return
	 */
	public Map<String, String> anotify() {
		HttpServletRequest request = HttpContextUtils.getHttpServletRequest();
		try {
			// 获取支付宝POST过来反馈信息
			Map<String, String> params = AliPayApi.toMap(request);

			for (Map.Entry<String, String> entry : params.entrySet()) {
				logger.info(entry.getKey() + " = " + entry.getValue());
			}

//			boolean verifyResult = AlipaySignature.rsaCheckV1(params, aliPayBean.getPublicKey(), "UTF-8", "RSA2");
			boolean verifyResult = AlipaySignature.rsaCertCheckV1(params, aliPayBean.getAliPayCertPath(), "UTF-8", "RSA2");


			if (verifyResult) {
				// TODO 请在这里加上商户的业务逻辑程序代码 异步通知可能出现订单重复通知 需要做去重处理
				logger.info("notify_url 验证成功succcess");
				Map<String, String> rtn = new HashMap<>();
				rtn.put("orderId", params.get("passback_params"));
				rtn.put("outTradeNo", params.get("out_trade_no"));
				rtn.put("transactionId", params.get("trade_no"));
				return rtn;
			} else {
				System.out.println("anotify 验证失败");
			}
		} catch (AlipayApiException e) {
			e.printStackTrace();
		}

		return null;
	}
}
