package com.neusoft.smart.pos.payment.repository;

import com.neusoft.smart.pos.constants.DictionaryConstant;
import com.neusoft.smart.pos.framework.constants.ApplicationConstants;
import com.neusoft.smart.pos.framework.exception.BusinessCommonException;
import com.neusoft.smart.pos.framework.utils.FileUtils;
import com.neusoft.smart.pos.framework.utils.LocalIpUtils;
import com.neusoft.smart.pos.framework.utils.MapBeanUtils;
import com.neusoft.smart.pos.payment.constants.PaymentErrorCode;
import com.neusoft.smart.pos.payment.constants.WXUsPayConstants;
import com.neusoft.smart.pos.payment.persistent.domain.MchPayChannel;
import com.neusoft.smart.pos.payment.persistent.domain.PayOrder;
import com.neusoft.smart.pos.payment.persistent.domain.PayTypeDict;
import com.neusoft.smart.pos.payment.persistent.ext.domain.*;
import com.neusoft.smart.pos.payment.utils.HttpClientUtils;
import com.neusoft.smart.pos.payment.utils.LogUtils;
import com.neusoft.smart.pos.payment.utils.WXPayUtils;
import lombok.val;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.io.InputStream;

/**
 * @author zcf
 * @date 2018-10-08 10：43
 * @description 微信服务商国际支付使用Repository
 */
@Component("weiXinUsPayServiceRepository")
public class WeiXinUsPayServiceRepository implements IThirdPayRepository {

	/**
	 * 创建微信支付单使用方法
	 * @param payOrder
	 * @param mchPayChannel
	 * @return
	 */
	@Override
	public ThirdPlatformCreateOrder createPayOrderToThirdPlatform(PayOrder payOrder, MchPayChannel mchPayChannel, PayTypeDict payTypeDict){
		//1.处理数据
		String weixinRequestData =  weixinCreateOrderRequestDataHandle(payOrder,mchPayChannel,payTypeDict);
		//2.请求微信预付单生成接口
        String responseData = "";
        if(StringUtils.isEmpty(payOrder.getScanCode())){
        	//用户主动扫码支付
			responseData = HttpClientUtils.postXMLData(WXUsPayConstants.DOMAIN_API+WXUsPayConstants.UNIFIEDORDER_URL_SUFFIX,weixinRequestData);
		}else{
        	//商户扫码支付
			responseData = HttpClientUtils.postXMLData(WXUsPayConstants.DOMAIN_API+WXUsPayConstants.MICROPAY_URL_SUFFIX,weixinRequestData);
		}
        //3.记录日志
		LogUtils.savePaymentTradeLog(payOrder.getMcode(),payOrder.getmOrderNumber(), DictionaryConstant.PAYMENT_PAY_TYPE_WXZF_US_SERCIE.getCode(),LogUtils.LOG_DESCRIPTION_DDSC,weixinRequestData,responseData,DictionaryConstant.PAYMENT_REQUEST_TYPE_ZD.getCode());

		return weixinCreateOrderResponseDataHandle(payOrder,responseData);
	}

	/**
	 * 微信数据整理方法
	 * @param payOrder
	 * @param mchPayChannel
	 * @return
	 */
	private String weixinCreateOrderRequestDataHandle(PayOrder payOrder, MchPayChannel mchPayChannel,PayTypeDict payTypeDict){
		val weixinPayOrder = new WeixinUsPayServiceCreateOrder();
		weixinPayOrder.setAppid(mchPayChannel.getAppid());
		weixinPayOrder.setMch_id(mchPayChannel.getMchId());
		weixinPayOrder.setSub_appid(mchPayChannel.getSubAppid());
		weixinPayOrder.setSub_mch_id(mchPayChannel.getSubMchId());
		weixinPayOrder.setNonce_str(WXPayUtils.generateNonceStr());
		weixinPayOrder.setBody(payOrder.getDescription());
		weixinPayOrder.setOut_trade_no(payOrder.getmOrderNumber());
		weixinPayOrder.setTotal_fee(String.valueOf(payOrder.getOrderAmount()));
		weixinPayOrder.setOpenid(payOrder.getOpenId());
		weixinPayOrder.setFee_type("JPY");
		if(StringUtils.isEmpty(payOrder.getPayIp())){
			weixinPayOrder.setSpbill_create_ip(LocalIpUtils.getLocalIP());
		}else{
			weixinPayOrder.setSpbill_create_ip(payOrder.getPayIp());
		}
		weixinPayOrder.setTime_expire(payOrder.getTimeExpire());
		weixinPayOrder.setAttach(payOrder.getMcode());
		if(!StringUtils.isEmpty(payOrder.getScanCode())){
			weixinPayOrder.setAuth_code(payOrder.getScanCode());
		}else{
			weixinPayOrder.setNotify_url(payTypeDict.getNotifyUrl());
			weixinPayOrder.setProduct_id(payOrder.getmOrderNumber());
			weixinPayOrder.setTrade_type(payOrder.getTradeType());
		}
		return WXPayUtils.generateSignedXml(MapBeanUtils.beanToMap(weixinPayOrder),mchPayChannel.getSecretKey());
	}

