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

import com.alibaba.fastjson.JSON;
import com.neusoft.smart.pos.constants.DictionaryConstant;
import com.neusoft.smart.pos.dto.payment.request.PostInitFacePayRequest;
import com.neusoft.smart.pos.framework.constants.ApplicationConstants;
import com.neusoft.smart.pos.framework.exception.BusinessCommonException;
import com.neusoft.smart.pos.framework.utils.*;
import com.neusoft.smart.pos.payment.constants.ChinaumsPayConstants;
import com.neusoft.smart.pos.payment.constants.PaymentErrorCode;
import com.neusoft.smart.pos.payment.constants.WXPayConstants;
import com.neusoft.smart.pos.payment.persistent.ext.domain.*;
import com.neusoft.smart.pos.payment.utils.ChinaumsUtils;
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 com.neusoft.smart.pos.payorder.persistent.domain.MchPayChannel;
import com.neusoft.smart.pos.payorder.persistent.domain.PayOrder;
import com.neusoft.smart.pos.payorder.persistent.domain.PayTypeDict;
import lombok.val;
import net.sf.json.JSONObject;
import org.springframework.stereotype.Component;

import java.io.InputStream;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @author zcf
 * @date 2018-07-09 10：43
 * @description 银联商务支付使用Repository
 */
@Component("chinaumsPayRepository")
public class ChinaumsPayRepository implements IThirdPayRepository {

	/**
	 * 创建银联商务支付单使用方法
	 * @param payOrder
	 * @param mchPayChannel
	 * @return
	 */
	@Override
	public String createPayOrderToThirdPlatform(PayOrder payOrder, MchPayChannel mchPayChannel, PayTypeDict payTypeDict){
		//1.处理数据
		String chinaumsRequestData =  chinaumsCreateOrderRequestDataHandle(payOrder,mchPayChannel,payTypeDict);
		//2.请求微信预付单生成接口
		String responseData = HttpClientUtils.postData(ChinaumsPayConstants.DOMAIN_API,chinaumsRequestData);
        //3.记录日志
		LogUtils.savePaymentTradeLog(payOrder.getMcode(),payOrder.getmOrderNumber(), DictionaryConstant.PAYMENT_PAY_TYPE_YLSW_SERCIE.getCode(),LogUtils.LOG_DESCRIPTION_DDSC,chinaumsRequestData,responseData,DictionaryConstant.PAYMENT_REQUEST_TYPE_ZD.getCode());

		return chinaumsCreateOrderResponseDataHandle(payOrder,responseData);
	}

	/**
	 * 银联商务数据整理方法
	 * @param payOrder
	 * @param mchPayChannel
	 * @return
	 */
	private String chinaumsCreateOrderRequestDataHandle(PayOrder payOrder, MchPayChannel mchPayChannel,PayTypeDict payTypeDict){
		val chinaumsPayOrder = new ChinaumsPayCreateOrder();
		chinaumsPayOrder.setMsgSrc(mchPayChannel.getAppSecretKey());
		chinaumsPayOrder.setRequestTimestamp(LocalDateTimeUtils.getDateTime());
		chinaumsPayOrder.setMid(mchPayChannel.getMchId());
		chinaumsPayOrder.setTid(mchPayChannel.getAppid());
		String expireTime = LocalDateTimeUtils.convertLocalDateTimeToString(LocalDateTimeUtils.convertStringToLocalDateTime(payOrder.getTimeExpire(),LocalDateTimeUtils.SIMPLE_DATETIME_FORMAT),LocalDateTimeUtils.DEFAULT_DATETIME_FORMAT);
		chinaumsPayOrder.setExpireTime(expireTime);
		chinaumsPayOrder.setNotifyUrl(payTypeDict.getNotifyUrl());
		chinaumsPayOrder.setBillNo(ChinaumsPayConstants.ORDER_NUMBER_PREFIX+payOrder.getmOrderNumber());
		chinaumsPayOrder.setBillDate(LocalDateTimeUtils.getDateTime(LocalDateTimeUtils.DEFAULT_DATE_FORMAT));
		chinaumsPayOrder.setTotalAmount(String.valueOf(payOrder.getPayAmount()));
		chinaumsPayOrder.setMsgType("bills.getQRCode");
		chinaumsPayOrder.setInstMid("QRPAYDEFAULT");
		String sign = ChinaumsUtils.makeSign(mchPayChannel.getSecretKey(), MapBeanUtils.beanToMap(chinaumsPayOrder));
		chinaumsPayOrder.setSign(sign);
		return JSON.toJSONString(chinaumsPayOrder);
	}

