package com.xxfc.platform.universal.biz;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.AlipayConstants;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.*;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.*;
import com.alipay.api.response.*;
import com.github.wxiaoqi.security.common.biz.BaseBiz;
import com.github.wxiaoqi.security.common.config.rabbit.RabbitConstant;
import com.github.wxiaoqi.security.common.msg.ObjectRestResponse;
import com.github.wxiaoqi.security.common.util.HTTPSUtils;
import com.github.wxiaoqi.security.common.util.OrderUtil;
import com.github.wxiaoqi.security.common.util.process.ResultCode;
import com.github.wxiaoqi.security.common.util.process.SystemConfig;
import com.github.wxiaoqi.security.common.util.result.JsonResultUtil;
import com.xxfc.platform.universal.entity.Dictionary;
import com.xxfc.platform.universal.entity.OrderPay;
import com.xxfc.platform.universal.mapper.OrderPayMapper;
import com.xxfc.platform.universal.vo.OrderPayVo;
import com.xxfc.platform.universal.weixin.api.WXPay;
import com.xxfc.platform.universal.weixin.util.HTTPUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import tk.mybatis.mapper.entity.Example;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import static com.xxfc.platform.universal.constant.DictionaryKey.PAY_DEMOTION;
import static com.xxfc.platform.universal.constant.DictionaryKey.UNIVERSAL_PAY;

/**
 * 订单支付
 *
 * @author zjw
 * @email nishijjo@qq.com
 * @date 2019-05-28 16:17:42
 */
@Service
@Slf4j
public class OrderPayBiz extends BaseBiz<OrderPayMapper,OrderPay> {

    @Autowired
    DictionaryBiz dictionaryBiz;

    @Autowired
    HttpServletRequest request;

    @Autowired
    MQServiceBiZ mqServiceBiZ;
    @Value("${universal.url}")
    String weixinHost;

