package com.czg.service.order.service.impl;

import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSONObject;
import com.czg.PayAdapter;
import com.czg.PayAdapterFactory;
import com.czg.PayCst;
import com.czg.constant.PayChannelCst;
import com.czg.constants.ParamCodeCst;
import com.czg.constants.PayTypeConstants;
import com.czg.enums.CzgPayEnum;
import com.czg.exception.CzgException;
import com.czg.order.dto.LtPayOtherDTO;
import com.czg.order.entity.OrderPayment;
import com.czg.order.entity.ShopMerchant;
import com.czg.order.service.OrderPaymentService;
import com.czg.order.service.ShopMerchantService;
import com.czg.pay.CzgPayBaseReq;
import com.czg.pay.CzgRefundReq;
import com.czg.pay.QueryOrderRespDTO;
import com.czg.pay.RefundRespDTO;
import com.czg.resp.CzgResult;
import com.czg.service.order.mapper.OrderPaymentMapper;
import com.czg.service.order.service.PayService;
import com.czg.system.service.SysParamsService;
import com.czg.utils.AssertUtil;
import com.mybatisflex.core.query.QueryWrapper;
import jakarta.annotation.Resource;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Map;

/**
 * @author ww
 * @description
 */
@Slf4j
@Service
public class PayServiceImpl implements PayService {

    @Resource
    private ShopMerchantService shopMerchantService;
    @DubboReference
    private SysParamsService sysParamsService;
    @Resource
    private OrderPaymentService paymentService;
    @Resource
    private OrderPaymentMapper paymentMapper;

    @Override
    public CzgResult<Map<String, Object>> pay(@NonNull Long shopId, CzgPayEnum payType, CzgPayBaseReq bizData) {
        ShopMerchant shopMerchant = getMerchant(shopId);
        PayAdapter adapter = PayAdapterFactory.getAdapter(shopMerchant.getChannel());
        String payData = null;
        if (shopMerchant.getChannel().equals(PayChannelCst.NATIVE)) {
            payData = shopMerchant.getNativePayJson();
        } else if (shopMerchant.getChannel().equals(PayChannelCst.POLY)) {
            payData = shopMerchant.getPolyPayJson();
        }
        if (payType.equals(CzgPayEnum.MICRO_PAY)) {
            checkMicroPay(bizData, shopMerchant);
        }
        if (!PayCst.Type.WECHAT.equals(bizData.getPayType()) && !PayCst.Type.ALIPAY.equals(bizData.getPayType())) {
            throw new CzgException("支付方式错误");
        }
        bizData.setSubAppid(PayCst.Type.ALIPAY.equals(bizData.getPayType()) ? shopMerchant.getAlipayAppId() : shopMerchant.getWechatAppId());
        return adapter.pay(payType, payData, getDomain(), getNotifyUrl(shopMerchant.getChannel()), bizData);
    }

    @Override
    @Transactional
    public CzgResult<Map<String, Object>> ltPayOther(LtPayOtherDTO param, String payType, String detail) {
        AssertUtil.isBlank(param.getOpenId(), "用户小程序ID不能为空");
        AssertUtil.isBlank(param.getPayType(), "支付方式不能为空");
        String payOrderNo = "LT" + IdUtil.getSnowflakeNextId();
        initPayment(OrderPayment.pay(param.getShopId(), param.getRecordId(), payType, payOrderNo,
                param.getPrice(), "", param.getRelatedId()));
        return pay(param.getShopId(), CzgPayEnum.LT_PAY,
                CzgPayBaseReq.ltPayReq(payOrderNo, detail, param.getPrice().multiply(MONEY_RATE).longValue(),
                        param.getPayType(), param.getOpenId(), param.getIp()));
    }

    @Override
    public CzgResult<RefundRespDTO> refund(@NonNull Long shopId, CzgRefundReq bizData) {
        ShopMerchant shopMerchant = getMerchant(shopId);
        PayAdapter adapter = PayAdapterFactory.getAdapter(shopMerchant.getChannel());
        String payData = null;
        if (shopMerchant.getChannel().equals(PayChannelCst.NATIVE)) {
            payData = shopMerchant.getNativePayJson();
            bizData.setNotifyUrl(sysParamsService.getSysParamValue(ParamCodeCst.System.NATIVE_REFUND_NOTIFY_URL));
        } else if (shopMerchant.getChannel().equals(PayChannelCst.POLY)) {
            payData = shopMerchant.getPolyPayJson();
            bizData.setNotifyUrl(sysParamsService.getSysParamValue(ParamCodeCst.System.POLY_REFUND_NOTIFY_URL));
        }
        return adapter.refund(getDomain(), payData, bizData);
    }

