package com.gxwebsoft.shop;

import com.gxwebsoft.common.core.exception.BusinessException;
import com.gxwebsoft.common.system.entity.User;
import com.gxwebsoft.shop.config.OrderConfigProperties;
import com.gxwebsoft.shop.dto.OrderCreateRequest;
import com.gxwebsoft.shop.entity.ShopGoods;
import com.gxwebsoft.shop.entity.ShopOrder;
import com.gxwebsoft.shop.service.OrderBusinessService;
import com.gxwebsoft.shop.service.ShopGoodsService;
import com.gxwebsoft.shop.service.ShopOrderGoodsService;
import com.gxwebsoft.shop.service.ShopOrderService;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

import java.math.BigDecimal;
import java.util.Arrays;

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

/**
 * 订单验证测试类
 * 测试商品信息后台验证逻辑
 */
@ExtendWith(MockitoExtension.class)
class OrderValidationTest {

    @Mock
    private ShopOrderService shopOrderService;

    @Mock
    private ShopOrderGoodsService shopOrderGoodsService;

    @Mock
    private ShopGoodsService shopGoodsService;

    @Mock
    private OrderConfigProperties orderConfig;

    @InjectMocks
    private OrderBusinessService orderBusinessService;

    private User testUser;
    private OrderCreateRequest testRequest;
    private ShopGoods testGoods;

    @BeforeEach
    void setUp() {
        // 准备测试用户
        testUser = new User();
        testUser.setUserId(1);
        testUser.setNickname("测试用户");
        testUser.setPhone("13800138000");

        // 准备测试商品
        testGoods = new ShopGoods();
        testGoods.setGoodsId(10018);
        testGoods.setName("测试商品");
        testGoods.setPrice(new BigDecimal("99.00"));
        testGoods.setStatus(0); // 上架状态
        testGoods.setStock(100); // 库存100
        testGoods.setCanBuyNumber(10); // 最大购买数量10
        testGoods.setCode("TEST001");

        // 准备测试订单请求
        testRequest = new OrderCreateRequest();
        testRequest.setType(0);
        testRequest.setTitle("测试订单");
        testRequest.setTotalPrice(new BigDecimal("99.00"));
        testRequest.setTenantId(1);

        // 准备商品项
        OrderCreateRequest.OrderGoodsItem goodsItem = new OrderCreateRequest.OrderGoodsItem();
        goodsItem.setGoodsId(10018);
        goodsItem.setQuantity(1);
        testRequest.setGoodsItems(Arrays.asList(goodsItem));
    }

    @Test
    void testValidateOrderRequest_Success() {
        // Mock 商品查询
        when(shopGoodsService.getById(10018)).thenReturn(testGoods);
        when(orderConfig.getTenantRule(1)).thenReturn(null);

        // 执行验证 - 应该成功
        assertDoesNotThrow(() -> {
            // 使用反射调用私有方法进行测试
            java.lang.reflect.Method method = OrderBusinessService.class
                    .getDeclaredMethod("validateOrderRequest", OrderCreateRequest.class, User.class);
            method.setAccessible(true);
            method.invoke(orderBusinessService, testRequest, testUser);
        });

        // 验证总金额被正确设置
        assertEquals(new BigDecimal("99.00"), testRequest.getTotalPrice());
    }

    @Test
    void testValidateOrderRequest_GoodsNotFound() {
        // Mock 商品不存在
        when(shopGoodsService.getById(10018)).thenReturn(null);

        // 执行验证 - 应该抛出异常
        Exception exception = assertThrows(Exception.class, () -> {
            java.lang.reflect.Method method = OrderBusinessService.class
                    .getDeclaredMethod("validateOrderRequest", OrderCreateRequest.class, User.class);
            method.setAccessible(true);
            method.invoke(orderBusinessService, testRequest, testUser);
        });

        // 检查是否是 InvocationTargetException 包装的 BusinessException
        assertTrue(exception instanceof java.lang.reflect.InvocationTargetException);
        Throwable cause = exception.getCause();
        assertTrue(cause instanceof BusinessException);
        assertTrue(cause.getMessage().contains("商品不存在"));
    }

