package com.cf.imes.module.system.service.pay.factory.impl.wechat;

import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.date.TemporalAccessorUtil;
import cn.hutool.core.text.CharSequenceUtil;
import com.alibaba.fastjson.JSON;
import com.cf.imes.framework.common.util.json.JsonUtils;
import com.cf.imes.framework.pay.config.ChenfengWechatPayConfig;
import com.cf.imes.framework.pay.core.client.dto.order.PayOrderRespDTO;
import com.cf.imes.module.system.controller.admin.pay.vo.PayOrderUnifiedReqDTO;
import com.cf.imes.framework.pay.core.enums.order.PayOrderDisplayModeEnum;
import com.cf.imes.module.system.enums.pay.PayChannelCodeEnum;
import com.cf.imes.module.system.enums.pay.PayOrderStatusEnum;
import com.cf.imes.module.system.service.pay.factory.impl.AbstractPayHandler;
import com.github.binarywang.wxpay.bean.notify.SignatureHeader;
import com.github.binarywang.wxpay.bean.notify.WxPayNotifyV3Result;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderV3Request;
import com.github.binarywang.wxpay.bean.result.enums.TradeTypeEnum;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Map;

import static cn.hutool.core.date.DatePattern.UTC_WITH_XXX_OFFSET_PATTERN;
import static com.cf.imes.framework.common.util.servlet.ServletUtils.getClientIP;

/**
 * 微信native支付处理器
 *
 * @author Gqr
 * @since 2025/4/15 15:46
 */
@Service("wechatNativePayHandler")
@Slf4j
public class WechatNativePayHandler extends AbstractPayHandler {

    @Resource
    private ChenfengWechatPayConfig chenfengWechatPayConfig;

    @Override
    public PayOrderRespDTO unifiedOrder(PayOrderUnifiedReqDTO reqDTO) throws WxPayException {
        // 构建 WxPayUnifiedOrderRequest 对象
        WxPayUnifiedOrderV3Request request = new WxPayUnifiedOrderV3Request();
        request.setOutTradeNo(reqDTO.getOutTradeNo());
        request.setDescription(reqDTO.getSubject());
        request.setAmount(new WxPayUnifiedOrderV3Request.Amount().setTotal(reqDTO.getPrice().multiply(new BigDecimal(100)).intValue())); // 单位分
        request.setTimeExpire(formatDateV3(reqDTO.getExpireTime()));
        request.setSceneInfo(new WxPayUnifiedOrderV3Request.SceneInfo().setPayerClientIp(getClientIP()));
        request.setNotifyUrl(reqDTO.getNotifyUrl());
        request.setAttach(JSON.toJSONString(reqDTO.getPassbackParams()));

        // 加载配置，创建client
        WxPayService client = new WxPayServiceImpl();
        client.setConfig(chenfengWechatPayConfig);

        // 执行请求
        String response = client.createOrderV3(TradeTypeEnum.NATIVE, request);

        // 转换结果
        return PayOrderRespDTO.waitingOf(PayOrderDisplayModeEnum.APP.getMode(), JsonUtils.toJsonString(response),
                reqDTO.getOutTradeNo(), response, PayChannelCodeEnum.WECHAT_NATIVE.getCode());
    }

    @Override
    public PayOrderRespDTO queryPayOrder(String outTradeNo) {
        return null;
    }

    @Override
    public PayOrderRespDTO doParseOrderNotify(Map<String, String> params, String body, Map<String, String> headers) throws WxPayException {
        // 1. 解析回调
        SignatureHeader signatureHeader = getRequestHeader(headers);
        // 加载配置，创建client
        WxPayService client = new WxPayServiceImpl();
        client.setConfig(chenfengWechatPayConfig);

        WxPayNotifyV3Result response = client.parseOrderNotifyV3Result(body, signatureHeader);
        WxPayNotifyV3Result.DecryptNotifyResult result = response.getResult();
        // 2. 构建结果
        Integer status = parseStatus(result.getTradeState());
        String openid = result.getPayer() != null ? result.getPayer().getOpenid() : null;
        return PayOrderRespDTO.of(status, result.getTransactionId(), openid, parseDateV3(result.getSuccessTime()),
                result.getOutTradeNo(), body, JSON.parseObject(result.getAttach(), Map.class));
    }

    static String formatDateV3(LocalDateTime time) {
        return TemporalAccessorUtil.format(time.atZone(ZoneId.systemDefault()), UTC_WITH_XXX_OFFSET_PATTERN);
    }

    /**
     * 组装请求头重的签名信息
     *
     * @see <a href="https://github.com/binarywang/weixin-java-pay-demo/blob/master/src/main/java/com/github/binarywang/demo/wx/pay/controller/WxPayV3Controller.java#L202-L221">官方示例</a>
     */
    private SignatureHeader getRequestHeader(Map<String, String> headers) {
        return SignatureHeader.builder()
                .signature(headers.get("wechatpay-signature"))
                .nonce(headers.get("wechatpay-nonce"))
                .serial(headers.get("wechatpay-serial"))
                .timeStamp(headers.get("wechatpay-timestamp"))
                .build();
    }

    private static Integer parseStatus(String tradeState) {
        switch (tradeState) {
            case "NOTPAY":
            case "USERPAYING": // 支付中，等待用户输入密码（条码支付独有）
                return PayOrderStatusEnum.WAITING.getStatus();
            case "SUCCESS":
                return PayOrderStatusEnum.SUCCESS.getStatus();
//            case "REFUND":
//                return PayOrderStatusEnum.REFUND.getStatus();
            case "CLOSED":
            case "REVOKED": // 已撤销（刷卡支付独有）
            case "PAYERROR": // 支付失败（其它原因，如银行返回失败）
                return PayOrderStatusEnum.FAIL.getStatus();
            default:
                throw new IllegalArgumentException(CharSequenceUtil.format("未知的支付状态({})", tradeState));
        }
    }

    static LocalDateTime parseDateV3(String time) {
        return LocalDateTimeUtil.parse(time, UTC_WITH_XXX_OFFSET_PATTERN);
    }

}