    @Override
    @Transactional
    public void unifyRefund(@NonNull Long shopId, @NonNull Long sourceId, @NonNull Long payOrderId, @NonNull String refPayOrderNo,
                            @NonNull String refundReason, @NonNull BigDecimal refundAmount) {
        OrderPayment payment = paymentService.getById(payOrderId);
        AssertUtil.isNull(payment, "退款失败,支付记录不存在");
        Long refundId = initPayment(OrderPayment.refund(payment.getChannel(), shopId, sourceId, payment.getSourceType(), refPayOrderNo, refundAmount, payment.getId(), payment.getPlatformType()));
        CzgResult<RefundRespDTO> refund = refund(shopId, new CzgRefundReq(refPayOrderNo, refundReason, refundAmount.multiply(MONEY_RATE).longValue(),
                payment.getAmount().multiply(PayService.MONEY_RATE).longValue(), payment.getOrderNo(), "", payment.getPlatformType()));
        OrderPayment uOrderPayment = new OrderPayment();
        uOrderPayment.setRespJson(JSONObject.toJSONString(refund.getData()));
        if (refund.getCode() != 200 || refund.getData() == null || !"SUCCESS".equals(refund.getData().getStatus())) {
            uOrderPayment.setPayStatus(PayTypeConstants.PayStatus.FAIL);
        } else {
            uOrderPayment.setTradeNumber(refund.getData().getThirdRefundNo());
            uOrderPayment.setPayStatus(PayTypeConstants.PayStatus.SUCCESS);
            uOrderPayment.setPayTime(LocalDateTimeUtil.parse(refund.getData().getRefundTime(), "yyyy-MM-dd HH:mm:ss"));
            uOrderPayment.setRespJson(refund.getData().getOriginalData());
        }
        paymentService.update(uOrderPayment, QueryWrapper.create().eq(OrderPayment::getId, refundId));
    }

    @Override
    @Transactional
    public void unifyRefund(OrderPayment refundPayment, String refPayOrderNo) {
        //支付的 订单
        OrderPayment payment = paymentService.getById(refundPayment.getRelatedId());
        AssertUtil.isNull(payment, "退款失败,支付记录不存在");
        Long refundCompensate = initPayment(OrderPayment.refundCompensate(refundPayment.getShopId(), refundPayment.getSourceId(),
                payment.getSourceType(), refPayOrderNo, refundPayment.getAmount(), refundPayment.getId()));
        CzgResult<RefundRespDTO> refund = refund(payment.getShopId(), new CzgRefundReq(refPayOrderNo, "退款补偿", refundPayment.getAmount().multiply(MONEY_RATE).longValue(),
                payment.getAmount().multiply(PayService.MONEY_RATE).longValue(), payment.getOrderNo(), "", payment.getPlatformType()));
        OrderPayment uOrderPayment = new OrderPayment();
        uOrderPayment.setTradeNumber(refund.getData().getThirdRefundNo());
        uOrderPayment.setRespJson(JSONObject.toJSONString(refund.getData()));
        if (refund.getCode() != 200 || refund.getData() == null || !"SUCCESS".equals(refund.getData().getStatus())) {
            uOrderPayment.setPayStatus(PayTypeConstants.PayStatus.FAIL);
        } else {
            uOrderPayment.setPayStatus(PayTypeConstants.PayStatus.SUCCESS);
            uOrderPayment.setPayTime(LocalDateTimeUtil.parse(refund.getData().getRefundTime(), "yyyy-MM-dd HH:mm:ss"));
            uOrderPayment.setRespJson(refund.getData().getOriginalData());
        }
        paymentService.update(uOrderPayment, QueryWrapper.create().eq(OrderPayment::getId, refundPayment.getId()));
        paymentService.update(uOrderPayment, QueryWrapper.create().eq(OrderPayment::getId, refundCompensate));
    }

