package com.ruoyi.web.modules.pay.service.impl;

import java.util.Date;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.web.modules.order.domain.BizOrder;
import com.ruoyi.web.modules.order.service.IOrderPaySuccessService;
import com.ruoyi.web.modules.order.support.CheckoutSupport;
import com.ruoyi.web.modules.pay.config.WeChatPayProperties;
import com.ruoyi.web.modules.pay.constant.PayConstants;
import com.ruoyi.web.modules.pay.domain.BizPayRecord;
import com.ruoyi.web.modules.pay.mapper.BizPayRecordMapper;
import com.ruoyi.web.modules.pay.service.IShopWechatPayService;
import com.ruoyi.web.modules.pay.service.IWeChatPayService;
import com.ruoyi.web.modules.pay.support.WeChatPaySupport;
import com.ruoyi.web.modules.pay.vo.WeChatPayParamsVO;

@Service
public class WeChatPayServiceImpl implements IWeChatPayService
{
    @Autowired
    private WeChatPayProperties payProperties;

    @Autowired
    private WeChatPaySupport paySupport;

    @Autowired
    private BizPayRecordMapper payRecordMapper;

    @Autowired
    private IShopWechatPayService shopWechatPayService;

    @Autowired
    private IOrderPaySuccessService orderPaySuccessService;

    @Autowired
    private CheckoutSupport checkoutSupport;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public WeChatPayParamsVO createJsapiPay(Long memberId, BizOrder order, String openid)
    {
        checkoutSupport.assertPendingPay(order);
        checkoutSupport.assertNotExpired(order, new Date());
        WeChatPayParamsVO vo = new WeChatPayParamsVO();
        vo.setOrderId(order.getOrderId());
        vo.setOrderNo(order.getOrderNo());
        if (!payProperties.isRealPayEnabled())
        {
            ensurePayRecord(order, memberId);
            vo.setMock(true);
            return vo;
        }
        if (StringUtils.isEmpty(openid))
        {
            throw new ServiceException(PayConstants.MSG_OPENID_REQUIRED);
        }
        String mchId = shopWechatPayService.resolvePayMchId(order.getShopId());
        BizPayRecord record = ensurePayRecord(order, memberId);
        String prepayId = paySupport.createJsapiPrepayId(record.getOutTradeNo(), "商城订单-" + order.getOrderNo(),
                order.getPayAmount(), openid, mchId, payProperties.getNotifyUrl());
        record.setPrepayId(prepayId);
        record.setUpdateTime(new Date());
        payRecordMapper.updateForPrepay(record);
        Map<String, String> params = paySupport.buildJsapiPayParams(prepayId);
        vo.setMock(false);
        vo.setPayParams(params);
        return vo;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void handleNotify(String rawBody, String timestamp, String nonce, String signature)
    {
        paySupport.verifyNotifySignature(timestamp, nonce, rawBody, signature);
        JSONObject notifyBody = JSON.parseObject(rawBody);
        if (notifyBody == null || notifyBody.getJSONObject("resource") == null)
        {
            throw new ServiceException(PayConstants.MSG_PAY_NOTIFY_INVALID);
        }
        JSONObject resource = notifyBody.getJSONObject("resource");
        JSONObject plain = paySupport.decryptNotifyResource(resource.getString("associated_data"),
                resource.getString("nonce"), resource.getString("ciphertext"));
        if (plain == null || !"SUCCESS".equals(plain.getString("trade_state")))
        {
            return;
        }
        String outTradeNo = plain.getString("out_trade_no");
        String transactionId = plain.getString("transaction_id");
        if (StringUtils.isEmpty(outTradeNo) || StringUtils.isEmpty(transactionId))
        {
            throw new ServiceException(PayConstants.MSG_PAY_NOTIFY_INVALID);
        }
        orderPaySuccessService.completeWeChatPay(outTradeNo, transactionId, new Date());
    }

    private BizPayRecord ensurePayRecord(BizOrder order, Long memberId)
    {
        BizPayRecord existing = payRecordMapper.selectLatestByOrderId(order.getOrderId());
        if (existing != null && PayConstants.PAY_STATUS_PENDING.equals(existing.getPayStatus()))
        {
            return existing;
        }
        Date now = new Date();
        BizPayRecord record = new BizPayRecord();
        record.setOrderId(order.getOrderId());
        record.setOrderNo(order.getOrderNo());
        record.setMemberId(memberId);
        record.setShopId(order.getShopId());
        record.setPayChannel(PayConstants.CHANNEL_WECHAT);
        record.setOutTradeNo(order.getOrderNo());
        record.setPayAmount(order.getPayAmount());
        record.setPayStatus(PayConstants.PAY_STATUS_PENDING);
        record.setCreateTime(now);
        record.setUpdateTime(now);
        payRecordMapper.insert(record);
        return record;
    }
}