    @Test
    void testValidateOrderRequest_GoodsOffShelf() {
        // 设置商品为下架状态
        testGoods.setStatus(1);
        when(shopGoodsService.getById(10018)).thenReturn(testGoods);

        // 执行验证 - 应该抛出异常
        Exception exception = assertThrows(Exception.class, () -> {
            java.lang.reflect.Method method = OrderBusinessService.class
                    .getDeclaredMethod("validateOrderRequest", OrderCreateRequest.class, User.class);
            method.setAccessible(true);
            method.invoke(orderBusinessService, testRequest, testUser);
        });

        // 检查是否是 InvocationTargetException 包装的 BusinessException
        assertTrue(exception instanceof java.lang.reflect.InvocationTargetException);
        Throwable cause = exception.getCause();
        assertTrue(cause instanceof BusinessException);
        assertTrue(cause.getMessage().contains("商品已下架"));
    }

    @Test
    void testValidateOrderRequest_InsufficientStock() {
        // 设置库存不足
        testGoods.setStock(0);
        when(shopGoodsService.getById(10018)).thenReturn(testGoods);

        // 执行验证 - 应该抛出异常
        Exception exception = assertThrows(Exception.class, () -> {
            java.lang.reflect.Method method = OrderBusinessService.class
                    .getDeclaredMethod("validateOrderRequest", OrderCreateRequest.class, User.class);
            method.setAccessible(true);
            method.invoke(orderBusinessService, testRequest, testUser);
        });

        // 检查是否是 InvocationTargetException 包装的 BusinessException
        assertTrue(exception instanceof java.lang.reflect.InvocationTargetException);
        Throwable cause = exception.getCause();
        assertTrue(cause instanceof BusinessException);
        assertTrue(cause.getMessage().contains("商品库存不足"));
    }

    @Test
    void testValidateOrderRequest_ExceedBuyLimit() {
        // 设置购买数量超过限制
        testRequest.getGoodsItems().get(0).setQuantity(15); // 超过最大购买数量10
        when(shopGoodsService.getById(10018)).thenReturn(testGoods);

        // 执行验证 - 应该抛出异常
        Exception exception = assertThrows(Exception.class, () -> {
            java.lang.reflect.Method method = OrderBusinessService.class
                    .getDeclaredMethod("validateOrderRequest", OrderCreateRequest.class, User.class);
            method.setAccessible(true);
            method.invoke(orderBusinessService, testRequest, testUser);
        });

        // 检查是否是 InvocationTargetException 包装的 BusinessException
        assertTrue(exception instanceof java.lang.reflect.InvocationTargetException);
        Throwable cause = exception.getCause();
        assertTrue(cause instanceof BusinessException);
        assertTrue(cause.getMessage().contains("购买数量超过限制"));
    }

    @Test
    void testValidateOrderRequest_PriceCalculation() {
        // 设置多个商品项
        OrderCreateRequest.OrderGoodsItem goodsItem1 = new OrderCreateRequest.OrderGoodsItem();
        goodsItem1.setGoodsId(10018);
        goodsItem1.setQuantity(2);

        OrderCreateRequest.OrderGoodsItem goodsItem2 = new OrderCreateRequest.OrderGoodsItem();
        goodsItem2.setGoodsId(10019);
        goodsItem2.setQuantity(1);

        testRequest.setGoodsItems(Arrays.asList(goodsItem1, goodsItem2));
        testRequest.setTotalPrice(new BigDecimal("297.00")); // 99*2 + 99*1

        // 准备第二个商品
        ShopGoods testGoods2 = new ShopGoods();
        testGoods2.setGoodsId(10019);
        testGoods2.setName("测试商品2");
        testGoods2.setPrice(new BigDecimal("99.00"));
        testGoods2.setStatus(0);
        testGoods2.setStock(100);

        when(shopGoodsService.getById(10018)).thenReturn(testGoods);
        when(shopGoodsService.getById(10019)).thenReturn(testGoods2);
        when(orderConfig.getTenantRule(1)).thenReturn(null);

        // 执行验证 - 应该成功
        assertDoesNotThrow(() -> {
            java.lang.reflect.Method method = OrderBusinessService.class
                    .getDeclaredMethod("validateOrderRequest", OrderCreateRequest.class, User.class);
            method.setAccessible(true);
            method.invoke(orderBusinessService, testRequest, testUser);
        });

        // 验证总金额计算正确
        assertEquals(new BigDecimal("297.00"), testRequest.getTotalPrice());
    }

