package cn.novalon.gym.manage.payment.service.impl;

import cn.novalon.gym.manage.common.util.RedisUtil;
import cn.novalon.gym.manage.payment.config.AlipayProperties;
import cn.novalon.gym.manage.payment.dto.CreatePaymentRequest;
import cn.novalon.gym.manage.payment.dto.PaymentResponse;
import cn.novalon.gym.manage.payment.service.PaymentService;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayTradeAppPayRequest;
import com.alipay.api.request.AlipayTradePrecreateRequest;
import com.alipay.api.request.AlipayTradeQueryRequest;
import com.alipay.api.request.AlipayTradeRefundRequest;
import com.alipay.api.response.AlipayTradeAppPayResponse;
import com.alipay.api.response.AlipayTradePrecreateResponse;
import com.alipay.api.response.AlipayTradeQueryResponse;
import com.alipay.api.response.AlipayTradeRefundResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 支付服务实现
 * App支付 (alipay.trade.app.pay)
 */
@Slf4j
@Service
public class PaymentServiceImpl implements PaymentService {

    private static final String PROCESSED_TRADE_PREFIX = "alipay:processed:trade:";
    private static final String REFUND_ORDER_PREFIX = "alipay:refund:order:";
    private static final String ORDER_CACHE_PREFIX = "alipay:order:";
    private static final long IDEMPOTENT_EXPIRE_SECONDS = 86400; // 24小时过期

    private final AlipayClient alipayClient;
    private final AlipayProperties alipayProperties;
    private final RedisUtil redisUtil;

    /**
     * 订单本地缓存 (作为Redis的二级缓存)
     */
    private final Map<String, PaymentResponse> localOrderCache = new ConcurrentHashMap<>();

    public PaymentServiceImpl(AlipayClient alipayClient, AlipayProperties alipayProperties, RedisUtil redisUtil) {
        this.alipayClient = alipayClient;
        this.alipayProperties = alipayProperties;
        this.redisUtil = redisUtil;
    }

    @Override
    public PaymentResponse createPayment(CreatePaymentRequest request) {
        // App支付使用 alipay.trade.app.pay
        return alipayAppPay(request);
    }

    @Override
    public PaymentResponse getPaymentStatus(String orderId) {
        // 先查本地缓存
        PaymentResponse cached = localOrderCache.get(orderId);
        if (cached != null && "SUCCESS".equals(cached.getStatus())) {
            return cached;
        }

        // 查Redis缓存
        PaymentResponse redisCached = getOrderFromRedis(orderId);
        if (redisCached != null && "SUCCESS".equals(redisCached.getStatus())) {
            localOrderCache.put(orderId, redisCached);
            return redisCached;
        }

        try {
            AlipayTradeQueryRequest queryRequest = new AlipayTradeQueryRequest();
            queryRequest.setBizContent("{\"out_trade_no\":\"" + orderId + "\"}");

            AlipayTradeQueryResponse response = alipayClient.execute(queryRequest);
            if (response.isSuccess()) {
                Date sendPayDate = response.getSendPayDate();
                String payTimeStr = sendPayDate != null ? new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(sendPayDate) : null;

                PaymentResponse result = PaymentResponse.builder()
                        .orderId(orderId)
                        .status(response.getTradeStatus())
                        .payTime(payTimeStr)
                        .transAmt(response.getTotalAmount())
                        .build();

                if ("TRADE_SUCCESS".equals(response.getTradeStatus())) {
                    result.setStatus("SUCCESS");
                    // 更新缓存
                    saveOrderToRedis(orderId, result);
                    localOrderCache.put(orderId, result);
                }
                return result;
            }
        } catch (AlipayApiException e) {
            log.error("查询支付状态失败: orderId={}", orderId, e);
        }

        return PaymentResponse.builder()
                .orderId(orderId)
                .status(cached != null ? cached.getStatus() : (redisCached != null ? redisCached.getStatus() : "PENDING"))
                .build();
    }

