package com.haha.service.payment.impl;

import com.haha.common.constant.PaymentConstants;
import com.haha.common.enums.PaymentChannel;
import com.haha.service.payment.*;
import com.haha.service.payment.config.WxPayConfig;
import com.wechat.pay.java.core.exception.HttpException;
import com.wechat.pay.java.core.exception.MalformedMessageException;
import com.wechat.pay.java.core.exception.ServiceException;
import com.wechat.pay.java.core.exception.ValidationException;
import com.wechat.pay.java.core.notification.NotificationParser;
import com.wechat.pay.java.core.notification.RequestParam;
import com.wechat.pay.java.service.payments.jsapi.JsapiServiceExtension;
import com.wechat.pay.java.service.payments.jsapi.model.Amount;
import com.wechat.pay.java.service.payments.jsapi.model.Payer;
import com.wechat.pay.java.service.payments.jsapi.model.PrepayRequest;
import com.wechat.pay.java.service.payments.jsapi.model.PrepayWithRequestPaymentResponse;
import com.wechat.pay.java.service.payments.jsapi.model.QueryOrderByOutTradeNoRequest;
import com.wechat.pay.java.service.payments.model.Transaction;
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 lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Map;

/**
 * 微信支付策略实现
 * 使用微信支付 V3 官方 SDK (wechatpay-java)
 */
@Slf4j
@Component
public class WxPayStrategy implements PaymentStrategy {

    @Autowired(required = false)
    private JsapiServiceExtension jsapiServiceExtension;

    @Autowired(required = false)
    private RefundService wxRefundService;

    @Autowired(required = false)
    private NotificationParser wxNotificationParser;

    @Autowired(required = false)
    private WxPayConfig wxPayConfig;

    @Override
    public PaymentChannel getChannel() {
        return PaymentChannel.WECHAT;
    }

    @Override
    public PaymentResult createPayment(PaymentRequest request) {
        log.info("[微信支付] 创建支付订单 - 订单号: {}, 金额: {}, 用户ID: {}, openId: {}",
                request.getOrderNo(), request.getAmount(), request.getUserId(), request.getOpenId());

        // 1. 检查服务可用性
        if (jsapiServiceExtension == null) {
            log.error("[微信支付] JSAPI 服务未初始化，请检查微信支付配置");
            return PaymentResult.builder()
                    .success(false)
                    .channel(PaymentChannel.WECHAT)
                    .errorCode("SERVICE_UNAVAILABLE")
                    .errorMsg("微信支付服务未初始化，请检查配置")
                    .build();
        }

        if (wxPayConfig == null) {
            log.error("[微信支付] 支付配置未初始化");
            return error("CONFIG_UNAVAILABLE", "微信支付配置未初始化");
        }

        // 2. 参数校验
        if (request.getOpenId() == null || request.getOpenId().isEmpty()) {
            log.error("[微信支付] 创建支付失败 - openId为空");
            return error("PARAM_ERROR", "微信支付必须提供openId");
        }

        // 3. 构建下单请求
        PrepayRequest prepayRequest = new PrepayRequest();
        prepayRequest.setAppid(wxPayConfig.getAppId());
        prepayRequest.setMchid(wxPayConfig.getMchId());
        prepayRequest.setDescription(request.getDescription() != null ? request.getDescription() : "哈哈零售-订单支付");
        prepayRequest.setOutTradeNo(request.getOrderNo());
        prepayRequest.setNotifyUrl(request.getNotifyUrl() != null ? request.getNotifyUrl() : wxPayConfig.getNotifyUrl());

        // 设置金额（元转分）
        Amount amount = new Amount();
        amount.setTotal(request.getAmount().multiply(PaymentConstants.YUAN_TO_FEN).intValue());
        amount.setCurrency("CNY");
        prepayRequest.setAmount(amount);

        // 设置支付者
        Payer payer = new Payer();
        payer.setOpenid(request.getOpenId());
        prepayRequest.setPayer(payer);

        log.info("[微信支付] 统一下单参数: appId={}, mchId={}, outTradeNo={}, totalFee={}分, openId={}, notifyUrl={}",
                wxPayConfig.getAppId(), wxPayConfig.getMchId(), request.getOrderNo(),
                amount.getTotal(), request.getOpenId(), prepayRequest.getNotifyUrl());

        // 4. 调用 SDK（一步完成下单+生成支付参数）
        try {
            PrepayWithRequestPaymentResponse response = jsapiServiceExtension.prepayWithRequestPayment(prepayRequest);

            // 5. 封装返回结果
            Map<String, String> payParams = new HashMap<>();
            payParams.put("appId", response.getAppId());
            payParams.put("timeStamp", response.getTimeStamp());
            payParams.put("nonceStr", response.getNonceStr());
            payParams.put("package", response.getPackageVal());
            payParams.put("signType", response.getSignType());
            payParams.put("paySign", response.getPaySign());

            String prepayId = extractPrepayId(response.getPackageVal());
            log.info("[微信支付] 统一下单成功 - prepayId: {}, timeStamp: {}", prepayId, response.getTimeStamp());

            return PaymentResult.builder()
                    .success(true)
                    .channel(PaymentChannel.WECHAT)
                    .prepayId(prepayId)
                    .payParams(payParams)
                    .build();

        } catch (HttpException e) {
            log.error("[微信支付] 统一下单HTTP异常: {}", e.getMessage(), e);
            return error("NETWORK_ERROR", "网络请求异常: " + e.getMessage());
        } catch (ServiceException e) {
            log.error("[微信支付] 统一下单业务异常: code={}, msg={}", e.getErrorCode(), e.getErrorMessage(), e);
            return error(e.getErrorCode(), e.getErrorMessage());
        } catch (MalformedMessageException e) {
            log.error("[微信支付] 统一下单消息解析异常: {}", e.getMessage(), e);
            return error("MESSAGE_ERROR", "消息解析异常: " + e.getMessage());
        } catch (Exception e) {
            log.error("[微信支付] 统一下单未知异常", e);
            return error("UNKNOWN_ERROR", "下单失败: " + e.getMessage());
        }
    }

