package com.yiqi.order.service.impl;

import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.AlipayConfig;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.request.AlipayTradeQueryRequest;
import com.alipay.api.request.AlipayTradeRefundRequest;
import com.alipay.api.response.AlipayTradeQueryResponse;
import com.alipay.api.response.AlipayTradeRefundResponse;
import com.wechat.pay.java.service.refund.RefundService;
import com.wechat.pay.java.service.refund.model.AmountReq;
import com.wechat.pay.java.service.refund.model.CreateRequest;
import com.wechat.pay.java.service.refund.model.Refund;
import com.yiqi.common.config.AlipayConfigs;
import com.yiqi.common.enums.*;
import com.yiqi.common.exception.ServiceException;
import com.yiqi.common.config.WxPayConfigs;
import com.yiqi.common.core.domain.AuthHolder;
import com.yiqi.common.core.domain.R;
import com.yiqi.common.utils.EnumUtils;
import com.yiqi.common.utils.OrderNoUtils;
import com.yiqi.common.utils.StringUtils;
import com.yiqi.delay.DelayMessage;
import com.yiqi.delay.DelayQueueCache;
import com.yiqi.order.domain.OrderPayInfo;
import com.yiqi.order.domain.OrderRefundInfo;
import com.yiqi.order.domain.dto.*;
import com.yiqi.order.domain.vo.OrderPayResultVO;
import com.yiqi.order.domain.vo.weapp.AppPayRespVO;
import com.yiqi.order.service.*;
import com.yiqi.payment.AliPayService;
import com.yiqi.payment.WechatPayService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.concurrent.ScheduledExecutorService;

import org.springframework.transaction.annotation.Transactional;


/**
 * @author xiaohei
 * @date 2023/12/25
 */
@Service
public class PayServiceImpl implements IPayService {
    @Autowired
    private ScheduledExecutorService scheduledExecutorService;
    @Autowired
    private OrderNoUtils orderNoUtils;
    @Autowired
    private IOrderRechargeService orderRechargeService;
    @Autowired
    private IOrderActivityService orderActivityService;
    @Autowired
    private IOrderGoodsService orderGoodsService;
    @Autowired
    private IOrderClothService orderClothService;
    @Autowired
    private AliPayService aliPayService;
    @Autowired
    private WechatPayService wechatPayService;
    @Autowired
    private IOrderPayInfoService orderPayInfoService;
    @Autowired
    private IOrderRefundInfoService orderRefundInfoService;
    @Autowired
    private DelayQueueCache delayQueueCache;

    private static final Logger log = LoggerFactory.getLogger(PayServiceImpl.class);