	/**
	 * 微信支付响应数据处理
	 * @param payOrder
	 * @param responseData
	 * @return
	 */
	private ThirdPlatformCreateOrder weixinCreateOrderResponseDataHandle(PayOrder payOrder, String responseData){
		val resultMap = WXPayUtils.xmlToMap(responseData);
		if(!resultMap.get("return_code").equalsIgnoreCase(ApplicationConstants.SUCCESS)){
			throw new BusinessCommonException(PaymentErrorCode.MCH_ORDER_GENERATE_ERROR);
		}
		if(!resultMap.get("result_code").equalsIgnoreCase(ApplicationConstants.SUCCESS)){
			if(resultMap.get("err_code").equalsIgnoreCase("AUTH_CODE_INVALID")){
				throw new BusinessCommonException(PaymentErrorCode.WX_AUTH_CODE_INVALID);
			}
			if(resultMap.get("err_code").equalsIgnoreCase("USERPAYING")){
				//等待用户支付
//				throw new BusinessCommonException(PaymentErrorCode.WX_AUTH_CODE_INVALID);
			}
		}
		val thirdPlatformOrder = new ThirdPlatformCreateOrder();
		thirdPlatformOrder.setMcode(payOrder.getMcode());
		thirdPlatformOrder.setTradeId(payOrder.getTradeId());
		thirdPlatformOrder.setMOrderNumber(payOrder.getmOrderNumber());
		thirdPlatformOrder.setOuterOrderNumber(resultMap.get("prepay_id"));

		if(payOrder.getTradeType().equals("NATIVE")){
			thirdPlatformOrder.setOuterCodeUrl(resultMap.get("code_url"));
		}else{
			thirdPlatformOrder.setOuterCodeUrl(resultMap.get("mweb_url"));
		}
		if(!StringUtils.isEmpty(payOrder.getScanCode())){
			if(resultMap.get("result_code").equalsIgnoreCase(ApplicationConstants.SUCCESS)){
				thirdPlatformOrder.setPayStatus(DictionaryConstant.PAY_STATUS_YFK.getCode());
			}
		}
		return thirdPlatformOrder;
	}

	/**
	 * 微信预付订单查询方法
	 * @param payOrder
	 * @param mchPayChannel
	 * @return
	 */
	public ThirdPlatformQueryOrder queryPayOrderFromThirdPlatform(PayOrder payOrder, MchPayChannel mchPayChannel){
		//1.处理数据
		val weixinPayQueryOrder = new WeixinPayServiceQueryOrder();
		weixinPayQueryOrder.setAppid(mchPayChannel.getAppid());
		weixinPayQueryOrder.setMch_id(mchPayChannel.getMchId());
		weixinPayQueryOrder.setSub_appid(mchPayChannel.getSubAppid());
		weixinPayQueryOrder.setSub_mch_id(mchPayChannel.getSubMchId());
		weixinPayQueryOrder.setNonce_str(WXPayUtils.generateNonceStr());
		weixinPayQueryOrder.setOut_trade_no(payOrder.getmOrderNumber());
		String weixinRequestData =  WXPayUtils.generateSignedXml(MapBeanUtils.beanToMap(weixinPayQueryOrder),mchPayChannel.getSecretKey());
		//2.请求微信预付单生成接口
		String responseData = HttpClientUtils.postXMLData(WXUsPayConstants.DOMAIN_API+WXUsPayConstants.ORDER_QUERY_URL_SUFFIX,weixinRequestData);
		//3.记录日志
		LogUtils.savePaymentTradeLog(mchPayChannel.getMcode(),payOrder.getmOrderNumber(), DictionaryConstant.PAYMENT_PAY_TYPE_WXZF_US_SERCIE.getCode(),LogUtils.LOG_DESCRIPTION_DDCS,weixinRequestData,responseData,DictionaryConstant.PAYMENT_REQUEST_TYPE_ZD.getCode());
		return weixinQueryOrderResponseDataHandle(mchPayChannel.getMcode(),payOrder.getmOrderNumber(),responseData);
	}

