package com.example.demo.service;

import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.MessageDigest;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.time.LocalDateTime;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
import java.util.UUID;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import com.example.demo.model.Payment;
import com.example.demo.model.PaymentMethod;
import com.example.demo.model.PaymentStatus;
import com.example.demo.repository.PaymentRepository;
import com.fasterxml.jackson.databind.ObjectMapper;

/**
 * 噜噜支付（彩虹易支付）服务
 * 
 * 签名方式：RSA（商户私钥，SHA256WithRSA）
 * 验签方式：RSA（平台公钥，SHA256WithRSA）
 */
@Service
public class LuluPayService {
    
    private static final Logger logger = LoggerFactory.getLogger(LuluPayService.class);
    
    private final PaymentRepository paymentRepository;
    private final RestTemplate restTemplate;
    private final ObjectMapper objectMapper;
    
    @Value("${lulupay.api-url:}")
    private String apiUrl;
    
    @Value("${lulupay.pid:}")
    private String pid;
    
    @Value("${lulupay.merchant-key:}")
    private String merchantKey;  // MD5签名密钥
    
    @Value("${lulupay.platform-public-key:}")
    private String platformPublicKey;  // RSA验签公钥
    
    @Value("${lulupay.notify-url:}")
    private String notifyUrl;
    
    @Value("${lulupay.return-url:}")
    private String returnUrl;
    
    @Autowired(required = false)
    private UserErrorLogService userErrorLogService;
    
    public LuluPayService(PaymentRepository paymentRepository) {
        this.paymentRepository = paymentRepository;
        this.restTemplate = new RestTemplate();
        this.objectMapper = new ObjectMapper();
    }

    /**
     * 创建支付订单
     * 调用API接口：https://api.dulupay.com/api/pay/create
     */
    public Map<String, Object> createPayment(Payment payment, String payType, String clientIp) {
        try {
            logger.info("开始创建噜噜支付订单，订单号：{}，金额：{}，支付方式：{}", 
                payment.getOrderId(), payment.getAmount(), payType);
            
            // 设置支付状态和方式
            payment.setStatus(PaymentStatus.PENDING);
            if ("wxpay".equals(payType)) {
                payment.setPaymentMethod(PaymentMethod.WECHAT);
            } else {
                payment.setPaymentMethod(PaymentMethod.ALIPAY);
            }
            
            if (payment.getOrderId() == null || payment.getOrderId().isEmpty()) {
                payment.setOrderId(generateOrderId());
            }
            payment.setCallbackUrl(notifyUrl);
            payment.setReturnUrl(returnUrl);
            
            // 保存支付记录
            paymentRepository.save(payment);
            logger.info("支付记录已保存，ID：{}", payment.getId());
            
            // 调用API创建支付
            return callCreateApi(payment, payType, clientIp);
            
        } catch (Exception e) {
            logger.error("创建支付订单异常，订单号：{}，错误：{}", payment.getOrderId(), e.getMessage(), e);
            payment.setStatus(PaymentStatus.FAILED);
            paymentRepository.save(payment);
            logPaymentError(payment.getOrderId(), payType, e.getMessage());
            throw new RuntimeException("支付服务异常：" + e.getMessage());
        }
    }
    