    @Override
    @Transactional
    public CzgResult<QueryOrderRespDTO> queryPayOrder(@NonNull Long shopId, String payOrderId, String mchOrderNo, String platform) {
        ShopMerchant shopMerchant = getMerchant(shopId);
        PayAdapter adapter = PayAdapterFactory.getAdapter(shopMerchant.getChannel());
        String payData = null;
        if (shopMerchant.getChannel().equals(PayChannelCst.NATIVE)) {
            payData = shopMerchant.getNativePayJson();
        } else if (shopMerchant.getChannel().equals(PayChannelCst.POLY)) {
            payData = shopMerchant.getPolyPayJson();
        }
        return adapter.queryPayOrder(getDomain(), payData, payOrderId, mchOrderNo, platform);
    }

    @Override
    @Transactional
    public CzgResult<RefundRespDTO> queryRefund(@NonNull Long shopId, String mchRefundNo, String refundOrderId) {
        ShopMerchant shopMerchant = getMerchant(shopId);
        PayAdapter adapter = PayAdapterFactory.getAdapter(shopMerchant.getChannel());
        String payData = null;
        if (shopMerchant.getChannel().equals(PayChannelCst.NATIVE)) {
            payData = shopMerchant.getNativePayJson();
        } else if (shopMerchant.getChannel().equals(PayChannelCst.POLY)) {
            payData = shopMerchant.getPolyPayJson();
        }
        return adapter.queryRefund(getDomain(), payData, mchRefundNo, refundOrderId);
    }


    @Override
    public Long initPayment(OrderPayment payment) {
        paymentMapper.insert(payment);
        return payment.getId();
    }

    private ShopMerchant getMerchant(Long shopId) {
        ShopMerchant shopMerchant = shopMerchantService.getByShopId(shopId);
        if (shopMerchant == null || StrUtil.isBlank(shopMerchant.getChannel())) {
            throw new CzgException("暂未开通支付!");
        }
        if (shopMerchant.getChannel().equals(PayChannelCst.NATIVE)) {
            if (StrUtil.isBlank(shopMerchant.getNativePayJson())) {
                throw new CzgException("原生支付未开通");
            }
        } else if (shopMerchant.getChannel().equals(PayChannelCst.POLY)) {
            if (StrUtil.isBlank(shopMerchant.getPolyPayJson())) {
                throw new CzgException("聚合支付未开通");
            }
        } else {
            throw new CzgException("暂不支持的支付渠道");
        }
        return shopMerchant;
    }

    private String getDomain() {
        return sysParamsService.getSysParamValue(ParamCodeCst.System.POLY_DOMAIN);
    }

    private String getNotifyUrl(String channel) {
        String notifyUrl = "";
        if (channel.equals(PayChannelCst.NATIVE)) {
            notifyUrl = sysParamsService.getSysParamValue(ParamCodeCst.System.NATIVE_PAY_NOTIFY_URL);
        } else if (channel.equals(PayChannelCst.POLY)) {
            notifyUrl = sysParamsService.getSysParamValue(ParamCodeCst.System.POLY_PAY_NOTIFY_URL);
        }
        if (StrUtil.isBlank(notifyUrl)) {
            throw new CzgException(channel.equals(PayChannelCst.NATIVE) ? "原生支付回调地址未配置" : "聚合支付回调地址未配置");
        }
        return notifyUrl;
    }

    private void checkMicroPay(CzgPayBaseReq bizData, ShopMerchant shopMerchant) {
        String data = bizData.getAuthCode();
        AssertUtil.isBlank(data, "扫码失败，请重试");
        if (data.length() > 26) {
            throw new CzgException("支付失败，不支持的条码");
        }
        String firstTwoDigitsStr = data.substring(0, 2);
        // 将截取的字符串转换为整数
        int firstTwoDigits = Integer.parseInt(firstTwoDigitsStr);
        // 判断范围
        if (firstTwoDigits >= 10 && firstTwoDigits <= 15) {
            //微信支付
            bizData.setSubAppid(shopMerchant.getWechatAppId());
            bizData.setPayType(PayCst.Type.WECHAT);
        } else if (firstTwoDigits >= 25 && firstTwoDigits <= 30) {
            //支付宝支付
            bizData.setSubAppid(shopMerchant.getAlipayAppId());
            bizData.setPayType(PayCst.Type.ALIPAY);
        } else {
            throw new CzgException("扫描码非法或暂不支持");
        }
    }
}