	/**
	 * 微信支付响应数据处理
	 * @return
	 */
	private ThirdPlatformQueryOrder weixinQueryOrderResponseDataHandle(String mcode,String orderNumber, String responseData){
		val resultMap = WXPayUtils.xmlToMap(responseData);
		if(!resultMap.get("return_code").equalsIgnoreCase(ApplicationConstants.SUCCESS)||!resultMap.get("result_code").equalsIgnoreCase(ApplicationConstants.SUCCESS)){
			throw new BusinessCommonException(PaymentErrorCode.MCH_ORDER_GENERATE_ERROR);
		}
		val thirdPlatformOrder = new ThirdPlatformQueryOrder();
		thirdPlatformOrder.setMcode(mcode);
		thirdPlatformOrder.setMOrderNumber(orderNumber);
		thirdPlatformOrder.setOuterTradeNumber(resultMap.get("transaction_id")==null?"":resultMap.get("transaction_id"));
		thirdPlatformOrder.setTradeStatus(getTradeStatus(resultMap.get("trade_state")));
		thirdPlatformOrder.setTimeEnd(resultMap.get("time_end"));
		return thirdPlatformOrder;
	}

	/**
	 * 根据微信交易状态返回支付平台订单状态
	 * @param tradeState
	 * @return
	 */
	private String getTradeStatus(String tradeState){
		String tradeStatus = DictionaryConstant.PAYMENT_ORDER_STATUS_DZF.getCode();
		switch(tradeState){
			case "SUCCESS":
				//支付成功
				tradeStatus = DictionaryConstant.PAYMENT_ORDER_STATUS_YZF.getCode();
				break;
			case "REFUND":
				//转入退款
				tradeStatus = DictionaryConstant.PAYMENT_ORDER_STATUS_TKZ.getCode();
				break;
			case "NOTPAY":
				//未支付
				tradeStatus = DictionaryConstant.PAYMENT_ORDER_STATUS_DZF.getCode();
				break;
			case "CLOSED":
				//已关闭
				tradeStatus = DictionaryConstant.PAYMENT_ORDER_STATUS_JYGB.getCode();
				break;
			case "REVOKED":
				//已撤销（刷卡支付）
				tradeStatus = DictionaryConstant.PAYMENT_ORDER_STATUS_DZF.getCode();
				break;
			case "USERPAYING":
				//用户支付中
				tradeStatus = DictionaryConstant.PAYMENT_ORDER_STATUS_DZF.getCode();
				break;
			case "PAYERROR":
				//支付失败(其他原因，如银行返回失败)
				tradeStatus = DictionaryConstant.PAYMENT_ORDER_STATUS_DZF.getCode();
				break;
		}
		return tradeStatus;
	}

	/**
	 * 微信预付订单取消方法
	 * @param payOrder
	 * @param mchPayChannel
	 * @return
	 */
	public ThirdPlatformCancelOrder cannelPayOrderFromThirdPlatform(PayOrder payOrder, MchPayChannel mchPayChannel){
		//1.处理数据
		val weixinPayServiceCannelOrder = new WeixinPayServiceCannelOrder();
		weixinPayServiceCannelOrder.setAppid(mchPayChannel.getAppid());
		weixinPayServiceCannelOrder.setMch_id(mchPayChannel.getMchId());
		weixinPayServiceCannelOrder.setSub_mch_id(mchPayChannel.getSubMchId());
		weixinPayServiceCannelOrder.setNonce_str(WXPayUtils.generateNonceStr());
		weixinPayServiceCannelOrder.setOut_trade_no(payOrder.getmOrderNumber());
		String weixinRequestData =  WXPayUtils.generateSignedXml(MapBeanUtils.beanToMap(weixinPayServiceCannelOrder),mchPayChannel.getSecretKey());
		//2.请求微信预付单生成接口
		String responseData = HttpClientUtils.postXMLData(WXUsPayConstants.DOMAIN_API+WXUsPayConstants.ORDER_CANNEL_URL_SUFFIX,weixinRequestData);
		//3.记录日志
		LogUtils.savePaymentTradeLog(mchPayChannel.getMcode(),payOrder.getmOrderNumber(), DictionaryConstant.PAYMENT_PAY_TYPE_WXZF_US_SERCIE.getCode(),LogUtils.LOG_DESCRIPTION_DDQX,weixinRequestData,responseData,DictionaryConstant.PAYMENT_REQUEST_TYPE_ZD.getCode());
		return weixinCannelOrderResponseDataHandle(mchPayChannel.getMcode(),payOrder.getmOrderNumber(),responseData);
	}