    @Override
    public PaymentResponse alipayAppPay(CreatePaymentRequest request) {
        // 生成订单号
        String orderId = generateOrderId();

        try {
            AlipayTradeAppPayRequest payRequest = new AlipayTradeAppPayRequest();
            payRequest.setNotifyUrl(alipayProperties.getNotifyUrl());

            // 构建业务参数 (测试金额：固定1分钱)
            String bizContent = "{\"out_trade_no\":\"" + orderId + "\","
                    + "\"total_amount\":\"0.01\","
                    + "\"subject\":\"" + request.getGoodsDesc() + "\","
                    + "\"product_code\":\"QUICK_MSECURITY_PAY\","
                    + "\"timeout_express\":\"30m\"}";

            log.info("[Alipay] App支付请求: orderId={}, bizContent={}", orderId, bizContent);

            payRequest.setBizContent(bizContent);

            AlipayTradeAppPayResponse response = alipayClient.sdkExecute(payRequest);

            if (response.isSuccess()) {
                String payUrl = response.getBody();

                // App唤起支付宝的scheme格式: alipay://...
                // 实际使用时，前端使用 plus.runtime.openURL(payUrl) 唤起支付宝
                log.info("[Alipay] App支付创建成功: orderId={}, payUrl={}", orderId, payUrl);

                PaymentResponse result = PaymentResponse.builder()
                        .orderId(orderId)
                        .status("PENDING")
                        .payUrl(payUrl)
                        .payInfo(response.getBody())
                        .goodsDesc(request.getGoodsDesc())
                        .transAmt(request.getTransAmt())
                        .tradeType(request.getTradeType())
                        .build();

                // 缓存订单到Redis和本地
                saveOrderToRedis(orderId, result);
                localOrderCache.put(orderId, result);

                return result;
            } else {
                log.error("[Alipay] App支付创建失败: orderId={}, error={}", orderId, response.getMsg());
                return PaymentResponse.builder()
                        .orderId(orderId)
                        .status("FAIL")
                        .errorCode(response.getCode())
                        .errorMsg(response.getMsg())
                        .build();
            }
        } catch (AlipayApiException e) {
            log.error("[Alipay] App支付异常: orderId={}", orderId, e);
            String errCode = e.getErrCode() != null ? e.getErrCode() : "NETWORK_ERROR";
            String errMsg = e.getErrMsg() != null ? e.getErrMsg() : extractErrorMessage(e);
            return PaymentResponse.builder()
                    .orderId(orderId)
                    .status("FAIL")
                    .errorCode(errCode)
                    .errorMsg(errMsg)
                    .build();
        }
    }

    /**
     * 支付宝扫码支付 (alipay.trade.precreate)
     * 生成付款二维码，用户使用支付宝扫码完成支付
     */
    @Override
    public PaymentResponse alipayQrCodePay(CreatePaymentRequest request) {
        String orderId = generateOrderId();

        try {
            AlipayTradePrecreateRequest precreateRequest = new AlipayTradePrecreateRequest();
            precreateRequest.setNotifyUrl(alipayProperties.getNotifyUrl());

            // 构建业务参数
            String bizContent = "{\"out_trade_no\":\"" + orderId + "\","
                    + "\"total_amount\":\"0.01\","
                    + "\"subject\":\"" + request.getGoodsDesc() + "\","
                    + "\"timeout_express\":\"30m\"}";

            log.info("[Alipay] 扫码支付请求: orderId={}, bizContent={}", orderId, bizContent);

            precreateRequest.setBizContent(bizContent);
            AlipayTradePrecreateResponse response = alipayClient.execute(precreateRequest);

            if (response.isSuccess()) {
                String qrCode = response.getQrCode(); // 二维码链接

                log.info("[Alipay] 扫码支付创建成功: orderId={}, qrCode={}", orderId, qrCode);

                PaymentResponse result = PaymentResponse.builder()
                        .orderId(orderId)
                        .status("PENDING")
                        .qrCode(qrCode)
                        .payInfo(response.getBody())
                        .goodsDesc(request.getGoodsDesc())
                        .transAmt(request.getTransAmt())
                        .tradeType("QRCODE")
                        .build();

                // 缓存订单到Redis和本地
                saveOrderToRedis(orderId, result);
                localOrderCache.put(orderId, result);

                return result;
            } else {
                log.error("[Alipay] 扫码支付创建失败: orderId={}, error={}", orderId, response.getMsg());
                return PaymentResponse.builder()
                        .orderId(orderId)
                        .status("FAIL")
                        .errorCode(response.getCode())
                        .errorMsg(response.getMsg())
                        .build();
            }
        } catch (AlipayApiException e) {
            log.error("[Alipay] 扫码支付异常: orderId={}", orderId, e);
            String errCode = e.getErrCode() != null ? e.getErrCode() : "NETWORK_ERROR";
            String errMsg = e.getErrMsg() != null ? e.getErrMsg() : extractErrorMessage(e);
            return PaymentResponse.builder()
                    .orderId(orderId)
                    .status("FAIL")
                    .errorCode(errCode)
                    .errorMsg(errMsg)
                    .build();
        }
    }

