package com.kexue.skills;

import com.kexue.skills.entity.PaymentOrder;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import java.math.BigDecimal;

import static org.junit.jupiter.api.Assertions.*;

/**
 * 微信支付参数校验单元测试（不依赖 Spring 容器）
 */
@DisplayName("微信支付参数校验测试")
class WechatPayValidationTest {

    private PaymentOrder testOrder;

    @BeforeEach
    void setUp() {
        testOrder = new PaymentOrder();
        testOrder.setUserId(1L);
        testOrder.setUserName("测试用户");
        testOrder.setProductName("测试商品");
        testOrder.setProductDesc("这是一个测试商品");
        testOrder.setAmount(new BigDecimal("0.01"));
        testOrder.setBusinessId(1L);
        testOrder.setBusinessType("purchase_content");
    }

    @Test
    @DisplayName("订单号格式验证 - 正常情况")
    void testOrderNo_Valid() {
        // 有效的订单号
        assertTrue(isValidOrderNo("ORDER_20260331_001"));
        assertTrue(isValidOrderNo("TEST_1234567890"));
        assertTrue(isValidOrderNo("PAY_abc_123_XYZ"));
        assertTrue(isValidOrderNo("a1b2c3d4e5f6"));
    }

    @Test
    @DisplayName("订单号格式验证 - 无效情况")
    void testOrderNo_Invalid() {
        // 包含特殊字符
        assertFalse(isValidOrderNo("ORDER@2026"));
        assertFalse(isValidOrderNo("TEST#ORDER"));
        assertFalse(isValidOrderNo("PAY$123"));
        
        // 包含中文
        assertFalse(isValidOrderNo("订单_123"));
        
        // 空字符串
        assertFalse(isValidOrderNo(""));
        assertFalse(isValidOrderNo("   "));
    }

    @Test
    @DisplayName("订单号长度验证")
    void testOrderNo_Length() {
        // 正好 32 位
        assertTrue(isValidOrderNo("12345678901234567890123456789012"));
        
        // 超过 32 位
        assertFalse(isValidOrderNo("123456789012345678901234567890123"));
        
        // 很长的 UUID（去掉横杠后通常超过 32 位）
        String longUuid = "12345678-1234-1234-1234-123456789012".replace("-", "");
        assertFalse(isValidOrderNo(longUuid));
    }

    @Test
    @DisplayName("金额验证 - 有效金额")
    void testAmount_Valid() {
        // 最小金额
        assertTrue(isValidAmount(new BigDecimal("0.01")));
        
        // 正常金额
        assertTrue(isValidAmount(new BigDecimal("1.00")));
        assertTrue(isValidAmount(new BigDecimal("9.99")));
        assertTrue(isValidAmount(new BigDecimal("100.00")));
        
        // 最大金额
        assertTrue(isValidAmount(new BigDecimal("100000.00")));
    }

    @Test
    @DisplayName("金额验证 - 无效金额")
    void testAmount_Invalid() {
        // 金额为 null
        assertFalse(isValidAmount(null));
        
        // 金额过小
        assertFalse(isValidAmount(new BigDecimal("0.001")));
        assertFalse(isValidAmount(new BigDecimal("0.00")));
        
        // 负数金额
        assertFalse(isValidAmount(new BigDecimal("-1.00")));
        
        // 金额过大
        assertFalse(isValidAmount(new BigDecimal("100000.01")));
        assertFalse(isValidAmount(new BigDecimal("200000.00")));
    }

