package com.seer.teach.pay.app.client.wechat;

import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.seer.teach.common.enums.pay.PayChannelEnum;
import com.seer.teach.common.utils.DateUtils;
import com.seer.teach.common.enums.pay.PayStatusEnum;
import com.seer.teach.common.enums.ResultCodeEnum;
import com.seer.teach.common.exception.CommonException;
import com.seer.teach.common.utils.AssertUtils;
import com.seer.teach.common.utils.MoneyUtil;
import com.seer.teach.pay.app.client.AbstractPayClient;
import com.seer.teach.pay.app.client.dto.PayOrderReqDTO;
import com.seer.teach.pay.app.client.dto.RefundNotificationRespDTO;
import com.seer.teach.pay.app.client.wechat.core.WechatPlayClient;
import com.seer.teach.pay.app.client.wechat.core.resp.WechatPrepayTransactionResp;
import com.seer.teach.pay.app.client.dto.PayOrderCallBackRespDTO;
import com.seer.teach.pay.app.client.dto.PayOrderRespDTO;
import com.seer.teach.pay.app.client.dto.PayRefundReqDTO;
import com.seer.teach.pay.dto.RefundSubmitRespDTO;
import com.seer.teach.pay.entity.PayOrderEntity;
import com.seer.teach.pay.entity.PayOrderExtensionEntity;
import com.seer.teach.user.api.UserInfoServiceApi;
import com.seer.teach.user.api.dto.UserAuthDTO;
import com.wechat.pay.java.service.payments.model.Transaction;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

