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

import com.alibaba.fastjson.JSON;
import com.alipay.api.AlipayApiException;
import com.alipay.api.internal.util.AlipaySignature;
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.biz.DragonServiceCommonBiz;
import com.liquidnet.service.dragon.channel.alipay.biz.AlipayBiz;
import com.liquidnet.service.dragon.channel.alipay.constant.AlipayConstant;
import com.liquidnet.service.dragon.channel.alipay.strategy.AlipayStrategyContext;
import com.liquidnet.service.dragon.channel.strategy.annotation.StrategyPayChannelHandler;
import com.liquidnet.service.dragon.channel.strategy.biz.DragonPayBiz;
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.service.impl.DragonOrderRefundsServiceImpl;
import com.liquidnet.service.dragon.utils.DataUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

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

/**
 * @author AnJiabin <anjiabin@zhengzai.tv>
 * @version V1.0
 * @Description: TODO
 * @class: PayChannelStrategyAlipayImpl
 * @Package com.liquidnet.service.dragon.channel.strategy.impl
 * @Copyright: LightNet @ Copyright (c) 2021
 * @date 2021/7/13 13:06
 */
@Slf4j
@Component
@StrategyPayChannelHandler(DragonConstant.PayChannelEnum.ALIPAY)
public class PayChannelStrategyAlipayImpl extends AbstractPayChannelStrategyImpl {
    @Autowired
    private AlipayStrategyContext alipayStrategyContext;

    @Autowired
    private DataUtils dataUtils;

    @Autowired
    private AlipayBiz alipayBiz;

    @Autowired
    private DragonPayBiz dragonPayBiz;

    @Autowired
    private DragonServiceCommonBiz dragonServiceCommonBiz;

    @Autowired
    private DragonOrderRefundsServiceImpl dragonOrderRefundsService;

    @Value("${liquidnet.dragon.alipay.appId}")
    private String appId;
    @Value("${liquidnet.dragon.alipay.merchantPubKey}")
    private String merchantPubKey;
    @Value("${liquidnet.dragon.alipay.merchantPrivateKey}")
    private String merchantPrivateKey;
    @Value("${liquidnet.dragon.alipay.signtType}")
    private String signtType;
    @Value("${liquidnet.dragon.alipay.charset}")
    private String charset;

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