    String notifyUrl = weixinHost + "/service/payment/notify/alipay";
    String alipayNotifyUrl =SystemConfig.weixinHost + "/service/payment/notify/alipay";
    public JSONObject preparepay( OrderPayVo orderPayVo) {
        if(null == orderPayVo) {
            log.error("-----参数为空-----------");
            return JsonResultUtil.createFailedResult(ResultCode.NULL_CODE, "参数为空");
        }
        if(orderPayVo.getAmount()==null||orderPayVo.getAmount()==0) {
            log.error("-----金额不为为0-----------");
            return JsonResultUtil.createFailedResult(ResultCode.NULL_CODE, "金额不为为0");
        }
        if(StringUtils.isBlank(orderPayVo.getOrderNo())) {
            log.error("-----订单不能为空-----------");
            return JsonResultUtil.createFailedResult(ResultCode.NULL_CODE, "订单不能为空");
    }
    String trade_no =  OrderUtil.GetOrderNumber("");
    String order_no=orderPayVo.getOrderNo();
    Integer amount=orderPayVo.getAmount();
        log.error("---下单---order_no====="+order_no+"--支付订单号--trade_no===="+trade_no+"--金额---amount===="+amount);
    //报名费回调路径

    //临时处理
    Map<String, Dictionary> dictionaryMap = dictionaryBiz.getAll4Map();
    Integer demotion = Integer.valueOf(dictionaryMap.get(UNIVERSAL_PAY+ "_"+ PAY_DEMOTION).getDetail());
    amount = amount/demotion;
        if(amount <= 0) {
        amount = 1;
    }
        Integer type=orderPayVo.getType();
        String jsParam="";
        String  notify_url=weixinHost+"/api/universal/pay/app/unauth/notify";
        log.info("报名费回调路径notify_url:"+notify_url);
        if(type!=null&&type==2){
            jsParam=WXPay.webPay( amount+"",orderPayVo.getBody(),notify_url,trade_no,orderPayVo.getBuyerIp(), orderPayVo.getBuyerAccount());
        }else {
            jsParam = WXPay.apppay(amount+"",orderPayVo.getBody(),notify_url ,trade_no,orderPayVo.getBuyerIp(),0);
        }
        log.info("报名费回调路径jsParam:"+jsParam);
        if(!StringUtils.isBlank(jsParam))
        {
            try {
                OrderPay orderPay= new OrderPay();
                BeanUtils.copyProperties(orderPay,orderPayVo);
                orderPay.setTradeNo(trade_no);
                orderPay.setSellerAccount(SystemConfig.APP_PARTNER);
                insertSelective(orderPay);
                log.error("---下单---order_no====="+order_no+"----成功");
            } catch (Exception e) {
                e.printStackTrace();
                log.error("---下单---order_no====="+order_no+"----异常---msg==="+ e.getMessage());
                return JsonResultUtil.createFailedResult(ResultCode.EXCEPTION_CODE, "出现异常");
            }
             JSONObject temp = JSON.parseObject(jsParam);
            return JsonResultUtil.createSuccessResultWithObj(temp);
        }else{
            return JsonResultUtil.createDefaultFail();
        }
    }
    //支付回调
    public void notice(String orderNo,String serialNumber){
        log.error("---支付回调---trade_no====="+orderNo+"----开始处理");
        Example example =new Example(OrderPay.class);
        example.createCriteria().andEqualTo("tradeNo", orderNo).andEqualTo("isDel",0).andEqualTo("status",0);
        List<OrderPay> list=mapper.selectByExample(example);
        if(list.size()==0){
            log.error("---支付回调---trade_no====="+orderNo+"----订单不存在或已处理");
             return;
        }
        example.clear();
        example.createCriteria().andEqualTo("tradeNo",orderNo);
        OrderPay orderPay=new OrderPay();
        orderPay.setFinishTime(System.currentTimeMillis());
        orderPay.setStatus(1);
        orderPay.setSerialNumber(serialNumber);
        int num=mapper.updateByExampleSelective(orderPay,example);

        log.error("---支付回调处理---num====="+num+"----orderNo======="+orderNo);
        if(num>0){
            //支付成功，添加积分
            OrderPay pay= list.get(0);
            OrderPay newValue = mapper.selectOne(orderPay);
            log.info("支付回调信息：newValue = {}", newValue);
            if(newValue.getStatus() == 1) {
                JSONObject jsonObject = new JSONObject();
                jsonObject.put("userId", newValue.getUserId());
                jsonObject.put("amount", newValue.getAmount());
                jsonObject.put("channelId", newValue.getOrderNo());
                if(newValue.getChannel() == 1) {//租车
                    jsonObject.put("integralRuleCode", "RENTRV");
                } else if(newValue.getChannel() == 2) { //旅游
                    jsonObject.put("integralRuleCode", "BUYROUT");
                } else if(newValue.getChannel() == 3) {  //会员
                    jsonObject.put("integralRuleCode", "BUYMEMBER");
                }
                log.info("支付订单号：orderNo = {}, orderType = {}", newValue.getOrderNo(), newValue.getChannel());
                log.info("支付成功获取积分：发送消息 exchange = {}, routingKey = {}, json = {}", RabbitConstant.INTEGRAL_TOPIC, RabbitConstant.INTEGRAL_ROUTING_KEY, jsonObject.toJSONString());
                mqServiceBiZ.sendMessage(RabbitConstant.INTEGRAL_TOPIC, RabbitConstant.INTEGRAL_ROUTING_KEY, jsonObject.toJSONString());
            }
            if(StringUtils.isNotBlank(pay.getNotifyUrl())){
                String url=pay.getNotifyUrl();
                Integer type=pay.getType()==null?1:pay.getType();
                url+="&tradeNo="+orderNo+"&type="+type;
                log.error("---支付回调处理---orderNo======="+orderNo+"----notifyUrl===="+url);
                String result="";
                if(url.contains("https")||url.contains("HTTPS")){
                     result= HTTPSUtils.httpRequest(url, "GET",null);
                }else{
                    result= HTTPUtils.doGet(url);
                }
                log.error("---支付回调处理---orderNo======="+orderNo+"---result==="+result);

            }
        }
    }

    /**
     * 支付宝回调接口
     * @return
     */
    public String alipayNotify() {
        //获取支付宝POST过来反馈信息
        Map<String,String> params = new HashMap<>();
        Map requestParams = request.getParameterMap();
        for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext();) {
            String name = (String) iter.next();
            String[] values = (String[]) requestParams.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i]
                        : valueStr + values[i] + ",";
            }
            log.info(valueStr);
            //乱码解决，这段代码在出现乱码时使用。
            //valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
            params.put(name, valueStr);
        }
        String msg = JSONObject.toJSONString(params);
        log.info("alipay notify message={}", msg);
		//添加回调记录