	/**
	 * 银联商务支付响应数据处理
	 * @param payOrder
	 * @param responseData
	 * @return
	 */
	private String chinaumsCreateOrderResponseDataHandle(PayOrder payOrder, String responseData){
		val resultMap = JSON.parseObject(responseData, HashMap.class);
		if(!resultMap.get("errCode").toString().equalsIgnoreCase(ApplicationConstants.SUCCESS)){
			throw new BusinessCommonException(PaymentErrorCode.MCH_ORDER_GENERATE_ERROR.getCode(),resultMap.get("errMsg").toString());
		}
		payOrder.setOuterOrderNumber(resultMap.get("qrCodeId").toString());
		payOrder.setCodeUrl(resultMap.get("billQRCode").toString());
		JSONObject payResponseJsonObject = new JSONObject();
		payResponseJsonObject.put("CodeUrl",payOrder.getCodeUrl());
		return payResponseJsonObject.toString();
//		val thirdPlatformOrder = new ThirdPlatformCreateOrder();
//		thirdPlatformOrder.setMcode(payOrder.getMcode());
//		thirdPlatformOrder.setTradeId(payOrder.getTradeId());
//		thirdPlatformOrder.setMOrderNumber(payOrder.getmOrderNumber());
//		thirdPlatformOrder.setOuterOrderNumber(resultMap.get("qrCodeId").toString());
//		thirdPlatformOrder.setOuterCodeUrl(resultMap.get("billQRCode").toString());
//		thirdPlatformOrder.setPayStatus(DictionaryConstant.PAY_STATUS_WFK.getCode());
//		return thirdPlatformOrder;
	}

	/**
	 * 银联商务预付订单查询方法
	 * @param payOrder
	 * @param mchPayChannel
	 * @return
	 */
	public ThirdPlatformQueryOrder queryPayOrderFromThirdPlatform(PayOrder payOrder, MchPayChannel mchPayChannel){
		//1.处理数据
		val chinaumsPayQueryOrder = new ChinaumsPayQueryOrder();
		chinaumsPayQueryOrder.setMsgSrc(mchPayChannel.getAppSecretKey());
		chinaumsPayQueryOrder.setRequestTimestamp(LocalDateTimeUtils.getDateTime());
		chinaumsPayQueryOrder.setMid(mchPayChannel.getMchId());
		chinaumsPayQueryOrder.setTid(mchPayChannel.getAppid());
		chinaumsPayQueryOrder.setBillNo(ChinaumsPayConstants.ORDER_NUMBER_PREFIX+payOrder.getmOrderNumber());
		chinaumsPayQueryOrder.setBillDate(DateUtils.format(payOrder.getCreatedAt(),DateUtils.FORMAT_SHORT));
		chinaumsPayQueryOrder.setMsgType("bills.query");
		chinaumsPayQueryOrder.setInstMid("QRPAYDEFAULT");
		String sign = ChinaumsUtils.makeSign(mchPayChannel.getSecretKey(), MapBeanUtils.beanToMap(chinaumsPayQueryOrder));
		chinaumsPayQueryOrder.setSign(sign);
		String chinaumsRequestData = JSON.toJSONString(chinaumsPayQueryOrder);
		//2.请求银商预付单生成接口
		String responseData = HttpClientUtils.postData(ChinaumsPayConstants.DOMAIN_API,chinaumsRequestData);
		//3.记录日志
		LogUtils.savePaymentTradeLog(mchPayChannel.getMcode(),payOrder.getmOrderNumber(), DictionaryConstant.PAYMENT_PAY_TYPE_YLSW_SERCIE.getCode(),LogUtils.LOG_DESCRIPTION_DDCS,chinaumsRequestData,responseData,DictionaryConstant.PAYMENT_REQUEST_TYPE_ZD.getCode());
		return chinaumsQueryOrderResponseDataHandle(mchPayChannel.getMcode(),payOrder.getmOrderNumber(),responseData);
	}