    @Override
    public String dragonNotify(HttpServletRequest request,String payType,String deviceFrom) {
        log.info("alipay-->notify-->begin payType:{} deviceFrom:{}",payType,deviceFrom);
        Map<String, String[]> requestParams = request.getParameterMap();
        Map<String, String> notifyMap = new HashMap<String, String>();
        notifyMap = alipayBiz.parseNotifyMsg(requestParams);
        log.info("dragonNotify-->alipay json : {}", JSON.toJSONString(notifyMap));
        log.info("接收到{}支付结果{}", payType, notifyMap);


        String returnStr = "fail";
        String code = notifyMap.get("out_trade_no");
        if(StringUtil.isBlank(code)){
            throw new LiquidnetServiceException(DragonErrorCodeEnum.TRADE_ERROR_NOT_EXISTS.getCode(),DragonErrorCodeEnum.TRADE_ERROR_NOT_EXISTS.getMessage());
        }

        //持久化通知记录
        dragonServiceCommonBiz.createDragonOrderLogs(code,dragonPayBiz.getPaymentType(payType,deviceFrom),JSON.toJSONString(notifyMap));

        //退款
        if(notifyMap.containsKey("refund_fee") || notifyMap.containsKey("gmt_refund") || notifyMap.containsKey("out_biz_no")) {
            returnStr = dragonOrderRefundsService.aliPayRefundCallBack(JSON.toJSONString(notifyMap));
            return returnStr;
        }

        // 根据银行订单号获取支付信息
        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());
        }

        try {
            if (AlipaySignature.rsaCheckV1(notifyMap, merchantPubKey, "UTF-8", "RSA2")){
                String tradeStatus = notifyMap.get("trade_status");
                boolean notifyResult = false;

                if (AlipayConstant.AlipayTradeStateEnum.TRADE_SUCCESS.name().equals(tradeStatus)
                        ||AlipayConstant.AlipayTradeStateEnum.TRADE_FINISHED.name().equals(tradeStatus)) {

                    String gmtPaymentStr = notifyMap.get("gmt_payment");// 付款时间
                    LocalDateTime timeEnd = null;
                    if (!StringUtil.isEmpty(gmtPaymentStr)) {
                        timeEnd = DateUtil.Formatter.yyyyMMddHHmmss.parse(gmtPaymentStr);
                    }
                    notifyResult = this.completeSuccessOrder(dragonOrdersDto, notifyMap.get("trade_no"), timeEnd, notifyMap.toString());
                } else {
                    notifyResult = this.completeFailOrder(dragonOrdersDto, notifyMap.toString());
                }
                if(notifyResult){
                    returnStr = "success";
                }
            } else {// 验证失败
                log.error("alipay notify fail code:{} msg:{} ",DragonErrorCodeEnum.TRADE_ALIPAY_SIGN_ERROR.getCode(),DragonErrorCodeEnum.TRADE_ALIPAY_SIGN_ERROR.getMessage());
                return returnStr;
            }
        } catch (AlipayApiException e) {
            log.error("alipay notify fail 验签失败：e:{}" , e);
            log.error("alipay notify fail 验签失败：code:{} msg:{}" ,DragonErrorCodeEnum.TRADE_ALIPAY_SIGN_ERROR.getCode(),DragonErrorCodeEnum.TRADE_ALIPAY_SIGN_ERROR.getMessage());
        }

        log.info("返回支付通道{}信息{}", payType, returnStr);
        log.info("alipay-->notify-->end payType:{} deviceFrom:{}",payType,deviceFrom);
        return returnStr;
    }

    @Override
    public DragonPayOrderQueryRespDto checkOrderStatus(String code) {
        DragonOrdersDto ordersDto = dataUtils.getPayOrderByCode(code);
        Map<String, Object> resultMap = alipayBiz.tradeQuery(code);
        DragonPayOrderQueryRespDto respDto = dragonPayBiz.buildPayOrderQueryRespDto(ordersDto);
        if ("10000".equals(resultMap.get("code"))) {
            // 当返回状态为“TRADE_FINISHED”交易成功结束和“TRADE_SUCCESS”支付成功时更新交易状态
            if (AlipayConstant.AlipayTradeStateEnum.TRADE_SUCCESS.getCode().equals(resultMap.get("tradeStatus"))
                    || AlipayConstant.AlipayTradeStateEnum.TRADE_FINISHED.getCode().equals(resultMap.get("tradeStatus"))) {
                respDto.setStatus(Integer.valueOf(DragonConstant.PayStatusEnum.STATUS_PAID.getCode()));
            }else{
                respDto.setStatus(Integer.valueOf(DragonConstant.PayStatusEnum.STATUS_PAY_FAIL.getCode()));
            }
//            throw new LiquidnetServiceException(DragonErrorCodeEnum.TRADE_ALIPAY_QUERY_ERROR.getCode(),DragonErrorCodeEnum.TRADE_ALIPAY_QUERY_ERROR.getMessage());
        }else if("40004".equals(resultMap.get("code"))&&"ACQ.TRADE_NOT_EXIST".equalsIgnoreCase(resultMap.get("subCode").toString())){
            respDto.setStatus(Integer.valueOf(DragonConstant.PayStatusEnum.STATUS_UNPAID.getCode()));
        }else{
            throw new LiquidnetServiceException(DragonErrorCodeEnum.TRADE_ALIPAY_QUERY_ERROR.getCode(),DragonErrorCodeEnum.TRADE_ALIPAY_QUERY_ERROR.getMessage());
        }
        return respDto;
    }
}