//		PaymentCallbackLog callbackLog = new PaymentCallbackLog();
//		callbackLog.setPayCode(rstradeNo);
//		callbackLog.setPayType(SystemConstant.PayType.ALIPAY);
//		callbackLog.setOrderCode(rsOrderCode);
//		callbackLog.setMessage(msg);
//		paymentCallbackLogRepository.save(callbackLog);
//        切记alipaypublickey是支付宝的公钥，请去open.alipay.com对应应用下查看。
//        boolean AlipaySignature.rsaCheckV1(Map<String, String> params, String publicKey, String charset, String sign_type)
       //支付宝回调验签
        try {
            boolean flag = AlipaySignature.rsaCheckV1(params, SystemConfig.ALIPAY_PUBLIC_KEY, AlipayConstants.CHARSET_UTF8, AlipayConstants.SIGN_TYPE_RSA2);
            if (!flag) {
                log.info("alipay order rsaCheckV1 fail, result={}", msg);
                return ObjectRestResponse.createDefaultFail().getMessage();
            }
            String rsTradeStatus = params.get("trade_status");
            if (!SystemConfig.ALIPAY_TRADE_FINISHED.equals(rsTradeStatus) && !SystemConfig.ALIPAY_TRADE_SUCCESS.equals(rsTradeStatus)) {
                log.info("alipay order trade_status has problem, result={}", msg);
                return ObjectRestResponse.createDefaultFail().getMessage();
            }
            //String rsSellerId = params.get("seller_id");
//
//			PaymentRecord paymentRecord = paymentRecordRepository.findOneByOrderCode(rsOrderCode);
//			//验证付款信息
//			if (paymentRecord == null || !paymentRecord.getAmount().toString().equals(rsAmount)
//					|| !aliPayConfig.getAppId().equals(rsAppId)) {
//				log.info("alipay order notify fail, result={}", msg);
//				return Response.FAILURE.getHeader().getMessage();
//			}

//			//重复回调
//			if (paymentRecord.getStatus().intValue() != 1) {
//				log.info("alipay order repeat notify, result={}", msg);
//				return Response.SUCCESS().getHeader().getMessage();
//			}
//
//			paymentRecord.setPayCode(rstradeNo);
//			paymentRecord.setStatus(2);
//			paymentRecordRepository.save(paymentRecord);

//			Map<String, Object> sendMap =  DataUtils.objectToMap(paymentRecord);
//			sendMap.put("amount", new BigDecimal(rsAmount).multiply(new BigDecimal(100)).intValue());
//			sendMsgToOrder(JSONObject.toJSONString(sendMap));
            return ObjectRestResponse.succ().getMessage();
        } catch (AlipayApiException e) {
            log.error("", e);
        }
        return ObjectRestResponse.createDefaultFail().getMessage();
    }

    /**
     * 支付宝生成支付信息
     * @return
     */
    @SuppressWarnings("rawtypes")
    private ObjectRestResponse generateAliPayment(OrderPayVo orderPayVo) {

        String notifyUrl = weixinHost + "/service/payment/notify/alipay";

        //实例化客户端
        AlipayClient alipayClient = new DefaultAlipayClient(SystemConfig.ALIPAY_PAY_BASE_URL + "/gateway.do",
                SystemConfig.ALIPAY_APPID, SystemConfig.ALIPAY_PRIVATE_KEY, AlipayConstants.FORMAT_JSON,
                AlipayConstants.CHARSET_UTF8, SystemConfig.ALIPAY_PUBLIC_KEY, AlipayConstants.SIGN_TYPE_RSA2);

        //实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称：alipay.trade.app.pay
//
        try{
            return fundAuthOrderAppFreeze(alipayClient, orderPayVo);
        }catch (Exception e){
            e.printStackTrace();
        }
//
        return ObjectRestResponse.createDefaultFail();
    }

    //支付宝APP支付方法
    public ObjectRestResponse appOrderPay(OrderPayVo orderPayVo, AlipayClient alipayClient) {
        BigDecimal realAmount = new BigDecimal(orderPayVo.getAmount().toString()).divide(new BigDecimal("100"), 2, BigDecimal.ROUND_UP);
        AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
//		//SDK已经封装掉了公共参数，这里只需要传入业务参数。以下方法为sdk的model入参方式(model和biz_content同时存在的情况下取biz_content)。
		AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
		//model.setBody("我是测试数据");
		model.setSubject(orderPayVo.getBody());
		model.setOutTradeNo(orderPayVo.getOrderNo());
		model.setTimeoutExpress("30m");
		model.setTotalAmount(realAmount.toString());
		model.setProductCode("QUICK_MSECURITY_PAY");
		request.setBizModel(model);
		request.setNotifyUrl(notifyUrl);
        try {
	        //这里和普通的接口调用不同，使用的是sdkExecute
	       AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request);
	        System.out.println(response.getBody());//就是orderString 可以直接给客户端请求，无需再做处理。
	        Map<String, Object> rt = new HashMap<>();
	    	rt.put("payType", orderPayVo.getType());
            rt.put("payData", response.getBody());
	    	return ObjectRestResponse.succ(rt);
	    } catch (AlipayApiException e) {
	        e.printStackTrace();
		}
        return ObjectRestResponse.createDefaultFail();
    }



    //预授权冻结
    public ObjectRestResponse fundAuthOrderAppFreeze(AlipayClient alipayClient, OrderPayVo orderPayVo) throws AlipayApiException {
        AlipayFundAuthOrderAppFreezeRequest request = new AlipayFundAuthOrderAppFreezeRequest();
        AlipayFundAuthOrderAppFreezeModel model = new AlipayFundAuthOrderAppFreezeModel();
        BigDecimal realAmount = new BigDecimal(orderPayVo.getAmount().toString()).divide(new BigDecimal("100"), 2, BigDecimal.ROUND_UP);
        model.setOrderTitle(orderPayVo.getSubject());
        model.setOutOrderNo(orderPayVo.getOrderNo());//替换为实际订单号
        model.setOutRequestNo(orderPayVo.getOrderNo());//替换为实际请求单号，保证每次请求都是唯一的
        model.setPayeeUserId(SystemConfig.APP_ID);//payee_user_id,Payee_logon_id不能同时为空
        model.setProductCode("PRE_AUTH_ONLINE");//PRE_AUTH_ONLINE为固定值，不要替换
        model.setAmount(realAmount.toString());
        //需要支持信用授权，该字段必传
        //model.setExtraParam("{\"category\":\"xxx\",\"outStoreCode\":\"charge001\",\"outStoreAlias\":\"充电桩北京路点\"}"); //outStoreAlias将在用户端信用守护、支付信息、账单详情页展示
        //选填字段，指定支付渠道
        model.setEnablePayChannels("[{\"payChannelType\":\"PCREDIT_PAY\"},{\"payChannelType\":\"MONEY_FUND\"}]");
        request.setBizModel(model);
        request.setNotifyUrl(notifyUrl);//异步通知地址，必填，该接口只通过该参数进行异步通知
        AlipayFundAuthOrderAppFreezeResponse response = alipayClient.sdkExecute(request);//注意这里是sdkExecute，可以获取签名参数
        if(response.isSuccess()){
            log.info("调用成功");
            log.info("response: {}" + response.getBody());//签名后的参数，直接入参到
            return ObjectRestResponse.succ(response.getBody());
        } else {
            log.info("调用失败");
           return  ObjectRestResponse.createDefaultFail();
        }
    }
    //解冻预授权
    public void fundAuthOrderUnFreeze(AlipayClient alipayClient) throws AlipayApiException {

        AlipayFundAuthOrderUnfreezeRequest request = new AlipayFundAuthOrderUnfreezeRequest();
        AlipayFundAuthOrderUnfreezeModel model = new AlipayFundAuthOrderUnfreezeModel();
        model.setAuthNo("2017120410002001390208978986"); // 支付宝资金授权订单号，在授权冻结成功时返回需要入库保存
        model.setOutRequestNo("UnfreezeRequestNo000003");//同一商户每次不同的资金操作请求，商户请求流水号不能重复,且与冻结流水号不同
        model.setAmount("0.01"); // 本次操作解冻的金额，单位为：元（人民币），精确到小数点后两位
        model.setRemark("预授权解冻"); // 商户对本次解冻操作的附言描述，长度不超过100个字母或50个汉字
        //选填字段，信用授权订单，针对信用全免订单，传入该值完结信用订单，形成芝麻履约记录
       // model.setExtraParam("{\"unfreezeBizInfo\":\"{\\\"bizComplete\\\":\\\"true\\\"}\"}");
        request.setBizModel(model);
        request.setNotifyUrl(notifyUrl);//异步通知地址，必填，该接口只通过该参数进行异步通知

        AlipayFundAuthOrderUnfreezeResponse response = alipayClient.execute(request);
        log.info("response: {}"+response.getBody());
    }
    //取消预授权
    public void fundAuthCancel() throws AlipayApiException {
        AlipayClient alipayClient = new DefaultAlipayClient("https://openapi.alipay.com/gateway.do","app_id","your private_key","json","GBK","alipay_public_key","RSA2");
        AlipayFundAuthOperationCancelRequest request = new AlipayFundAuthOperationCancelRequest();
        AlipayFundAuthOperationCancelModel model = new AlipayFundAuthOperationCancelModel();
        //model.setAuthNo("2017120110002001390206804295"); // 支付宝资金授权订单号，在授权冻结成功时返回参数中获得
        model.setOutOrderNo("orderFreeze000005"); //商户的授权资金订单号，与支付宝的授权资金订单号不能同时为空
        //model.setOperationId("20171201317348823902"); //支付宝的授权资金操作流水号
        model.setOutRequestNo("requestNo000005");//与支付宝的授权资金操作流水号不能同时为空，与冻结流水号相同
        model.setRemark("预授权撤销"); // 商户对本次撤销操作的附言描述，长度不超过100个字母或50个汉字
        request.setBizModel(model);
        request.setNotifyUrl("");//异步通知地址，必填，该接口只通过该参数进行异步通知

        AlipayFundAuthOperationCancelResponse response = alipayClient.execute(request);
        log.info("response: {}"+response.getBody());
    }
    //预授权转支付
    public void tradePay() throws AlipayApiException {
        AlipayClient alipayClient = new DefaultAlipayClient("https://openapi.alipay.com/gateway.do","app_id","your private_key","json","utf-8","alipay_public_key","RSA2");

        AlipayTradePayRequest request = new AlipayTradePayRequest();

        AlipayTradePayModel model = new AlipayTradePayModel();
        model.setOutTradeNo("20180412100020088982"); // 预授权转支付商户订单号，为新的商户交易流水号；如果重试发起扣款，商户订单号不要变；
        model.setProductCode("PRE_AUTH_ONLINE"); // 固定值PRE_AUTH_ONLINE
        model.setAuthNo("2018041210002001660228733635"); // 填写预授权冻结交易号
        model.setSubject("预授权转支付测试"); // 解冻转支付标题，用于展示在支付宝账单中
        model.setTotalAmount("0.01"); // 结算支付金额
        model.setSellerId(SystemConfig.ALIPAY_PID); // 填写卖家支付宝账户pid
        model.setBuyerId(SystemConfig.ALIPAY_APPID); // 填写预授权用户uid，通过预授权冻结接口返回的payer_user_id字段获取
        model.setStoreId("test_store_id"); // 填写实际交易发生的终端编号，与预授权的outStoreCode保持一致即可
        model.setBody("预授权解冻转支付测试"); // 可填写备注信息
        //如果需要从一笔授权中完成多笔订单支付，保持auth_no不变，不同订单根据outTradeNo进行标识，此时auth_confirm_mode不传或者传入NOT_COMPLETE；进行到最后一笔转支付时，auth_confirm_mode传入COMPLETE由支付宝完成剩余金额自动解冻，或者商户自行调用解冻接口将剩余金额解冻。
        model.setAuthConfirmMode("NOT_COMPLETE");//传入该值用户剩余金额不会自动解冻
        request.setBizModel(model);
        request.setNotifyUrl("");//异步通知地址，必填，该接口只通过该参数进行异步通知

        AlipayTradePayResponse response = alipayClient.execute(request);
        if(response.isSuccess()){
            System.out.println("调用成功");
            log.info("response: {}"+response.getBody());
        } else {
            System.out.println("调用失败");
        }
    }
    //退款
    public void testTradeRefund() throws Exception {
        AlipayClient alipayClient = new DefaultAlipayClient("https://openapi.alipay.com/gateway.do","app_id","your private_key","json","GBK","alipay_public_key","RSA2");
        AlipayTradeRefundModel model = new AlipayTradeRefundModel();
        model.setOutTradeNo("tradePay000002"); //与预授权转支付商户订单号相同，代表对该笔交易退款
        model.setRefundAmount("0.01");
        model.setRefundReason("预授权退款测试");
        model.setOutRequestNo("refund0000001");//标识一次退款请求，同一笔交易多次退款需要保证唯一，如部分退款则此参数必传。
        AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
        request.setBizModel(model);
        AlipayTradeRefundResponse response = alipayClient.execute(request);
        log.info("response: {}"+response.getBody());
    }
    public Object generatePayment(OrderPayVo orderPayVo) {
        switch (orderPayVo.getType()) {
            case 1:  //支付宝
                ObjectRestResponse  objectRestResponse = generateAliPayment(orderPayVo);
                return objectRestResponse;
            case 2: //微信
                JSONObject jsonObject = preparepay(orderPayVo);
                return jsonObject;
            case 3: //银联
                return null;
            default:
                log.info("不支持的付款类型，payType={}", orderPayVo.getType());
                break;
        }
        return null;
    }



    public static void main(String[] args) {
        String url="https://xxtest.upyuns.com/api/order/baseOrder/app/unauth/notifyUrl?orderNo=20190603141137010007&tradeNo=20190603141137000002";
        String result="";
        if(url.contains("https")||url.contains("HTTPS")){
            result= HTTPSUtils.httpRequest(url, "GET",null);
        }else{
            result= HTTPUtils.doGet(url);
        }
        System.out.println(result);
    }
}