    /**
     * 调用统一下单API（使用submit方式，返回表单直接跳转）
     */
    private Map<String, Object> callCreateApi(Payment payment, String payType, String clientIp) throws Exception {
        String apiEndpoint = apiUrl + "api/pay/submit";
        
        // 构建请求参数（按SDK方式，不含method和clientip）
        Map<String, String> params = new TreeMap<>();
        params.put("pid", pid);
        params.put("type", payType);
        params.put("out_trade_no", payment.getOrderId());
        params.put("notify_url", notifyUrl);
        params.put("return_url", returnUrl);
        params.put("name", payment.getDescription() != null ? payment.getDescription() : "VIP会员");
        params.put("money", payment.getAmount().setScale(2, BigDecimal.ROUND_HALF_UP).toString());
        params.put("timestamp", String.valueOf(System.currentTimeMillis() / 1000));
        
        // 生成MD5签名
        String sign = generateMd5Sign(params);
        params.put("sign", sign);
        params.put("sign_type", "MD5");
        
        logger.info("调用噜噜支付API: {}，参数: {}", apiEndpoint, params);
        
        // 构建跳转表单（SDK方式）
        StringBuilder formHtml = new StringBuilder();
        formHtml.append("<form id=\"lulupay_form\" action=\"").append(escapeHtml(apiEndpoint)).append("\" method=\"post\">");
        for (Map.Entry<String, String> entry : params.entrySet()) {
            formHtml.append("<input type=\"hidden\" name=\"").append(entry.getKey())
                    .append("\" value=\"").append(escapeHtml(entry.getValue())).append("\"/>");
        }
        formHtml.append("<input type=\"submit\" value=\"正在跳转...\"/>");
        formHtml.append("</form>");
        formHtml.append("<script>document.getElementById('lulupay_form').submit();</script>");
        
        Map<String, Object> result = new HashMap<>();
        result.put("success", true);
        result.put("outTradeNo", payment.getOrderId());
        result.put("payForm", formHtml.toString());
        result.put("payType", "PAGE_PAY");
        
        logger.info("支付表单已生成，订单号：{}", payment.getOrderId());
        
        return result;
    }

    /**
     * 处理异步通知回调
     * 使用RSA验签（平台公钥）
     */
    public boolean handleNotify(Map<String, String> params) {
        try {
            logger.info("收到噜噜支付异步通知: {}", params);
            
            // 使用RSA验签
            if (!verifyRsaSign(params)) {
                logger.warn("噜噜支付异步通知RSA签名验证失败");
                return false;
            }
            
            String tradeStatus = params.get("trade_status");
            String outTradeNo = params.get("out_trade_no");
            String tradeNo = params.get("trade_no");
            String type = params.get("type");
            String money = params.get("money");
            
            logger.info("订单号：{}，交易号：{}，交易状态：{}，支付方式：{}，金额：{}", 
                outTradeNo, tradeNo, tradeStatus, type, money);
            
            // 查找支付记录
            Payment payment = paymentRepository.findByOrderId(outTradeNo)
                .orElseThrow(() -> new RuntimeException("支付记录不存在：" + outTradeNo));
            
            // 注意：这里只做验签和基本状态记录，不更新支付状态为SUCCESS
            // 支付状态的更新和积分增加由 LuluPayCallbackController 调用 PaymentService.confirmPaymentSuccess 统一处理
            // 这样可以确保积分增加逻辑被正确触发
            if ("TRADE_CLOSED".equals(tradeStatus)) {
                payment.setStatus(PaymentStatus.CANCELLED);
                paymentRepository.save(payment);
                logger.info("交易关闭，订单号：{}", outTradeNo);
            }
            // TRADE_SUCCESS 的处理交给 Controller 层的 confirmPaymentSuccess
            
            return true;
            
        } catch (Exception e) {
            logger.error("处理噜噜支付异步通知异常：", e);
            return false;
        }
    }
    
    /**
     * 处理同步返回
     */
    public boolean handleReturn(Map<String, String> params) {
        try {
            logger.info("收到噜噜支付同步返回: {}", params);
            
            // 使用RSA验签
            if (!verifyRsaSign(params)) {
                logger.warn("噜噜支付同步返回RSA签名验证失败");
                return false;
            }
            
            String outTradeNo = params.get("out_trade_no");
            String tradeNo = params.get("trade_no");
            String tradeStatus = params.get("trade_status");
            
            logger.info("同步返回，订单号：{}，交易号：{}，状态：{}", outTradeNo, tradeNo, tradeStatus);
            
            // 同步返回只做验签和记录日志，不更新状态
            // 状态更新由异步通知处理，避免重复处理
            // 这里只返回验签结果，让前端知道支付是否成功
            
            return "TRADE_SUCCESS".equals(tradeStatus);
            
        } catch (Exception e) {
            logger.error("处理噜噜支付同步返回异常：", e);
            return false;
        }
    }