    @Override
    public RefundResult refund(RefundRequest request) {
        log.info("[微信支付] 申请退款 - 订单号: {}, 交易号: {}, 退款单号: {}, 退款金额: {}, 订单总金额: {}, 退款原因: {}",
                request.getOrderNo(), request.getTransactionId(), request.getRefundNo(),
                request.getRefundAmount(), request.getTotalAmount(), request.getReason());

        // 检查服务可用性
        if (wxRefundService == null) {
            log.error("[微信支付] 退款服务未初始化，请检查微信支付配置");
            return RefundResult.builder()
                    .success(false)
                    .errorCode("SERVICE_UNAVAILABLE")
                    .errorMsg("退款服务未初始化，请检查配置")
                    .build();
        }

        try {
            CreateRequest createRequest = new CreateRequest();

            // 设置原交易信息（优先使用 transactionId）
            if (request.getTransactionId() != null && !request.getTransactionId().isEmpty()) {
                createRequest.setTransactionId(request.getTransactionId());
            } else {
                createRequest.setOutTradeNo(request.getOrderNo());
            }

            // 设置退款单号
            createRequest.setOutRefundNo(request.getRefundNo());
            
            // 设置退款原因
            if (request.getReason() != null && !request.getReason().isEmpty()) {
                createRequest.setReason(request.getReason());
            }

            // 设置退款金额
            AmountReq amountReq = new AmountReq();
            amountReq.setRefund(request.getRefundAmount().multiply(PaymentConstants.YUAN_TO_FEN).longValue());
            amountReq.setTotal(request.getTotalAmount().multiply(PaymentConstants.YUAN_TO_FEN).longValue());
            amountReq.setCurrency("CNY");
            createRequest.setAmount(amountReq);

            log.info("[微信支付] 退款参数: transactionId={}, outTradeNo={}, outRefundNo={}, refundFee={}分, totalFee={}分",
                    createRequest.getTransactionId(), createRequest.getOutTradeNo(),
                    createRequest.getOutRefundNo(), amountReq.getRefund(), amountReq.getTotal());

            Refund refund = wxRefundService.create(createRequest);

            log.info("[微信支付] 退款申请成功 - refundId: {}, status: {}", refund.getRefundId(), refund.getStatus());

            return RefundResult.builder()
                    .success(true)
                    .refundId(refund.getRefundId())
                    .build();

        } catch (ServiceException e) {
            log.error("[微信支付] 退款业务异常: code={}, msg={}", e.getErrorCode(), e.getErrorMessage(), e);
            return RefundResult.builder()
                    .success(false)
                    .errorCode(e.getErrorCode())
                    .errorMsg(e.getErrorMessage())
                    .build();
        } catch (HttpException e) {
            log.error("[微信支付] 退款HTTP异常: {}", e.getMessage(), e);
            return RefundResult.builder()
                    .success(false)
                    .errorCode("NETWORK_ERROR")
                    .errorMsg("网络请求异常: " + e.getMessage())
                    .build();
        } catch (Exception e) {
            log.error("[微信支付] 退款未知异常", e);
            return RefundResult.builder()
                    .success(false)
                    .errorCode("UNKNOWN_ERROR")
                    .errorMsg("退款失败: " + e.getMessage())
                    .build();
        }
    }

