package com.example.demo.controller;

import java.io.BufferedReader;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.alipay.api.internal.util.AlipaySignature;
import com.example.demo.model.Payment;
import com.example.demo.model.PaymentStatus;
import com.example.demo.repository.PaymentRepository;

import jakarta.servlet.http.HttpServletRequest;

/**
 * 支付宝回调接口控制器
 * 参考 IJPay 实现，处理支付宝异步通知和同步返回
 * 
 * @author Generated
 */
@RestController
@RequestMapping("/api/payments/alipay")
public class AlipayCallbackController {

    private static final Logger logger = LoggerFactory.getLogger(AlipayCallbackController.class);

    @Autowired
    private PaymentRepository paymentRepository;

    @Autowired
    private com.example.demo.config.PaymentConfig.AliPayConfig aliPayConfig;
    
    @Autowired
    private com.example.demo.service.PaymentService paymentService;

    /**
     * 支付宝异步通知接口
     * 支付宝服务器会通过POST方式调用此接口，通知支付结果
     * 
     * 参考 IJPay 实现：
     * - 使用 AlipaySignature.rsaCheckV1() 验证签名
     * - 处理重复通知（去重）
     * - 更新订单状态
     * - 返回 "success" 或 "failure"
     * 
     * @param request HTTP请求对象
     * @return "success" 表示处理成功，"failure" 表示处理失败
     */
    @PostMapping(value = "/notify", produces = MediaType.TEXT_PLAIN_VALUE)
    public String notifyUrl(HttpServletRequest request) {
        logger.info("========== 收到支付宝异步通知 ==========");
        logger.info("请求方法: {}", request.getMethod());
        logger.info("请求URL: {}", request.getRequestURL());
        logger.info("Content-Type: {}", request.getContentType());
        
        try {
            // 获取支付宝POST过来的反馈信息
            Map<String, String> params = getRequestParams(request);
            
            // 打印所有参数（用于调试）
            logger.info("支付宝异步通知参数:");
            for (Map.Entry<String, String> entry : params.entrySet()) {
                logger.info("  {} = {}", entry.getKey(), entry.getValue());
            }
            
            // 验证签名
            boolean verifyResult = AlipaySignature.rsaCheckV1(
                params, 
                aliPayConfig.getPublicKey(), 
                aliPayConfig.getCharset() != null ? aliPayConfig.getCharset() : "UTF-8", 
                aliPayConfig.getSignType() != null ? aliPayConfig.getSignType() : "RSA2"
            );
            
            if (!verifyResult) {
                logger.error("========== 支付宝异步通知签名验证失败 ==========");
                return "failure";
            }
            
            logger.info("========== 支付宝异步通知签名验证成功 ==========");
            
            // 获取关键参数
            String tradeStatus = params.get("trade_status");
            String outTradeNo = params.get("out_trade_no");
            String tradeNo = params.get("trade_no");
            String totalAmount = params.get("total_amount");
            String appId = params.get("app_id");
            
            logger.info("订单号: {}, 交易号: {}, 交易状态: {}, 金额: {}, 应用ID: {}", 
                outTradeNo, tradeNo, tradeStatus, totalAmount, appId);
            
            // 查找支付记录
            logger.info("正在查找支付记录，订单号: {}", outTradeNo);
            Optional<Payment> paymentOpt = paymentRepository.findByOrderId(outTradeNo);
            if (!paymentOpt.isPresent()) {
                logger.error("❌ 支付记录不存在: orderId={}", outTradeNo);
                logger.error("请检查数据库中是否存在该订单号的支付记录");
                return "failure";
            }
            logger.info("✅ 找到支付记录: paymentId={}", paymentOpt.get().getId());
            
            Payment payment = paymentOpt.get();
            
            // 处理重复通知（去重）
            // 如果订单已经是成功状态，且本次通知也是成功，则认为是重复通知
            if (payment.getStatus() == PaymentStatus.SUCCESS && 
                ("TRADE_SUCCESS".equals(tradeStatus) || "TRADE_FINISHED".equals(tradeStatus))) {
                logger.info("收到重复的成功通知，订单号: {}, 已处理过，直接返回success", outTradeNo);
                return "success";
            }
            
            // 根据交易状态更新支付记录
            boolean shouldUpdateOrder = false;
            switch (tradeStatus) {
                case "TRADE_SUCCESS":
                case "TRADE_FINISHED":
                    // 交易成功
                    if (payment.getStatus() != PaymentStatus.SUCCESS) {
                        payment.setStatus(PaymentStatus.SUCCESS);
                        payment.setExternalTransactionId(tradeNo);
                        payment.setPaidAt(LocalDateTime.now());
                        shouldUpdateOrder = true;
                        logger.info("订单支付成功: {}", outTradeNo);
                    }
                    break;
                    
                case "TRADE_CLOSED":
                    // 交易关闭（未付款交易超时关闭，或支付完成后全额退款）
                    if (payment.getStatus() != PaymentStatus.CANCELLED) {
                        payment.setStatus(PaymentStatus.CANCELLED);
                        shouldUpdateOrder = true;
                        logger.info("订单已关闭: {}", outTradeNo);
                    }
                    break;
                    
                case "WAIT_BUYER_PAY":
                    // 交易创建，等待买家付款
                    if (payment.getStatus() != PaymentStatus.PROCESSING) {
                        payment.setStatus(PaymentStatus.PROCESSING);
                        shouldUpdateOrder = true;
                        logger.info("订单等待付款: {}", outTradeNo);
                    }
                    break;
                    
                default:
                    logger.warn("未知的交易状态: {}, 订单号: {}", tradeStatus, outTradeNo);
                    break;
            }
            
            // 保存支付记录并处理业务逻辑
            if (shouldUpdateOrder) {
                // 如果是支付成功，调用统一的支付确认方法（会自动创建订单、增加积分等）
                if (payment.getStatus() == PaymentStatus.SUCCESS) {
                    try {
                        // 使用PaymentService的确认支付成功方法，确保和PayPal一样的处理逻辑
                        paymentService.confirmPaymentSuccess(payment.getId(), tradeNo);
                        logger.info("✅ 支付确认成功，已创建订单并增加积分: 订单号={}", outTradeNo);
                    } catch (Exception e) {
                        logger.error("❌ 支付确认失败（但支付状态已更新）: {}", e.getMessage());
                        // 即使确认失败，也要保存支付状态，避免丢失支付记录
                        paymentRepository.save(payment);
                    }
                } else {
                    // 非成功状态，只保存支付记录
                    paymentRepository.save(payment);
                    logger.info("支付记录更新成功: 订单号={}, 状态={}", outTradeNo, payment.getStatus());
                }
            }
            
            logger.info("========== 支付宝异步通知处理完成 ==========");
            return "success";
            
        } catch (Exception e) {
            logger.error("========== 处理支付宝异步通知异常 ==========", e);
            return "failure";
        }
    }
    