    @Override
    @Transactional(rollbackFor = Exception.class)
    public R unifiePaySuccessNotify(String orderPayNo, String orderNo, String outTradeNo) {
        OrderPayInfo orderPayInfo = orderPayInfoService.getOrderPayInfoByRequestNo(orderPayNo);
        if (orderPayInfo == null) {
            return R.fail("未查询到订单");
        }
        orderPayInfo.setPayStatus("1");
        orderPayInfoService.updateById(orderPayInfo);
        String header = orderPayNo.substring(0, 1);
        if (StringUtils.isBlank(orderNo)) {
            orderNo = orderPayInfo.getOrderNo();
        }

        switch (EnumUtils.getEnumByType(header, OrderNoHeaderType.class)) {
            case cloth_order_header: {
                return orderClothService.paySuccess(orderNo, outTradeNo);
            }
            case goods_order_header: {
                return orderGoodsService.handlePaySuccessUpdateOrderStatus(orderNo, outTradeNo);
            }
            case recharge_order_header: {
                return orderRechargeService.creatPassWordCardByPayNotify(orderNo, outTradeNo);
            }
            case activity_order_header: {
                return orderActivityService.handlePaySuccessUpdateActivityOrderStatus(orderNo);
            }
        }
        return R.fail("订单类型不正确");
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public R unifieRefundSuccessNotify(String requestNo, String orderNo, String outTradeNo) {
        OrderRefundInfo orderRefundInfo = orderRefundInfoService.getOrderRefundInfoByRequestNo(requestNo);
        if (orderRefundInfo == null) {
            return R.fail("未查询到订单");
        }
        orderRefundInfo.setRefundStatus("1");
        orderRefundInfoService.updateById(orderRefundInfo);
        String refundNo = orderRefundInfo.getRefundOrderNo();
        String header = refundNo.substring(0, 1);
        switch (EnumUtils.getEnumByType(header, OrderNoHeaderType.class)) {
            case cloth_order_header: {
                return orderClothService.refundSuccess(refundNo, orderNo);
            }
            case goods_order_header: {
                return orderGoodsService.handlePaySuccessUpdateOrderStatus(orderNo, null);
            }
            case recharge_order_header: {
                orderRechargeService.refundSuccess(orderNo);
                break;
            }
            case activity_order_header: {
                return orderActivityService.handlePaySuccessUpdateActivityOrderStatus(orderNo);
            }
        }
        return R.fail("订单类型不正确");
    }

    @Override
    public AppPayRespVO appPay(PayOrderAppDTO payOrderAppDTO) {
        OrderPayInfo orderPayInfo = orderPayInfoService.createOrderPayInfo(payOrderAppDTO.getStoreId(), payOrderAppDTO.getOrderNo(), payOrderAppDTO.getPayAmount(), payOrderAppDTO.getPayType());
        payOrderAppDTO.setRequestNo(orderPayInfo.getRequestNo());
        switch (EnumUtils.getEnumByType(payOrderAppDTO.getPayType(), PayType.class)) {
            case WECHAT: {
                if ("APP".equals(payOrderAppDTO.getPlatform())) {
                    return wechatPayService.appPay(payOrderAppDTO);
                } else {
                    payOrderAppDTO.setUserId(AuthHolder.openId());
                    return wechatPayService.xcxPay(payOrderAppDTO);
                }
            }
            case ALIPAY: {
                return aliPayService.appPay(payOrderAppDTO);
            }
            default:
                throw new ServiceException("支付方式为" + EnumUtils.getEnumByType(payOrderAppDTO.getPayType()
                        , PayType.class).getInfo() + "不支持第三方APP支付");
        }
    }

    @Override
    public OrderPayResultVO faceToFacePay(PayOrderFaceToFaceDTO payOrderFaceToFaceDTO) {
        if (payOrderFaceToFaceDTO.getExpireTime() == null) {
            throw new ServiceException("支付缺少过期时间");
        }
        OrderPayResultVO orderPayResultVO = new OrderPayResultVO();
        orderPayResultVO.setPayResult(100);
        // 1. 创建支付订单
        OrderPayInfo payInfo = orderPayInfoService.createOrderPayInfo(
                payOrderFaceToFaceDTO.getStoreId(),
                payOrderFaceToFaceDTO.getOrderNo(),
                payOrderFaceToFaceDTO.getPayAmount(),
                payOrderFaceToFaceDTO.getPayType()
        );
        //优先增加到延迟队列
        DelayMessage delayMessage = new DelayMessage(payInfo.getRequestNo(), DelayTagsEnum.ORDER_PAY_DELAY_QUEUE.getCode(), JSONUtil.toJsonStr(payInfo));
        //暂不执行
        payOrderFaceToFaceDTO.setRequestNo(payInfo.getRequestNo());
        PayResponseDTO payResponseDTO = null;
        switch (EnumUtils.getEnumByType(payOrderFaceToFaceDTO.getPayType(), PayType.class)) {
            case WECHAT: {
                payResponseDTO = wechatPayService.facePay(payOrderFaceToFaceDTO);
                break;
            }
            case ALIPAY: {
                payResponseDTO = aliPayService.facePay(payOrderFaceToFaceDTO);
                break;
            }
            default:
                payResponseDTO = PayResponseDTO.payError("支付方式不能为空");
        }
        if (payResponseDTO.getPayResult().equals(PayResult.success.getCode())) {
            unifiePaySuccessNotify(payInfo.getRequestNo(), payOrderFaceToFaceDTO.getOrderNo(), payResponseDTO.getOutTradeNo());
            orderPayResultVO = OrderPayResultVO.paySuccess(payOrderFaceToFaceDTO.getOrderNo());
            return orderPayResultVO;
        } else if (payResponseDTO.getPayResult().equals(PayResult.fail.getCode())) {
            //支付失败
            orderPayResultVO.setPayResult(101);
            orderPayResultVO.setOrderNo(payOrderFaceToFaceDTO.getOrderNo());
            orderPayResultVO.setPayMsg(payResponseDTO.getPayMsg());
            return orderPayResultVO;
        } else {
            //支付中，更新开始执行查询
            delayMessage.setIsRun(1);
            delayQueueCache.addDelayJob(delayMessage, PayQueryTimesEnum.getDelayTime(delayMessage.getPollingNum()));
            orderPayResultVO.setPayResult(100);
            orderPayResultVO.setOrderNo(payOrderFaceToFaceDTO.getOrderNo());
            orderPayResultVO.setPayMsg(payResponseDTO.getPayMsg());
            return orderPayResultVO;
        }
    }

    @Override
    public PayResponseDTO orderPayQuery(OrderPayInfo orderPayInfo) {
        PayResponseDTO payResponseDTO = null;
        switch (EnumUtils.getEnumByType(orderPayInfo.getPayType(), PayType.class)) {
            case WECHAT: {
                payResponseDTO = wechatPayService.orderPayQuery(orderPayInfo.getRequestNo());
                break;
            }
            case ALIPAY: {
                payResponseDTO = aliPayService.orderPayQuery(orderPayInfo.getRequestNo());
                break;
            }
            default:
                payResponseDTO = PayResponseDTO.payWait(orderPayInfo.getRequestNo());
        }
        return payResponseDTO;
    }

    @Override
    public RefundResponseDTO orderRefundQuery(PayRefundDTO payRefundDTO) {
        RefundResponseDTO refundResponseDTO = null;
        switch (EnumUtils.getEnumByType(payRefundDTO.getPayType(), PayType.class)) {
            case WECHAT: {
                refundResponseDTO = wechatPayService.orderRefundQuery(payRefundDTO.getOutRequestNo());
                break;
            }
            case ALIPAY: {
                refundResponseDTO = RefundResponseDTO.refundSuccess(payRefundDTO.getOutRequestNo(), payRefundDTO.getOutRequestNo());
                break;
            }
            default:
                refundResponseDTO = RefundResponseDTO.refundError("支付方式不能为空");
        }
        return refundResponseDTO;
    }

    /**
     * 退款
     *
     * @param payRefundDTO
     * @return 退款状态 OrderRefundStatus
     */
    @Override
    public String refund(PayRefundDTO payRefundDTO) {
        switch (EnumUtils.getEnumByType(payRefundDTO.getPayType(), PayType.class)) {
            case WECHAT: {
                return wxRefund(payRefundDTO);
            }
            case ALIPAY: {
                return alipayRefund(payRefundDTO);
            }
            default: {
                throw new ServiceException("当前订单支付方式为" + EnumUtils.getEnumByType(payRefundDTO.getPayType()
                        , PayType.class).getInfo() + "不支持的退款方式");
            }
        }

    }

    @Override
    public RefundResponseDTO refundApply(PayRefundDTO payRefundDTO) {
        OrderRefundInfo orderRefundInfo = orderRefundInfoService.createOrderRefundInfo(payRefundDTO);
        payRefundDTO.setOutRequestNo(orderRefundInfo.getRequestNo());
        RefundResponseDTO response = new RefundResponseDTO();
        switch (EnumUtils.getEnumByType(payRefundDTO.getPayType(), PayType.class)) {
            case WECHAT: {
                response = wechatPayService.orderRefund(payRefundDTO);
            }
            case ALIPAY: {
                response = aliPayService.orderRefund(payRefundDTO);
            }
            default: {
                response = RefundResponseDTO.refundError("不支持第三方APP退款");
            }
        }
        if (PayResult.success.getCode() == (response.getRefundResult())) {
            // 退款成功
            unifieRefundSuccessNotify(payRefundDTO.getOutRequestNo(), payRefundDTO.getOrderNo(), payRefundDTO.getOutTradeNo());
        } else if (PayResult.fail.getCode() == (response.getRefundResult())) {
            // 退款失败
        } else {
            // 退款处理中,加入延迟队列
            DelayMessage delayMessage = new DelayMessage(
                    payRefundDTO.getOutRequestNo(),
                    DelayTagsEnum.ORDER_REUND_DELAY_QUEUE_TASK.getCode(),
                    JSONUtil.toJsonStr(payRefundDTO)
            );

            delayQueueCache.addDelayJob(
                    delayMessage,
                    RefundQueryTimesEnum.getDelayTime(delayMessage.getPollingNum())
            );
        }
        return response;
    }

    /**
     * @param orderNo      订单编号
     * @param refundStatus 退款状态，枚举值：
     *                     SUCCESS：退款成功
     *                     CLOSED：退款关闭
     *                     ABNORMAL：退款异常，退款到银行发现用户的卡作废或者冻结了，导致原路退款银行卡失败，可前往【商户平台—>交易中心】，手动处理此笔退款
     */
    @Override
    public void refundNotify(String orderNo, String refundStatus) {
        String header = orderNo.substring(0, 1);
        switch (EnumUtils.getEnumByType(header, OrderNoHeaderType.class)) {
            case cloth_order_header: {
                if (OrderRefundStatus.REFUND_SUCCESS.getCode().equals(refundStatus)) {
                    orderClothService.refundSuccess(null, orderNo);
                } else if (OrderRefundStatus.REFUND_CANCEL.getCode().equals(refundStatus)) {
                    orderClothService.refundClosed(orderNo);
                } else {
                    orderClothService.refundError(orderNo);
                }
                return;
            }
            case goods_order_header: {
                if (OrderRefundStatus.REFUND_SUCCESS.getCode().equals(refundStatus)) {
                    orderGoodsService.refundSuccess(null, orderNo);
                } else if (OrderRefundStatus.REFUND_CANCEL.getCode().equals(refundStatus)) {
                    orderGoodsService.refundClosed(null, orderNo);
                } else {
                    orderGoodsService.refundError(null, orderNo);
                }
                return;
            }
            case recharge_order_header: {
                if (OrderRefundStatus.REFUND_SUCCESS.getCode().equals(refundStatus)) {
                    orderRechargeService.refundSuccess(orderNo);
                } else if (OrderRefundStatus.REFUND_CANCEL.getCode().equals(refundStatus)) {
                    orderRechargeService.refundClosed(orderNo);
                } else {
                    orderRechargeService.refundError(orderNo);
                }
                return;
            }
            case activity_order_header: {
                if (OrderRefundStatus.REFUND_SUCCESS.getCode().equals(refundStatus)) {
                    orderActivityService.refundSuccess(orderNo);
                } else if (OrderRefundStatus.REFUND_CANCEL.getCode().equals(refundStatus)) {
                    orderActivityService.refundClosed(orderNo);
                } else {
                    orderActivityService.refundError(orderNo);
                }
                return;
            }
        }
        throw new ServiceException("订单类型不正确");
    }

    private String wxRefund(PayRefundDTO payRefundDTO) {
        RefundService refundService = new RefundService.Builder().config(WxPayConfigs.getConfig()).build();
        CreateRequest request = new CreateRequest();
        request.setOutTradeNo(payRefundDTO.getOrderNo());
        request.setOutRefundNo(orderNoUtils.getOrderNo());
        request.setReason(payRefundDTO.getRefundReason());
        AmountReq amountReq = new AmountReq();
        amountReq.setRefund(payRefundDTO.getRefundAmount().multiply(new BigDecimal(100)).longValue());
        amountReq.setTotal(payRefundDTO.getRefundAmount().multiply(new BigDecimal(100)).longValue());
        amountReq.setCurrency("CNY");
        request.setAmount(amountReq);
        request.setNotifyUrl(WxPayConfigs.getRefundNotifyUrl());
        Refund refund = refundService.create(request);
        return OrderRefundStatus.wxStatusTransfer(refund.getStatus());
    }

    private String alipayRefund(PayRefundDTO payRefundDTO) {
        AlipayClient alipayClient = null;
        try {
            alipayClient = new DefaultAlipayClient(getAlipayConfig());
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }
        AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
        JSONObject bizContent = new JSONObject();
        bizContent.put("out_trade_no", payRefundDTO.getOrderNo());
        bizContent.put("refund_amount", payRefundDTO.getRefundAmount().setScale(2, RoundingMode.HALF_UP).doubleValue());
        if (StringUtils.isNotEmpty(payRefundDTO.getOutRequestNo())) {
            bizContent.put("out_request_no", payRefundDTO.getOutRequestNo());
        }
        if (StringUtils.isNotEmpty(payRefundDTO.getRefundReason())) {
            bizContent.put("refund_reason", payRefundDTO.getRefundReason());
        }


        //// 返回参数选项，按需传入
        //JSONArray queryOptions = new JSONArray();
        //queryOptions.add("refund_detail_item_list");
        //bizContent.put("query_options", queryOptions);

        request.setBizContent(bizContent.toString());
        AlipayTradeRefundResponse response = null;
        try {
            response = alipayClient.certificateExecute(request);
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }
        if (!response.isSuccess() && !"10000".equals(response.getCode())) {
            throw new ServiceException("退款请求失败，errorCode:" + response.getCode() + ";errorMsg:"
                    + response.getMsg() + ";subCode:" + response.getSubCode() + ";subMsg:" + response.getSubMsg());
        }
        return OrderRefundStatus.REFUND_SUCCESS.getCode();
    }

    //<editor-folder desc="支付宝校验订单状态">
    @Override
    public AlipayTradeQueryResponse alipayCheckOrderStatus(String orderNo) {
        AlipayClient alipayClient = null;
        try {
            alipayClient = new DefaultAlipayClient(getAlipayConfig());
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }
        AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
        JSONObject bizContent = new JSONObject();
        //商户订单号，商家自定义，保持唯一性
        bizContent.put("out_trade_no", orderNo);
        request.setBizContent(bizContent.toString());
        AlipayTradeQueryResponse response = null;
        try {
            response = alipayClient.certificateExecute(request);
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }
        if (!response.isSuccess()) {
            log.info("支付宝支付校验状态失败，errorCode:" + response.getCode() + ";errorMsg:"
                    + response.getMsg() + ";subCode:" + response.getSubCode() + ";subMsg:" + response.getSubMsg());
        }
        return response;
    }

    private AlipayConfig getAlipayConfig() {
        AlipayConfig alipayConfig = new AlipayConfig();
        //设置网关地址
//        alipayConfig.setServerUrl(Configs.getOpenApiDomain());
        //设置应用APPID
        alipayConfig.setAppId(AlipayConfigs.getAppid());
        //设置应用私钥
        alipayConfig.setPrivateKey(AlipayConfigs.getPrivateKey());
        //设置应用公钥证书路径
        alipayConfig.setAppCertPath(AlipayConfigs.getPublicKey());
        //设置支付宝公钥证书路径
        alipayConfig.setAlipayPublicCertPath(AlipayConfigs.getAlipayPublicKey());
        //设置支付宝根证书路径
        alipayConfig.setRootCertPath(AlipayConfigs.getAlipayRootKey());
        //设置请求格式，固定值json
//        alipayConfig.setFormat("json");
        //设置字符集
//        alipayConfig.setCharset("UTF-8");
        //设置签名类型
        alipayConfig.setSignType(AlipayConfigs.getSignType());

        return alipayConfig;
    }


}