    @Override
    public boolean verifyCallback(Map<String, Object> params) {
        // 微信 V3 SDK 的 NotificationParser.parse() 在解析时自动完成签名验证
        // 验签逻辑已内置于 parseCallback 中，此处返回 true 允许进入解析流程
        // 如果签名验证失败，parseCallback 中 SDK 会抛出 ValidationException
        log.debug("[微信支付] V3 签名验证由 SDK NotificationParser 在 parseCallback 中自动完成");
        return true;
    }

    @Override
    public PaymentCallbackResult parseCallback(Map<String, Object> params) {
        log.info("[微信支付] 解析回调通知 - 参数Keys: {}", params.keySet());

        // 检查服务可用性
        if (wxNotificationParser == null) {
            log.error("[微信支付] 回调解析服务未初始化，请检查微信支付配置");
            return PaymentCallbackResult.builder()
                    .success(false)
                    .channel(PaymentChannel.WECHAT)
                    .errorMsg("回调解析服务未初始化，请检查配置")
                    .build();
        }

        try {
            // 从 params 中提取微信 V3 回调所需的信息
            String timestamp = (String) params.get("Wechatpay-Timestamp");
            String nonce = (String) params.get("Wechatpay-Nonce");
            String signature = (String) params.get("Wechatpay-Signature");
            String serial = (String) params.get("Wechatpay-Serial");
            String signType = (String) params.getOrDefault("Wechatpay-Signature-Type", "WECHATPAY2-SHA256-RSA2048");
            String body = (String) params.get("body");

            log.debug("[微信支付] 回调请求头: timestamp={}, nonce={}, serial={}, signType={}",
                    timestamp, nonce, serial, signType);

            // 构建 RequestParam
            RequestParam requestParam = new RequestParam.Builder()
                    .serialNumber(serial)
                    .nonce(nonce)
                    .timestamp(timestamp)
                    .signature(signature)
                    .signType(signType)
                    .body(body)
                    .build();

            // SDK 自动完成签名验证 + AES-256-GCM 解密
            Transaction transaction = wxNotificationParser.parse(requestParam, Transaction.class);

            log.info("[微信支付] 回调解析成功 - outTradeNo: {}, transactionId: {}, tradeState: {}",
                    transaction.getOutTradeNo(), transaction.getTransactionId(), transaction.getTradeState());

            // 转换支付时间
            LocalDateTime payTime = null;
            if (transaction.getSuccessTime() != null) {
                // 微信返回的时间格式: 2018-06-08T10:34:56+08:00 (ISO 8601)
                try {
                    OffsetDateTime offsetDateTime = OffsetDateTime.parse(transaction.getSuccessTime(), DateTimeFormatter.ISO_OFFSET_DATE_TIME);
                    payTime = offsetDateTime.toLocalDateTime();
                } catch (Exception e) {
                    log.warn("[微信支付] 支付时间解析失败: {}, 使用当前时间", transaction.getSuccessTime());
                    payTime = LocalDateTime.now();
                }
            }

            // 转换金额（分转元）
            BigDecimal amount = BigDecimal.ZERO;
            if (transaction.getAmount() != null && transaction.getAmount().getTotal() != null) {
                amount = BigDecimal.valueOf(transaction.getAmount().getTotal())
                        .divide(PaymentConstants.YUAN_TO_FEN, 2, RoundingMode.HALF_UP);
            }

            // 判断交易状态
            boolean isSuccess = Transaction.TradeStateEnum.SUCCESS.equals(transaction.getTradeState());

            log.info("[微信支付] 回调处理完成 - 订单号: {}, 交易号: {}, 金额: {}, 支付时间: {}, 成功: {}",
                    transaction.getOutTradeNo(), transaction.getTransactionId(), amount, payTime, isSuccess);

            return PaymentCallbackResult.builder()
                    .success(isSuccess)
                    .orderNo(transaction.getOutTradeNo())
                    .transactionId(transaction.getTransactionId())
                    .amount(amount)
                    .payTime(payTime)
                    .channel(PaymentChannel.WECHAT)
                    .rawData(params)
                    .build();

        } catch (ValidationException e) {
            log.error("[微信支付] 回调签名验证失败: {}", e.getMessage(), e);
            return PaymentCallbackResult.builder()
                    .success(false)
                    .channel(PaymentChannel.WECHAT)
                    .rawData(params)
                    .errorMsg("签名验证失败: " + e.getMessage())
                    .build();
        } catch (MalformedMessageException e) {
            log.error("[微信支付] 回调消息解析失败: {}", e.getMessage(), e);
            return PaymentCallbackResult.builder()
                    .success(false)
                    .channel(PaymentChannel.WECHAT)
                    .rawData(params)
                    .errorMsg("消息解析失败: " + e.getMessage())
                    .build();
        } catch (Exception e) {
            log.error("[微信支付] 回调处理未知异常", e);
            return PaymentCallbackResult.builder()
                    .success(false)
                    .channel(PaymentChannel.WECHAT)
                    .rawData(params)
                    .errorMsg("回调处理失败: " + e.getMessage())
                    .build();
        }
    }