    /**
     * 支付宝同步返回接口
     * 用户支付完成后，支付宝会跳转到此页面（GET请求）
     * 
     * 参考 IJPay 实现：
     * - 使用 AlipaySignature.rsaCheckV1() 验证签名
     * - 验证成功后可以跳转到支付成功页面
     * 
     * @param request HTTP请求对象
     * @return 支付结果信息
     */
    @GetMapping("/return")
    public Map<String, Object> returnUrl(HttpServletRequest request) {
        logger.info("========== 收到支付宝同步返回 ==========");
        logger.info("请求方法: {}", request.getMethod());
        logger.info("请求URL: {}", request.getRequestURL());
        
        Map<String, Object> result = new HashMap<>();
        
        try {
            // 获取支付宝GET过来的反馈信息
            Map<String, String> params = getRequestParams(request);
            
            // 打印所有参数（用于调试）
            logger.info("支付宝同步返回参数:");
            for (Map.Entry<String, String> entry : params.entrySet()) {
                logger.info("  {} = {}", entry.getKey(), entry.getValue());
            }
            
            // 验证签名
            boolean verifyResult = AlipaySignature.rsaCheckV1(
                params, 
                aliPayConfig.getPublicKey(), 
                aliPayConfig.getCharset() != null ? aliPayConfig.getCharset() : "UTF-8", 
                aliPayConfig.getSignType() != null ? aliPayConfig.getSignType() : "RSA2"
            );
            
            if (!verifyResult) {
                logger.error("========== 支付宝同步返回签名验证失败 ==========");
                result.put("success", false);
                result.put("message", "签名验证失败");
                return result;
            }
            
            logger.info("========== 支付宝同步返回签名验证成功 ==========");
            
            // 获取关键参数
            String outTradeNo = params.get("out_trade_no");
            String tradeNo = params.get("trade_no");
            String totalAmount = params.get("total_amount");
            
            logger.info("订单号: {}, 交易号: {}, 金额: {}", outTradeNo, tradeNo, totalAmount);
            
            // 查找支付记录
            Optional<Payment> paymentOpt = paymentRepository.findByOrderId(outTradeNo);
            if (!paymentOpt.isPresent()) {
                logger.error("支付记录不存在: {}", outTradeNo);
                result.put("success", false);
                result.put("message", "支付记录不存在");
                return result;
            }
            
            Payment payment = paymentOpt.get();
            
            // 如果状态还是待支付，更新为处理中（实际状态应该由异步通知更新）
            if (payment.getStatus() == PaymentStatus.PENDING) {
                payment.setStatus(PaymentStatus.PROCESSING);
                payment.setExternalTransactionId(tradeNo);
                paymentRepository.save(payment);
                logger.info("支付记录状态已更新为处理中: {}", outTradeNo);
            }
            
            result.put("success", true);
            result.put("message", "支付成功");
            result.put("orderId", outTradeNo);
            result.put("tradeNo", tradeNo);
            result.put("amount", totalAmount);
            result.put("paymentStatus", payment.getStatus().name());
            
            logger.info("========== 支付宝同步返回处理完成 ==========");
            return result;
            
        } catch (Exception e) {
            logger.error("========== 处理支付宝同步返回异常 ==========", e);
            result.put("success", false);
            result.put("message", "处理失败: " + e.getMessage());
            return result;
        }
    }
    