	/**
	 * 微信支付订单取消响应数据处理
	 * @return
	 */
	private ThirdPlatformCancelOrder weixinCannelOrderResponseDataHandle(String mcode,String orderNumber, String responseData){
		val resultMap = WXPayUtils.xmlToMap(responseData);
		val thirdPlatformCancelOrder = new ThirdPlatformCancelOrder();
		thirdPlatformCancelOrder.setMcode(mcode);
		thirdPlatformCancelOrder.setMOrderNumber(orderNumber);
		thirdPlatformCancelOrder.setPayType(DictionaryConstant.PAYMENT_PAY_TYPE_WXZF_US_SERCIE.getCode());
		if(!resultMap.get("return_code").equalsIgnoreCase(ApplicationConstants.SUCCESS)||!resultMap.get("result_code").equalsIgnoreCase(ApplicationConstants.SUCCESS)){
			thirdPlatformCancelOrder.setCancelStatus("0");
		}else{
			thirdPlatformCancelOrder.setCancelStatus("1");
		}
		return thirdPlatformCancelOrder;
	}

	@Autowired
	private MchPayChannelRepository mchPayChannelRepository;

	/**
	 * 微信预付订单退款申请方法
	 * @param payOrder
	 * @param mchPayChannel
	 * @param refundAmount:退款金额
	 * @return
	 */
	@Override
	public ThirdPlatformRefundOrder refundPayOrderFromThirdPlatform(PayOrder payOrder,String refundNumber,Long refundAmount, MchPayChannel mchPayChannel,PayTypeDict payTypeDict) {
		val weixinPayServiceRefundOrder = new WeixinPayServiceRefundOrder();
		weixinPayServiceRefundOrder.setAppid(mchPayChannel.getAppid());
		weixinPayServiceRefundOrder.setMch_id(mchPayChannel.getMchId());
		weixinPayServiceRefundOrder.setSub_mch_id(mchPayChannel.getSubMchId());
		weixinPayServiceRefundOrder.setNonce_str(WXPayUtils.generateNonceStr());
		weixinPayServiceRefundOrder.setOut_trade_no(payOrder.getmOrderNumber());
		weixinPayServiceRefundOrder.setOut_refund_no(refundNumber);
		weixinPayServiceRefundOrder.setRefund_fee(payOrder.getOrderAmount());
		weixinPayServiceRefundOrder.setTotal_fee(payOrder.getOrderAmount());
		weixinPayServiceRefundOrder.setNotify_url(payTypeDict.getRefundNotifyUrl());
		String weixinRequestData =  WXPayUtils.generateSignedXml(MapBeanUtils.beanToMap(weixinPayServiceRefundOrder),mchPayChannel.getSecretKey());
		//2.请求微信退款申请接口
		InputStream instream = FileUtils.convertByteArrayToInputStream(mchPayChannel.getCert());
		String responseData = HttpClientUtils.postXmlDataWithCert(WXUsPayConstants.DOMAIN_API+WXUsPayConstants.ORDER_REFUND_URL_SUFFIX,weixinRequestData,weixinPayServiceRefundOrder.getMch_id(),instream);
		//3.记录日志
		LogUtils.savePaymentTradeLog(payOrder.getMcode(),payOrder.getmOrderNumber(), DictionaryConstant.PAYMENT_PAY_TYPE_WXZF_US_SERCIE.getCode(),LogUtils.LOG_DESCRIPTION_SQTK,weixinRequestData,responseData,DictionaryConstant.PAYMENT_REQUEST_TYPE_ZD.getCode());

		return weixinRefundOrderResponseDataHandle(payOrder,responseData);
	}

