package com.liquidnet.service.dragon.channel.strategy.impl;

import com.alibaba.fastjson.JSON;
import com.liquidnet.common.exception.LiquidnetServiceException;
import com.liquidnet.commons.lang.util.DateUtil;
import com.liquidnet.commons.lang.util.StringUtil;
import com.liquidnet.service.base.ResponseDto;
import com.liquidnet.service.dragon.channel.strategy.IPayChannelStrategy;
import com.liquidnet.service.dragon.channel.strategy.annotation.StrategyPayChannelHandler;
import com.liquidnet.service.dragon.channel.wepay.biz.WepayBiz;
import com.liquidnet.service.dragon.channel.wepay.constant.WepayConstant;
import com.liquidnet.service.dragon.channel.wepay.strategy.WepayStrategyContext;
import com.liquidnet.service.dragon.constant.DragonConstant;
import com.liquidnet.service.dragon.constant.DragonErrorCodeEnum;
import com.liquidnet.service.dragon.dto.DragonOrdersDto;
import com.liquidnet.service.dragon.dto.DragonPayBaseReqDto;
import com.liquidnet.service.dragon.dto.DragonPayBaseRespDto;
import com.liquidnet.service.dragon.dto.DragonPayOrderQueryRespDto;
import com.liquidnet.service.dragon.utils.DataUtils;
import com.liquidnet.service.dragon.utils.MqHandleUtil;
import com.liquidnet.service.dragon.utils.PayWepayUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.io.InputStream;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;

/**
 * @author AnJiabin <anjiabin@zhengzai.tv>
 * @version V1.0
 * @Description: TODO
 * @class: PayChannelStrategyWepayImpl
 * @Package com.liquidnet.service.dragon.channel.strategy.impl
 * @Copyright: LightNet @ Copyright (c) 2021
 * @date 2021/7/13 13:06
 */
@Slf4j
@Component
@StrategyPayChannelHandler(DragonConstant.PayChannelEnum.WEPAY)
public class PayChannelStrategyWepayImpl implements IPayChannelStrategy {
    @Autowired
    private WepayStrategyContext wepayStrategyContext;

    @Autowired
    private DataUtils dataUtils;

    @Autowired
    private MqHandleUtil mqHandleUtil;

    @Autowired
    private WepayBiz wepayBiz;

    @Override
    public ResponseDto<DragonPayBaseRespDto> dragonPay(DragonPayBaseReqDto dragonPayBaseReqDto) {
        return wepayStrategyContext.getStrategy(dragonPayBaseReqDto.getDeviceFrom()).dragonPay(dragonPayBaseReqDto);
    }

    @Override
    public void dragonNotify(HttpServletRequest request,String payType,String deviceFrom) {
        try {
            InputStream inputStream = request.getInputStream();// 从request中取得输入流
            Map<String, String> notifyMap = new HashMap<String, String>();
            try {
                notifyMap = PayWepayUtils.parseXml(inputStream);
                log.info("dragonNotify-->wepay json : {}", JSON.toJSONString(notifyMap));

                log.info("接收到{}支付结果{}", payType, notifyMap);

                String code = notifyMap.get("out_trade_no");
                // 根据银行订单号获取支付信息
                DragonOrdersDto dragonOrdersDto = dataUtils.getPayOrderByCode(code);
                if (dragonOrdersDto == null) {
                    throw new LiquidnetServiceException(DragonErrorCodeEnum.TRADE_ERROR_NOT_EXISTS.getCode(),DragonErrorCodeEnum.TRADE_ERROR_NOT_EXISTS.getMessage());
                }

                if (DragonConstant.PayStatusEnum.STATUS_PAID.getCode().equals(dragonOrdersDto.getStatus())) {
                    throw new LiquidnetServiceException(DragonErrorCodeEnum.TRADE_ERROR_HAS_PAID.getCode(),DragonErrorCodeEnum.TRADE_ERROR_HAS_PAID.getMessage());
                }

                String partnerKey = "";

                String sign = notifyMap.remove("sign");
                if (PayWepayUtils.notifySign(notifyMap, sign, partnerKey)) {// 根据配置信息验证签名
                    if (WepayConstant.WeixinTradeStateEnum.SUCCESS.getCode().equals(notifyMap.get("result_code"))) {// 业务结果
                        // 成功
                        String timeEndStr = notifyMap.get("time_end");
                        LocalDateTime timeEnd = null;
                        if (!StringUtil.isEmpty(timeEndStr)) {
                            timeEnd = DateUtil.Formatter.yyyyMMddHHmmss.parse(timeEndStr);
                        }
                        completeSuccessOrder(dragonOrdersDto, notifyMap.get("transaction_id"), timeEnd, notifyMap.toString());
//                        returnStr = "<xml>\n" + "  <return_code><![CDATA[SUCCESS]]></return_code>\n" + "  <return_msg><![CDATA[OK]]></return_msg>\n" + "</xml>";
                    } else {
//                        completeFailOrder(dragonOrdersDto, notifyMap.toString());
                    }
                } else {
                    throw new LiquidnetServiceException(DragonErrorCodeEnum.TRADE_WEPAY_SIGN_ERROR.getCode(),DragonErrorCodeEnum.TRADE_WEPAY_SIGN_ERROR.getMessage());
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public DragonPayOrderQueryRespDto checkOrderStatus(String code) {
        DragonOrdersDto ordersDto = dataUtils.getPayOrderByCode(code);
        DragonPayOrderQueryRespDto respDto = wepayStrategyContext.getStrategy(DragonConstant.PayTypeEnum.getEnumByCode(ordersDto.getPaymentType()).getDeviceFrom()).checkOrderStatus(code);
        return respDto;
    }

    @Transactional(rollbackFor = Exception.class)
    void completeSuccessOrder(DragonOrdersDto dragonOrdersDto, String bankTrxNo, LocalDateTime timeEnd, String bankReturnMsg) {
        log.info("订单支付成功!");
        dragonOrdersDto.setPaymentAt(timeEnd);
        dragonOrdersDto.setPaymentId(bankTrxNo);// 设置银行流水号
//        DragonOrdersDto.(bankReturnMsg);
        dragonOrdersDto.setStatus(Integer.parseInt(DragonConstant.PayStatusEnum.STATUS_PAID.getCode()));
        dataUtils.updateOrderStatus(dragonOrdersDto.getCode(),dragonOrdersDto);

        //通知消息入队列
        mqHandleUtil.sendQueueWepay(wepayBiz.buildPayNotifyReqBo(dragonOrdersDto));
    }
}