    @Override
    public PaymentResult queryPayment(String outTradeNo) {
        log.info("[微信支付] 查询订单状态 - 订单号: {}", outTradeNo);

        // 检查服务可用性
        if (jsapiServiceExtension == null) {
            log.error("[微信支付] JSAPI 服务未初始化，请检查微信支付配置");
            return PaymentResult.builder()
                    .success(false)
                    .channel(PaymentChannel.WECHAT)
                    .errorCode("SERVICE_UNAVAILABLE")
                    .errorMsg("支付查询服务未初始化，请检查配置")
                    .build();
        }

        if (wxPayConfig == null) {
            return error("CONFIG_UNAVAILABLE", "微信支付配置未初始化");
        }

        try {
            QueryOrderByOutTradeNoRequest request = new QueryOrderByOutTradeNoRequest();
            request.setMchid(wxPayConfig.getMchId());
            request.setOutTradeNo(outTradeNo);

            Transaction transaction = jsapiServiceExtension.queryOrderByOutTradeNo(request);

            boolean isSuccess = Transaction.TradeStateEnum.SUCCESS.equals(transaction.getTradeState());

            Map<String, String> payParams = new HashMap<>();
            payParams.put("tradeState", transaction.getTradeState().name());
            if (transaction.getTradeStateDesc() != null) {
                payParams.put("tradeStateDesc", transaction.getTradeStateDesc());
            }
            if (transaction.getTransactionId() != null) {
                payParams.put("transactionId", transaction.getTransactionId());
            }

            log.info("[微信支付] 订单查询完成 - outTradeNo: {}, tradeState: {}, transactionId: {}",
                    outTradeNo, transaction.getTradeState(), transaction.getTransactionId());

            return PaymentResult.builder()
                    .success(isSuccess)
                    .channel(PaymentChannel.WECHAT)
                    .payParams(payParams)
                    .build();

        } catch (ServiceException e) {
            log.error("[微信支付] 订单查询业务异常: code={}, msg={}", e.getErrorCode(), e.getErrorMessage(), e);
            return error(e.getErrorCode(), e.getErrorMessage());
        } catch (HttpException e) {
            log.error("[微信支付] 订单查询HTTP异常: {}", e.getMessage(), e);
            return error("NETWORK_ERROR", "网络请求异常: " + e.getMessage());
        } catch (Exception e) {
            log.error("[微信支付] 订单查询未知异常", e);
            return error("UNKNOWN_ERROR", "查询失败: " + e.getMessage());
        }
    }

    // ==================== 私有辅助方法 ====================

    /**
     * 从 packageVal 中提取 prepayId
     * packageVal 格式: "prepay_id=xxx"
     */
    private String extractPrepayId(String packageVal) {
        if (packageVal != null && packageVal.startsWith("prepay_id=")) {
            return packageVal.substring("prepay_id=".length());
        }
        return packageVal;
    }

    /**
     * 构建错误的支付结果
     */
    private PaymentResult error(String code, String msg) {
        return PaymentResult.builder()
                .success(false)
                .channel(PaymentChannel.WECHAT)
                .errorCode(code)
                .errorMsg(msg)
                .build();
    }

    /**
     * 构建错误的支付结果（使用默认错误码）
     */
    private PaymentResult error(String msg) {
        return error("ERROR", msg);
    }
}