    @Test
    @DisplayName("商品描述长度验证")
    void testProductDescription_Length() {
        // 短描述（正常）
        StringBuilder shortDesc = new StringBuilder();
        for (int i = 0; i < 10; i++) {
            shortDesc.append("测试");
        }
        assertTrue(getByteLength(shortDesc.toString()) <= 128);
        
        // 长描述（应截断）
        StringBuilder longDesc = new StringBuilder();
        for (int i = 0; i < 100; i++) {
            longDesc.append("这是非常长的商品描述");
        }
        
        // 原始长度应该超过 128 字节
        assertTrue(getByteLength(longDesc.toString()) > 128);
        
        // 处理后应该不超过 128 字节
        String processed = limitBodyLength(longDesc.toString());
        assertTrue(getByteLength(processed) <= 128, "处理后的描述不应超过 128 字节");
        assertTrue(processed.endsWith("..."), "处理后的描述应以省略号结尾");
    }

    @Test
    @DisplayName("IP 地址格式验证")
    void testIpAddress_Format() {
        // IPv4 地址
        assertTrue(isValidIpAddress("192.168.1.100"));
        assertTrue(isValidIpAddress("10.0.0.1"));
        assertTrue(isValidIpAddress("172.16.0.100"));
        assertTrue(isValidIpAddress("127.0.0.1"));
        
        // 无效 IP
        assertFalse(isValidIpAddress("256.256.256.256"));
        assertFalse(isValidIpAddress("192.168.1"));
        assertFalse(isValidIpAddress("invalid.ip"));
    }

    @Test
    @DisplayName("业务类型验证")
    void testBusinessType_Valid() {
        assertTrue(isValidBusinessType("recharge"));
        assertTrue(isValidBusinessType("purchase_content"));
    }

    @Test
    @DisplayName("业务类型验证 - 无效")
    void testBusinessType_Invalid() {
        assertFalse(isValidBusinessType(null));
        assertFalse(isValidBusinessType(""));
        assertFalse(isValidBusinessType("unknown_type"));
        assertFalse(isValidBusinessType("RECHARGE")); // 区分大小写
    }

    // ===== 辅助验证方法 =====

    /**
     * 验证订单号格式
     */
    private boolean isValidOrderNo(String orderNo) {
        if (orderNo == null || orderNo.trim().isEmpty()) {
            return false;
        }
        if (orderNo.length() > 32) {
            return false;
        }
        return orderNo.matches("^[a-zA-Z0-9_]+$");
    }

    /**
     * 验证金额
     */
    private boolean isValidAmount(BigDecimal amount) {
        if (amount == null) {
            return false;
        }
        if (amount.compareTo(new BigDecimal("0.01")) < 0) {
            return false;
        }
        if (amount.compareTo(new BigDecimal("100000")) > 0) {
            return false;
        }
        return true;
    }

    /**
     * 获取字符串的字节长度（UTF-8 编码）
     */
    private int getByteLength(String text) {
        try {
            return text.getBytes(java.nio.charset.StandardCharsets.UTF_8).length;
        } catch (Exception e) {
            return text.length();
        }
    }

    /**
     * 限制商品描述长度（模拟服务层逻辑）
     */
    private String limitBodyLength(String body) {
        if (body == null) {
            return "";
        }
        try {
            byte[] bytes = body.getBytes(java.nio.charset.StandardCharsets.UTF_8);
            if (bytes.length <= 128) {
                return body;
            }
            String truncated = new String(bytes, 0, Math.min(128 - 3, bytes.length), java.nio.charset.StandardCharsets.UTF_8);
            return truncated + "...";
        } catch (Exception e) {
            return body.length() > 60 ? body.substring(0, 60) + "..." : body;
        }
    }

    /**
     * 验证 IP 地址格式
     */
    private boolean isValidIpAddress(String ip) {
        if (ip == null || ip.isEmpty()) {
            return false;
        }
        String[] parts = ip.split("\\.");
        if (parts.length != 4) {
            return false;
        }
        try {
            for (String part : parts) {
                int num = Integer.parseInt(part);
                if (num < 0 || num > 255) {
                    return false;
                }
            }
            return true;
        } catch (NumberFormatException e) {
            return false;
        }
    }

    /**
     * 验证业务类型
     */
    private boolean isValidBusinessType(String businessType) {
        return "recharge".equals(businessType) || "purchase_content".equals(businessType);
    }
}