	/**
	 * 银联商务支付响应数据处理
	 * @return
	 */
	private ThirdPlatformQueryOrder chinaumsQueryOrderResponseDataHandle(String mcode,String orderNumber, String responseData){
		val resultMap = JSON.parseObject(responseData, HashMap.class);
		if(!resultMap.get("errCode").toString().equalsIgnoreCase(ApplicationConstants.SUCCESS)){
			throw new BusinessCommonException(PaymentErrorCode.MCH_ORDER_GENERATE_ERROR.getCode(),resultMap.get("errMsg").toString());
		}
		val thirdPlatformOrder = new ThirdPlatformQueryOrder();
		thirdPlatformOrder.setMcode(mcode);
		thirdPlatformOrder.setMOrderNumber(orderNumber);
		thirdPlatformOrder.setTradeStatus(getTradeStatus(resultMap.get("billStatus").toString()));

		//处理支付信息
		if(resultMap.containsKey("billPayment")){
			val billPaymentMap = (Map)resultMap.get("billPayment");
			thirdPlatformOrder.setOuterTradeNumber(billPaymentMap.get("paySeqId")==null?"":billPaymentMap.get("paySeqId").toString());
			if(billPaymentMap.get("payTime") != null){
				Date payDate = DateUtils.parse(billPaymentMap.get("payTime").toString(),DateUtils.FORMAT_LONG);
				String payTime = DateUtils.format(payDate,DateUtils.FORMAT_LONG_UNMARK);
				thirdPlatformOrder.setTimeEnd(payTime);
			}
		}
		return thirdPlatformOrder;
	}

	/**
	 * 根据银联商务交易状态返回支付平台订单状态
	 * @param tradeState
	 * @return
	 */
	private String getTradeStatus(String tradeState){
		String tradeStatus = DictionaryConstant.PAYMENT_ORDER_STATUS_DZF.getCode();
		switch(tradeState){
			case "PAID":
				//支付成功
				tradeStatus = DictionaryConstant.PAYMENT_ORDER_STATUS_YZF.getCode();
				break;
			case "REFUND":
				//转入退款
				tradeStatus = DictionaryConstant.PAYMENT_ORDER_STATUS_TKZ.getCode();
				break;
			case "UNPAID":
				//未支付
				tradeStatus = DictionaryConstant.PAYMENT_ORDER_STATUS_DZF.getCode();
				break;
			case "CLOSED":
				//已关闭
				tradeStatus = DictionaryConstant.PAYMENT_ORDER_STATUS_JYGB.getCode();
				break;
		}
		return tradeStatus;
	}

	/**
	 * 银联商务预付订单取消方法
	 * @param payOrder
	 * @param mchPayChannel
	 * @return
	 */
	public ThirdPlatformCancelOrder cannelPayOrderFromThirdPlatform(PayOrder payOrder, MchPayChannel mchPayChannel){
		//1.处理数据
		val chinaumsPayCannelOrder = new ChinaumsPayCannelOrder();
		chinaumsPayCannelOrder.setMsgSrc(mchPayChannel.getAppSecretKey());
		chinaumsPayCannelOrder.setRequestTimestamp(LocalDateTimeUtils.getDateTime());
		chinaumsPayCannelOrder.setMid(mchPayChannel.getMchId());
		chinaumsPayCannelOrder.setTid(mchPayChannel.getAppid());
		chinaumsPayCannelOrder.setMsgType("bills.closeQRCode");
		chinaumsPayCannelOrder.setInstMid("QRPAYDEFAULT");
		chinaumsPayCannelOrder.setQrCodeId(payOrder.getOuterOrderNumber());
		String sign = ChinaumsUtils.makeSign(mchPayChannel.getSecretKey(), MapBeanUtils.beanToMap(chinaumsPayCannelOrder));
		chinaumsPayCannelOrder.setSign(sign);
		String chinaumsRequestData = JSON.toJSONString(chinaumsPayCannelOrder);
		String responseData = HttpClientUtils.postData(ChinaumsPayConstants.DOMAIN_API,chinaumsRequestData);
		//3.记录日志
		LogUtils.savePaymentTradeLog(mchPayChannel.getMcode(),payOrder.getmOrderNumber(), DictionaryConstant.PAYMENT_PAY_TYPE_WXZF_SERCIE.getCode(),LogUtils.LOG_DESCRIPTION_DDQX,chinaumsRequestData,responseData,DictionaryConstant.PAYMENT_REQUEST_TYPE_ZD.getCode());
		return chinaumsCannelOrderResponseDataHandle(mchPayChannel.getMcode(),payOrder.getmOrderNumber(),responseData);
	}