    /**
     * 生成MD5签名（用于请求）
     * 签名规则：参数按key排序，拼接成 key1=value1&key2=value2&key=商户密钥，然后MD5
     */
    private String generateMd5Sign(Map<String, String> params) throws Exception {
        String signContent = getSignContent(params) + merchantKey;
        logger.debug("MD5待签名字符串: {}", signContent);
        
        MessageDigest md = MessageDigest.getInstance("MD5");
        byte[] digest = md.digest(signContent.getBytes(StandardCharsets.UTF_8));
        
        StringBuilder sb = new StringBuilder();
        for (byte b : digest) {
            sb.append(String.format("%02x", b));
        }
        
        String sign = sb.toString();
        logger.debug("MD5签名结果: {}", sign);
        return sign;
    }
    
    /**
     * 验证RSA签名（用于回调验签）
     * 使用平台公钥验证 SHA256WithRSA 签名
     */
    private boolean verifyRsaSign(Map<String, String> params) {
        try {
            String sign = params.get("sign");
            if (sign == null || sign.isEmpty()) {
                logger.warn("签名为空");
                return false;
            }
            
            String signContent = getSignContent(params);
            logger.debug("RSA验签字符串: {}", signContent);
            
            // 解析公钥
            byte[] keyBytes = Base64.getDecoder().decode(platformPublicKey.replaceAll("\\s+", ""));
            X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            PublicKey publicKey = keyFactory.generatePublic(keySpec);
            
            // SHA256WithRSA验签
            Signature signature = Signature.getInstance("SHA256withRSA");
            signature.initVerify(publicKey);
            signature.update(signContent.getBytes(StandardCharsets.UTF_8));
            
            boolean result = signature.verify(Base64.getDecoder().decode(sign));
            if (!result) {
                logger.warn("RSA签名验证失败");
            }
            return result;
            
        } catch (Exception e) {
            logger.error("RSA验签异常: {}", e.getMessage(), e);
            return false;
        }
    }
    
    /**
     * 获取待签名字符串（按key的ASCII码升序排序）
     */
    private String getSignContent(Map<String, String> params) {
        TreeMap<String, String> sortedParams = new TreeMap<>(params);
        StringBuilder sb = new StringBuilder();
        
        for (Map.Entry<String, String> entry : sortedParams.entrySet()) {
            String k = entry.getKey();
            String v = entry.getValue();
            
            // 跳过sign、sign_type和空值
            if ("sign".equals(k) || "sign_type".equals(k) || v == null || v.trim().isEmpty()) {
                continue;
            }
            
            if (sb.length() > 0) {
                sb.append("&");
            }
            sb.append(k).append("=").append(v);
        }
        
        return sb.toString();
    }
    
    private String escapeHtml(String str) {
        if (str == null) return "";
        return str.replace("&", "&amp;").replace("<", "&lt;")
                  .replace(">", "&gt;").replace("\"", "&quot;").replace("'", "&#39;");
    }
    
    private String generateOrderId() {
        return "LULU" + System.currentTimeMillis() + UUID.randomUUID().toString().substring(0, 6).toUpperCase();
    }
    
    private void logPaymentError(String orderId, String payType, String errorMsg) {
        try {
            if (userErrorLogService != null) {
                userErrorLogService.logErrorAsync(null,
                    com.example.demo.model.UserErrorLog.ErrorType.PAYMENT_ERROR,
                    "噜噜支付创建失败: " + errorMsg, "LuluPayService", orderId, payType);
            }
        } catch (Exception logEx) {
            logger.warn("记录支付错误日志失败: {}", logEx.getMessage());
        }
    }
}