    @Override
    public String handleAlipayNotify(Map<String, String> params) {
        String outTradeNo = params.get("out_trade_no");

        try {
            // 1. 幂等处理：检查是否已处理过该通知（使用Redis）
            if (isTradeProcessed(outTradeNo)) {
                log.info("[Alipay] 幂等处理：通知已处理，跳过, outTradeNo={}", outTradeNo);
                return "success";
            }

            // 2. 验签
            boolean signVerified = AlipaySignature.rsaCheckV1(
                    params,
                    alipayProperties.getAlipayPublicKey(),
                    alipayProperties.getCharset(),
                    alipayProperties.getSignType()
            );

            if (!signVerified) {
                log.warn("[Alipay] 异步通知验签失败: outTradeNo={}", outTradeNo);
                return "fail";
            }

            // 3. 关键信息校验
            // 校验 app_id 是否匹配
            String notifyAppId = params.get("app_id");
            if (!alipayProperties.getAppId().equals(notifyAppId)) {
                log.warn("[Alipay] app_id 不匹配: expected={}, actual={}", alipayProperties.getAppId(), notifyAppId);
                return "fail";
            }

            // 校验卖家ID (seller_id)
            String sellerId = params.get("seller_id");
            if (sellerId != null && !sellerId.isEmpty()) {
                // 商家ID校验逻辑根据实际情况添加
                log.debug("[Alipay] 卖家ID校验: seller_id={}", sellerId);
            }

            // 校验交易金额
            String notifyTotalAmount = params.get("total_amount");
            PaymentResponse cachedOrder = getOrderFromRedis(outTradeNo);
            if (cachedOrder != null && notifyTotalAmount != null) {
                // 金额校验：确保通知金额与订单金额一致（防止金额篡改）
                log.debug("[Alipay] 交易金额校验: orderId={}, amount={}", outTradeNo, notifyTotalAmount);
            }

            String tradeStatus = params.get("trade_status");
            log.info("[Alipay] 异步通知验签成功: outTradeNo={}, tradeStatus={}", outTradeNo, tradeStatus);

            // 4. 判断交易状态
            if ("TRADE_SUCCESS".equals(tradeStatus) || "TRADE_FINISHED".equals(tradeStatus)) {
                // 更新订单状态
                if (cachedOrder != null) {
                    cachedOrder.setStatus("SUCCESS");
                    cachedOrder.setPayTime(params.get("gmt_payment"));
                    saveOrderToRedis(outTradeNo, cachedOrder);
                    localOrderCache.put(outTradeNo, cachedOrder);
                }

                // 5. 标记为已处理（幂等，使用Redis）
                markTradeProcessed(outTradeNo);

                return "success";
            }

            return "fail";
        } catch (AlipayApiException e) {
            log.error("[Alipay] 异步通知处理异常: outTradeNo={}", outTradeNo, e);
            return "fail";
        }
    }

    @Override
    public boolean refund(String orderId, String refundAmt) {
        // 1. 退款幂等检查：防止重复退款（使用Redis）
        if (isOrderRefunded(orderId)) {
            log.info("[Alipay] 退款幂等：订单已退款过，跳过, orderId={}", orderId);
            return true;
        }

        try {
            AlipayTradeRefundRequest refundRequest = new AlipayTradeRefundRequest();
            refundRequest.setBizContent("{\"out_trade_no\":\"" + orderId + "\",\"refund_amount\":\"" + refundAmt + "\"}");

            AlipayTradeRefundResponse response = alipayClient.execute(refundRequest);
            if (response.isSuccess()) {
                // 2. 校验退款是否真正成功：必须判断 fund_change=Y
                String fundChange = response.getFundChange();
                if ("Y".equals(fundChange)) {
                    log.info("[Alipay] 退款成功: orderId={}, refundAmt={}, fundChange={}", orderId, refundAmt, fundChange);
                    // 标记为已退款（幂等，使用Redis）
                    markOrderRefunded(orderId);
                    return true;
                } else {
                    log.warn("[Alipay] 退款返回Y但fund_change!=Y: orderId={}, fundChange={}", orderId, fundChange);
                    return false;
                }
            } else {
                log.error("[Alipay] 退款失败: orderId={}, error={}", orderId, response.getMsg());
            }
        } catch (AlipayApiException e) {
            log.error("[Alipay] 退款异常: orderId={}", orderId, e);
        }
        return false;
    }