/**
 * 微信支付策略实现
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class WechatJsApiPayClient extends AbstractPayClient {

    private WechatPlayClient wechatPlayClient;

    private final UserInfoServiceApi userInfoServiceApi;

    /**
     * 获取支付渠道的编码
     *
     * @return 支付渠道编码
     */
    @Override
    public PayChannelEnum getChannel() {
        return PayChannelEnum.WECHAT_JSAPI;
    }


    @Override
    public boolean isAsyncCallback() {
        return true;
    }

    @Override
    public void init(String configJson) {
        wechatPlayClient = new WechatPlayClient(configJson);
    }

    @Override
    protected Object getPrepayRequestParam(PayOrderReqDTO payOrder) {
        UserAuthDTO userAuthDTO = userInfoServiceApi.getUserAuthByUserIdAndAppId(payOrder.getUserId(), wechatPlayClient.getAppId());
        return userAuthDTO.getOpenId();
    }

    /**
     * 创建支付订单
     *
     * @param payOrder 支付订单实体
     * @return 创建的支付订单结果
     */
    @Override
    protected PayOrderRespDTO doPayOrder(PayOrderReqDTO payOrder, Object extrasRequest) {
        try {
            // 调用微信预支付接口时传入配置
            log.info("准备调用微信预支付接口");
            WechatPrepayTransactionResp wechatResp = wechatPlayClient.prepayPay(payOrder, extrasRequest);

            log.info("微信预支付接口调用完成");
            // 检查微信预支付响应是否为空
            if (wechatResp == null) {
                log.error("微信预支付接口返回空响应，订单号：{}", payOrder.getPayOrderSn());
                throw new CommonException(ResultCodeEnum.WX_PREPAY_ERROR, "微信预支付接口返回空响应");
            }

            log.info("微信预支付接口调用成功，响应数据：{}", wechatResp);

            // 检查响应中的关键字段
            if (wechatResp.getPackageVal() == null || wechatResp.getPackageVal().isEmpty()) {
                log.error("微信预支付响应中packageVal为空，订单号：{}", payOrder.getPayOrderSn());
                throw new CommonException(ResultCodeEnum.WX_PREPAY_ERROR, "微信预支付响应中packageVal为空");
            }

            // 构造返回结果
            PayOrderRespDTO response = new PayOrderRespDTO();
            response.setChannelCode(payOrder.getChannelCode());
            response.setStatus(PayStatusEnum.PENDING.getCode());

            // 构造微信支付参数
            Map<String, Object> payParams = new HashMap<>();
            payParams.put("appId", wechatResp.getAppId());
            payParams.put("timeStamp", wechatResp.getTimeStamp());
            payParams.put("nonceStr", wechatResp.getNonceStr());
            payParams.put("package", wechatResp.getPackageVal());
            payParams.put("signType", wechatResp.getSignType());
            payParams.put("paySign", wechatResp.getPaySign());
            response.setPayParams(payParams);

            // 从 packageVal 中提取 prepayId
            String prepayId = extractPrepayIdFromPackage(wechatResp.getPackageVal());
            response.setPrepayId(prepayId);

            log.info("微信预支付订单创建成功，订单号：{}，支付金额：{}元，prepayId：{}",
                    payOrder.getPayOrderSn(), MoneyUtil.centToYuan(payOrder.getTotalAmount()), prepayId);

            // 验证关键字段是否成功设置
            if (response.getPrepayId() == null || response.getPrepayId().isEmpty()) {
                log.error("prepayId为空，订单号：{}", payOrder.getPayOrderSn());
                throw new CommonException(ResultCodeEnum.WX_PREPAY_ERROR, "prepayId为空");
            }

            if (response.getPayParams() == null) {
                log.error("payParams为空，订单号：{}", payOrder.getPayOrderSn());
                throw new CommonException(ResultCodeEnum.WX_PREPAY_ERROR, "payParams为空");
            }


            return response;
        } catch (Exception e) {
            log.error("创建微信预支付订单失败，订单号：{}，支付金额：{}元",
                    payOrder.getPayOrderSn(), MoneyUtil.centToYuan(payOrder.getTotalAmount()), e);
            throw new CommonException(ResultCodeEnum.WX_PREPAY_ERROR, "微信预支付失败: " + e.getMessage());
        }
    }

    /**
     * 查询支付状态
     *
     * @param orderSn 订单号
     * @return 支付订单
     */
    @Override
    protected PayOrderEntity doQueryPayStatus(String orderSn) {
        log.info("查询微信支付状态，订单号：{}", orderSn);
        PayOrderEntity payOrder = payOrderService.getOne(
                new LambdaQueryWrapper<PayOrderEntity>()
                        .eq(PayOrderEntity::getOrderSn, orderSn)
                        .eq(PayOrderEntity::getChannelCode, getChannel())
        );
        if (payOrder == null) {
            log.warn("支付订单不存在，订单号：{}", orderSn);
            return null;
        }
        if (Integer.valueOf(PayStatusEnum.SUCCESS.getCode()).equals(payOrder.getStatus()) ||
                Integer.valueOf(PayStatusEnum.PAY_FAILED.getCode()).equals(payOrder.getStatus())) {
            return payOrder;
        }
        return payOrder;
    }


    @Override
    public PayOrderCallBackRespDTO parseOrderNotify(Map<String, String> headers, Map<String, String> params, String body) {
        Transaction transaction = wechatPlayClient.parseOrderNotifyV3(headers, body).orElseThrow(() -> new CommonException(ResultCodeEnum.WX_PREPAY_ERROR));
        PayOrderCallBackRespDTO payOrderCallBackRespDTO = new PayOrderCallBackRespDTO();
        payOrderCallBackRespDTO.setPayOrderSn(transaction.getOutTradeNo());
        payOrderCallBackRespDTO.setPayStatus(PayStatusEnum.fromWxOrderCode(transaction.getTradeState().name()));
        payOrderCallBackRespDTO.setPaySuccessTime(DateUtils.parseStringToLocalDateTime(transaction.getSuccessTime()));
        payOrderCallBackRespDTO.setTransactionId(transaction.getTransactionId());
        payOrderCallBackRespDTO.setResponse(JSONUtil.toJsonStr(transaction));
        return payOrderCallBackRespDTO;
    }

    /**
     * 关闭支付订单
     *
     * @param orderSn 订单号
     * @return 处理结果
     */
    @Override
    protected boolean doClosePayOrder(String orderSn) {
        try {
            log.info("关闭微信支付订单，订单号：{}", orderSn);
            // 查询订单
            PayOrderEntity payOrder = payOrderService.getOne(
                    new LambdaQueryWrapper<PayOrderEntity>()
                            .eq(PayOrderEntity::getOrderSn, orderSn)
                            .eq(PayOrderEntity::getChannelCode, getChannel()));
            AssertUtils.notNull(payOrder, ResultCodeEnum.ORDER_NOT_FOUND);
            // 只有待支付状态的订单才能关闭
            if (!Integer.valueOf(PayStatusEnum.PENDING.getCode()).equals(payOrder.getStatus())) {
                log.warn("订单状态不允许关闭，订单号：{}，当前状态：{}", orderSn, payOrder.getStatus());
                return false;
            }
            // 更新订单状态为已取消
            boolean updateResult = payOrderService.update(
                    new LambdaUpdateWrapper<PayOrderEntity>()
                            .set(PayOrderEntity::getStatus, PayStatusEnum.CANCEL.getCode())
                            .eq(PayOrderEntity::getId, payOrder.getId()));
            // 更新扩展表
            if (updateResult) {
                payOrderExtensionService.update(
                        new LambdaUpdateWrapper<PayOrderExtensionEntity>()
                                .eq(PayOrderExtensionEntity::getOrderId, payOrder.getId()));
            }
            // 调用微信关闭订单接口
            try {
                // 获取支付渠道配置
                boolean closeResult = wechatPlayClient.closeOrderWithConfig(orderSn);
                log.info("调用微信关闭订单接口结果：{}，订单号：{}", closeResult, orderSn);
            } catch (Exception e) {
                log.error("调用微信关闭订单接口失败，订单号：{}，错误信息：{}", orderSn, e.getMessage(), e);
            }
            log.info("关闭微信支付订单结果：{}，订单号：{}", updateResult, orderSn);
            return updateResult;
        } catch (Exception e) {
            log.error("关闭微信支付订单失败，订单号：{}", orderSn, e);
            return false;
        }
    }

    /**
     * 从 packageVal 中提取 prepayId
     * packageVal 格式为：prepay_id=wx171706502273445c8266c570ca87a40001
     */
    private String extractPrepayIdFromPackage(String packageVal) {
        if (packageVal == null || packageVal.trim().isEmpty()) {
            return null;
        }
        String prefix = "prepay_id=";
        if (packageVal.startsWith(prefix)) {
            return packageVal.substring(prefix.length());
        }
        log.warn("无法从 packageVal 中提取 prepayId：{}", packageVal);
        return null;
    }

    protected RefundSubmitRespDTO doRefundOrder(PayRefundReqDTO payRefundReqDTO) {
        String outTradeNo = payRefundReqDTO.getOutTradeNo();
        String refundReason = payRefundReqDTO.getReason();
        Long refundAmount = payRefundReqDTO.getRefundPrice();
        Long totalAmount = payRefundReqDTO.getPayPrice();
        String refundSn = payRefundReqDTO.getOutRefundNo();
        try {
            log.info("开始处理微信退款订单：{}", payRefundReqDTO);
            //调用微信客户端提交退款
            RefundSubmitRespDTO wechatResp = wechatPlayClient.submitRefund(outTradeNo, refundReason, refundAmount, totalAmount, refundSn);
            log.info("微信退款接口调用完成，订单号：{}，退款单号：{}", outTradeNo, refundSn);
            return wechatResp;
        } catch (Exception e) {
            log.error("处理微信退款订单失败，订单号：{}，退款单号：{}", outTradeNo, refundSn, e);
            throw e;
        }
    }

    /**
     * 查询退款状态
     *
     * @param refundSn 退款单号
     * @return 退款订单信息
     */
    public RefundSubmitRespDTO doQueryRefundStatus(String refundSn) {
        try {
            log.info("查询微信退款状态，退款单号：{}", refundSn);

            // 调用微信查询退款接口
            RefundSubmitRespDTO wechatResp = wechatPlayClient.queryRefund(refundSn);

            log.info("微信查询退款接口调用完成，退款单号：{}", refundSn);

            return wechatResp;
        } catch (Exception e) {
            log.error("查询微信退款状态失败，退款单号：{}", refundSn, e);
            throw e;
        }
    }

    /**
     * 处理退款回调
     *
     * @param headers 回调请求头
     * @param params  回调请求参数
     * @param body    回调请求体
     * @return RefundSubmitRespDTO
     */
    public Optional<RefundNotificationRespDTO> parseRefundNotify(Map<String, String> headers, Map<String, String> params, String body) {
        try {
            log.info("开始处理微信退款回调");
            return wechatPlayClient.parseRefundNotifyV3(headers, body);
        } catch (Exception e) {
            log.error("处理微信退款回调失败", e);
            throw e;
        }
    }
}