    @Test
    void testValidateOrderRequest_PriceDiscrepancy() {
        // 设置前端传入的金额与后台计算不一致
        testRequest.setTotalPrice(new BigDecimal("88.00")); // 错误的金额
        when(shopGoodsService.getById(10018)).thenReturn(testGoods);

        // 执行验证 - 应该抛出异常
        Exception exception = assertThrows(Exception.class, () -> {
            java.lang.reflect.Method method = OrderBusinessService.class
                    .getDeclaredMethod("validateOrderRequest", OrderCreateRequest.class, User.class);
            method.setAccessible(true);
            method.invoke(orderBusinessService, testRequest, testUser);
        });

        // 检查是否是 InvocationTargetException 包装的 BusinessException
        assertTrue(exception instanceof java.lang.reflect.InvocationTargetException);
        Throwable cause = exception.getCause();
        assertTrue(cause instanceof BusinessException);
        assertTrue(cause.getMessage().contains("订单金额计算错误"));
    }

    @Test
    void testBuildShopOrder_RequiredFields() throws Exception {
        // Mock 配置
        OrderConfigProperties.DefaultConfig defaultConfig = new OrderConfigProperties.DefaultConfig();
        defaultConfig.setDefaultComments("默认备注");
        when(orderConfig.getDefaultConfig()).thenReturn(defaultConfig);

        // 使用反射调用 buildShopOrder 方法
        java.lang.reflect.Method buildMethod = OrderBusinessService.class
                .getDeclaredMethod("buildShopOrder", OrderCreateRequest.class, User.class);
        buildMethod.setAccessible(true);

        ShopOrder result = (ShopOrder) buildMethod.invoke(orderBusinessService, testRequest, testUser);

        // 验证必需字段都已设置
        assertNotNull(result.getPayPrice(), "payPrice 不能为空");
        assertNotNull(result.getPrice(), "price 不能为空");
        assertNotNull(result.getReducePrice(), "reducePrice 不能为空");
        assertNotNull(result.getMoney(), "money 不能为空");
        assertNotNull(result.getPayStatus(), "payStatus 不能为空");
        assertNotNull(result.getOrderStatus(), "orderStatus 不能为空");
        assertNotNull(result.getDeliveryStatus(), "deliveryStatus 不能为空");
        assertNotNull(result.getPayType(), "payType 不能为空");

        // 验证默认值
        assertEquals(testRequest.getTotalPrice(), result.getPayPrice());
        assertEquals(testRequest.getTotalPrice(), result.getPrice());
        assertEquals(BigDecimal.ZERO, result.getReducePrice());
        assertEquals(testRequest.getTotalPrice(), result.getMoney());
        assertEquals(false, result.getPayStatus());
        assertEquals(Integer.valueOf(0), result.getOrderStatus());
        assertEquals(Integer.valueOf(10), result.getDeliveryStatus());
        assertEquals(Integer.valueOf(1), result.getPayType());

        // 验证关键字段 - 租户ID（影响微信支付证书路径）
        assertNotNull(result.getTenantId(), "tenantId 不能为空");
        assertEquals(testRequest.getTenantId(), result.getTenantId(), "tenantId 必须正确设置");
    }

    @Test
    void testBuildShopOrder_TenantIdValidation() throws Exception {
        // 创建一个新的请求对象，租户ID为空
        OrderCreateRequest requestWithoutTenant = new OrderCreateRequest();
        requestWithoutTenant.setType(0);
        requestWithoutTenant.setTitle("测试订单");
        requestWithoutTenant.setTotalPrice(new BigDecimal("99.00"));
        requestWithoutTenant.setTenantId(null); // 设置为空

        // 准备商品项
        OrderCreateRequest.OrderGoodsItem goodsItem = new OrderCreateRequest.OrderGoodsItem();
        goodsItem.setGoodsId(10018);
        goodsItem.setQuantity(1);
        requestWithoutTenant.setGoodsItems(Arrays.asList(goodsItem));

        // 使用反射调用 buildShopOrder 方法
        java.lang.reflect.Method buildMethod = OrderBusinessService.class
                .getDeclaredMethod("buildShopOrder", OrderCreateRequest.class, User.class);
        buildMethod.setAccessible(true);

        // 执行验证 - 应该抛出异常
        Exception exception = assertThrows(Exception.class, () -> {
            buildMethod.invoke(orderBusinessService, requestWithoutTenant, testUser);
        });

        // 检查是否是 InvocationTargetException 包装的 BusinessException
        assertTrue(exception instanceof java.lang.reflect.InvocationTargetException);
        Throwable cause = exception.getCause();
        assertTrue(cause instanceof BusinessException);
        assertTrue(cause.getMessage().contains("租户ID不能为空"));
    }
}