	/**
	 * 微信退款申请响应数据处理
	 * @param payOrder
	 * @param responseData
	 * @return
	 */
	private ThirdPlatformRefundOrder weixinRefundOrderResponseDataHandle(PayOrder payOrder, String responseData){
		val resultMap = WXPayUtils.xmlToMap(responseData);
		if(!resultMap.get("return_code").equalsIgnoreCase(ApplicationConstants.SUCCESS)){
			throw new BusinessCommonException(PaymentErrorCode.MCH_ORDER_REFUND_ERROR);
		}
		val thirdPlatformOrder = new ThirdPlatformRefundOrder();
		thirdPlatformOrder.setMcode(payOrder.getMcode());
		thirdPlatformOrder.setMOrderNumber(payOrder.getmOrderNumber());
		thirdPlatformOrder.setPayType(payOrder.getPayType());
		if(!resultMap.get("result_code").equalsIgnoreCase(ApplicationConstants.SUCCESS)){
			if(resultMap.get("err_code").equalsIgnoreCase("ORDERNOTEXIST")){
				thirdPlatformOrder.setRefundStatus("3");
			}else{
				thirdPlatformOrder.setRefundStatus("0");
			}
		}else{
			thirdPlatformOrder.setRefundNumber(resultMap.get("out_refund_no"));
			thirdPlatformOrder.setThirdRefundNumber(resultMap.get("refund_id"));
			thirdPlatformOrder.setRefundAmount(Long.parseLong(resultMap.get("refund_fee")));
			thirdPlatformOrder.setRefundStatus("1");
		}
		return thirdPlatformOrder;
	}

	/**
	 * 预付单撤销使用方法
	 * @return
	 */
	public ThirdPlatformReverseOrder reversePayOrderFromThirdPlatform(PayOrder payOrder, String orderNumber, MchPayChannel mchPayChannel){
		//1.处理数据
		val weixinPayServiceReverseOrder = new WeixinPayServiceReverseOrder();
		weixinPayServiceReverseOrder.setAppid(mchPayChannel.getAppid());
		weixinPayServiceReverseOrder.setMch_id(mchPayChannel.getMchId());
		weixinPayServiceReverseOrder.setSub_mch_id(mchPayChannel.getSubMchId());
		weixinPayServiceReverseOrder.setNonce_str(WXPayUtils.generateNonceStr());
		weixinPayServiceReverseOrder.setOut_trade_no(orderNumber);
		String weixinRequestData =  WXPayUtils.generateSignedXml(MapBeanUtils.beanToMap(weixinPayServiceReverseOrder),mchPayChannel.getSecretKey());
		InputStream instream = FileUtils.convertByteArrayToInputStream(mchPayChannel.getCert());
		//2.请求微信预付单生成接口
		String responseData = HttpClientUtils.postXmlDataWithCert(WXUsPayConstants.DOMAIN_API+WXUsPayConstants.ORDER_REVERSE_URL_SUFFIX,weixinRequestData,weixinPayServiceReverseOrder.getMch_id(),instream);
		//3.记录日志
		LogUtils.savePaymentTradeLog(mchPayChannel.getMcode(),orderNumber, DictionaryConstant.PAYMENT_PAY_TYPE_WXZF_US_SERCIE.getCode(),LogUtils.LOG_DESCRIPTION_DDCX,weixinRequestData,responseData,DictionaryConstant.PAYMENT_REQUEST_TYPE_ZD.getCode());
		return weixinReverseOrderResponseDataHandle(mchPayChannel.getMcode(),orderNumber,responseData);
	}

	/**
	 * 微信支付订单撤销响应数据处理
	 * @return
	 */
	private ThirdPlatformReverseOrder weixinReverseOrderResponseDataHandle(String mcode,String orderNumber, String responseData){
		val resultMap = WXPayUtils.xmlToMap(responseData);
		val thirdPlatformReverseOrder = new ThirdPlatformReverseOrder();
		thirdPlatformReverseOrder.setMcode(mcode);
		thirdPlatformReverseOrder.setMOrderNumber(orderNumber);
		thirdPlatformReverseOrder.setPayType(DictionaryConstant.PAYMENT_PAY_TYPE_WXZF_US_SERCIE.getCode());
		if(!resultMap.get("return_code").equalsIgnoreCase(ApplicationConstants.SUCCESS)||!resultMap.get("result_code").equalsIgnoreCase(ApplicationConstants.SUCCESS)){
			if(resultMap.get("err_code").equalsIgnoreCase("NOT_ALLOW")){
				throw new BusinessCommonException(PaymentErrorCode.WX_PAY_NOT_ALLOW);
			}
			thirdPlatformReverseOrder.setReverseStatus("1");
		}else{
			thirdPlatformReverseOrder.setReverseStatus("2");
		}
		return thirdPlatformReverseOrder;
	}
}