	/**
	 * 银联商务支付订单取消响应数据处理
	 * @return
	 */
	private ThirdPlatformCancelOrder chinaumsCannelOrderResponseDataHandle(String mcode,String orderNumber, String responseData){
		val resultMap = JSON.parseObject(responseData, HashMap.class);
		if(!resultMap.get("errCode").toString().equalsIgnoreCase(ApplicationConstants.SUCCESS)){
			throw new BusinessCommonException(PaymentErrorCode.MCH_ORDER_GENERATE_ERROR.getCode(),resultMap.get("errMsg").toString());
		}
		val thirdPlatformCancelOrder = new ThirdPlatformCancelOrder();
		thirdPlatformCancelOrder.setMcode(mcode);
		thirdPlatformCancelOrder.setMOrderNumber(orderNumber);
		thirdPlatformCancelOrder.setPayType(DictionaryConstant.PAYMENT_PAY_TYPE_YLSW_SERCIE.getCode());
		thirdPlatformCancelOrder.setCancelStatus("1");
		return thirdPlatformCancelOrder;
	}

	/**
	 * 银联商务预付订单退款申请方法
	 * @param payOrder
	 * @param mchPayChannel
	 * @param refundAmount:退款金额
	 * @return
	 */
	@Override
	public ThirdPlatformRefundOrder refundPayOrderFromThirdPlatform(PayOrder payOrder,String refundNumber,Long refundAmount, MchPayChannel mchPayChannel,PayTypeDict payTypeDict) {
		val chinaumsPayRefundOrder = new ChinaumsPayRefundOrder();
		chinaumsPayRefundOrder.setMsgSrc(mchPayChannel.getAppSecretKey());
		chinaumsPayRefundOrder.setRequestTimestamp(LocalDateTimeUtils.getDateTime());
		chinaumsPayRefundOrder.setMid(mchPayChannel.getMchId());
		chinaumsPayRefundOrder.setTid(mchPayChannel.getAppid());
		chinaumsPayRefundOrder.setBillNo(ChinaumsPayConstants.ORDER_NUMBER_PREFIX+payOrder.getmOrderNumber());
		chinaumsPayRefundOrder.setBillDate(DateUtils.format(payOrder.getCreatedAt(),DateUtils.FORMAT_SHORT));
		chinaumsPayRefundOrder.setMsgType("bills.refund");
		chinaumsPayRefundOrder.setInstMid("QRPAYDEFAULT");
		chinaumsPayRefundOrder.setRefundAmount(payOrder.getPayAmount().toString());
		String sign = ChinaumsUtils.makeSign(mchPayChannel.getSecretKey(), MapBeanUtils.beanToMap(chinaumsPayRefundOrder));
		chinaumsPayRefundOrder.setSign(sign);
		String chinaumsRequestData = JSON.toJSONString(chinaumsPayRefundOrder);
		String responseData = HttpClientUtils.postData(ChinaumsPayConstants.DOMAIN_API,chinaumsRequestData);
		//3.记录日志
		LogUtils.savePaymentTradeLog(payOrder.getMcode(),payOrder.getmOrderNumber(), DictionaryConstant.PAYMENT_PAY_TYPE_YLSW_SERCIE.getCode(),LogUtils.LOG_DESCRIPTION_SQTK,chinaumsRequestData,responseData,DictionaryConstant.PAYMENT_REQUEST_TYPE_ZD.getCode());
		return chinaumsRefundOrderResponseDataHandle(payOrder,refundNumber,responseData);
	}