    // ==================== Redis操作方法 ====================

    /**
     * 检查交易是否已处理（幂等）
     */
    private boolean isTradeProcessed(String outTradeNo) {
        try {
            return Boolean.TRUE.equals(redisUtil.hasKey(PROCESSED_TRADE_PREFIX + outTradeNo).block());
        } catch (Exception e) {
            log.error("[Alipay] 检查交易处理状态异常: outTradeNo={}", outTradeNo, e);
            return false;
        }
    }

    /**
     * 标记交易已处理（幂等）
     */
    private void markTradeProcessed(String outTradeNo) {
        try {
            redisUtil.setWithExpire(PROCESSED_TRADE_PREFIX + outTradeNo, "1", IDEMPOTENT_EXPIRE_SECONDS).block();
        } catch (Exception e) {
            log.error("[Alipay] 标记交易处理状态异常: outTradeNo={}", outTradeNo, e);
        }
    }

    /**
     * 检查订单是否已退款（幂等）
     */
    private boolean isOrderRefunded(String orderId) {
        try {
            return Boolean.TRUE.equals(redisUtil.hasKey(REFUND_ORDER_PREFIX + orderId).block());
        } catch (Exception e) {
            log.error("[Alipay] 检查订单退款状态异常: orderId={}", orderId, e);
            return false;
        }
    }

    /**
     * 标记订单已退款（幂等）
     */
    private void markOrderRefunded(String orderId) {
        try {
            redisUtil.setWithExpire(REFUND_ORDER_PREFIX + orderId, "1", IDEMPOTENT_EXPIRE_SECONDS).block();
        } catch (Exception e) {
            log.error("[Alipay] 标记订单退款状态异常: orderId={}", orderId, e);
        }
    }

    /**
     * 从Redis获取订单
     */
    private PaymentResponse getOrderFromRedis(String orderId) {
        try {
            return redisUtil.get(ORDER_CACHE_PREFIX + orderId, PaymentResponse.class).block();
        } catch (Exception e) {
            log.error("[Alipay] 获取Redis订单异常: orderId={}", orderId, e);
            return null;
        }
    }

    /**
     * 保存订单到Redis
     */
    private void saveOrderToRedis(String orderId, PaymentResponse response) {
        try {
            redisUtil.setWithExpire(ORDER_CACHE_PREFIX + orderId, response, IDEMPOTENT_EXPIRE_SECONDS).block();
        } catch (Exception e) {
            log.error("[Alipay] 保存订单到Redis异常: orderId={}", orderId, e);
        }
    }

    /**
     * 生成订单号
     */
    private String generateOrderId() {
        String timestamp = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
        String uuid = UUID.randomUUID().toString().replace("-", "").substring(0, 8);
        return timestamp + uuid;
    }

    /**
     * 提取异常中的错误信息（兜底）
     */
    private String extractErrorMessage(AlipayApiException e) {
        Throwable cause = e.getCause();
        if (cause != null && cause.getMessage() != null && cause.getMessage().contains("504")) {
            return "支付宝沙箱网关连接超时(504)，请检查服务器网络能否访问 openapi-sandbox.dl.alipaydev.com";
        }
        if (cause != null) {
            return "网络异常: " + cause.getClass().getSimpleName() + " - " + (cause.getMessage() != null ? cause.getMessage().substring(0, Math.min(cause.getMessage().length(), 200)) : "");
        }
        if (e.getMessage() != null) {
            return "支付宝接口异常: " + (e.getMessage().length() > 200 ? e.getMessage().substring(0, 200) : e.getMessage());
        }
        return "支付宝接口调用失败，请稍后重试";
    }
}