    /**
     * 从HttpServletRequest中获取所有参数
     * 兼容GET和POST请求，支持form-urlencoded格式
     * 
     * 注意：Spring Boot 3 使用 jakarta.servlet，而 IJPay 可能使用 javax.servlet
     * 所以这里手动解析参数，而不是直接使用 AliPayApi.toMap(request)
     * 
     * @param request HTTP请求对象
     * @return 参数Map
     */
    private Map<String, String> getRequestParams(HttpServletRequest request) throws IOException {
        Map<String, String> params = new HashMap<>();
        
        // 获取URL参数（GET请求）
        request.getParameterMap().forEach((key, values) -> {
            if (values != null && values.length > 0) {
                params.put(key, values[0]);
            }
        });
        
        // 如果是POST请求，尝试从请求体获取参数
        if ("POST".equalsIgnoreCase(request.getMethod())) {
            try (BufferedReader reader = request.getReader()) {
                StringBuilder body = new StringBuilder();
                String line;
                while ((line = reader.readLine()) != null) {
                    body.append(line);
                }
                
                // 解析form-urlencoded格式的请求体
                if (body.length() > 0) {
                    String bodyStr = body.toString();
                    if (bodyStr.contains("=")) {
                        String[] pairs = bodyStr.split("&");
                        for (String pair : pairs) {
                            String[] keyValue = pair.split("=", 2);
                            if (keyValue.length == 2) {
                                try {
                                    String key = java.net.URLDecoder.decode(keyValue[0], "UTF-8");
                                    String value = java.net.URLDecoder.decode(keyValue[1], "UTF-8");
                                    // POST参数会覆盖GET参数（如果存在）
                                    params.put(key, value);
                                } catch (Exception e) {
                                    logger.warn("解析参数失败: {}", pair, e);
                                }
                            }
                        }
                    }
                }
            }
        }
        
        return params;
    }
}