	/**
	 * 银联商务退款申请响应数据处理
	 * @param payOrder
	 * @param responseData
	 * @return
	 */
	private ThirdPlatformRefundOrder chinaumsRefundOrderResponseDataHandle(PayOrder payOrder,String refundNumber, String responseData){
		val resultMap = JSON.parseObject(responseData, HashMap.class);
		if(!resultMap.get("errCode").toString().equalsIgnoreCase(ApplicationConstants.SUCCESS)){
			throw new BusinessCommonException(PaymentErrorCode.MCH_ORDER_GENERATE_ERROR.getCode(),resultMap.get("errMsg").toString());
		}
		val thirdPlatformOrder = new ThirdPlatformRefundOrder();
		thirdPlatformOrder.setMcode(payOrder.getMcode());
		thirdPlatformOrder.setMOrderNumber(payOrder.getmOrderNumber());
		thirdPlatformOrder.setPayType(payOrder.getPayType());
		thirdPlatformOrder.setRefundNumber(refundNumber);
		thirdPlatformOrder.setRefundAmount(payOrder.getPayAmount());
		if(resultMap.get("refundStatus").toString().equalsIgnoreCase("SUCCESS")){
			thirdPlatformOrder.setRefundStatus("2");
			thirdPlatformOrder.setThirdRefundNumber(resultMap.get("refundOrderId").toString());
		}else if(resultMap.get("refundStatus").toString().equalsIgnoreCase("PROCESSING")){
			thirdPlatformOrder.setRefundStatus("1");
			thirdPlatformOrder.setThirdRefundNumber(resultMap.get("refundOrderId").toString());
		}else{
			thirdPlatformOrder.setRefundStatus("0");
		}
		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.setNonce_str(WXPayUtils.generateNonceStr());
		weixinPayServiceReverseOrder.setOut_trade_no(orderNumber);
		String weixinRequestData =  SignatureUtils.generateSignedXml(MapBeanUtils.beanToMap(weixinPayServiceReverseOrder),mchPayChannel.getSecretKey());
		InputStream instream = FileUtils.convertByteArrayToInputStream(mchPayChannel.getCert());
		//2.请求微信预付单生成接口
		String responseData = HttpClientUtils.postXmlDataWithCert(WXPayConstants.DOMAIN_API+WXPayConstants.ORDER_REVERSE_URL_SUFFIX,weixinRequestData,weixinPayServiceReverseOrder.getMch_id(),instream);
		//3.记录日志
		LogUtils.savePaymentTradeLog(mchPayChannel.getMcode(),orderNumber, DictionaryConstant.PAYMENT_PAY_TYPE_WXZF_SERCIE.getCode(),LogUtils.LOG_DESCRIPTION_DDCX,weixinRequestData,responseData,DictionaryConstant.PAYMENT_REQUEST_TYPE_ZD.getCode());
		return weixinReverseOrderResponseDataHandle(mchPayChannel.getMcode(),orderNumber,responseData);
	}

	@Override
	public ThirdPlatformInitFacePay initFacePay(PostInitFacePayRequest initFacePayRequest, MchPayChannel mchPayChannel, PayTypeDict payTypeDict) {
		return null;
	}

	@Override
	public ThirdPlatformInitFacePay initFaceLive(PostInitFacePayRequest initFacePayRequest, MchPayChannel mchPayChannel, PayTypeDict payTypeDict) {
		return null;
	}

	@Override
	public boolean IsSupportPartialRefund() {
		return false;
	}

	/**
	 * 银联商务支付订单撤销响应数据处理
	 * @return
	 */
	private ThirdPlatformReverseOrder weixinReverseOrderResponseDataHandle(String mcode,String orderNumber, String responseData){
		val resultMap = SignatureUtils.xmlToMap(responseData);
		val thirdPlatformReverseOrder = new ThirdPlatformReverseOrder();
		thirdPlatformReverseOrder.setMcode(mcode);
		thirdPlatformReverseOrder.setMOrderNumber(orderNumber);
		thirdPlatformReverseOrder.setPayType(DictionaryConstant.PAYMENT_PAY_TYPE_WXZF_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;
	}
}
