package com.ycwl.basic.pricing.service;

import com.ycwl.basic.pricing.dto.DiscountCombinationResult;
import com.ycwl.basic.pricing.dto.PriceCalculationRequest;
import com.ycwl.basic.pricing.dto.PriceCalculationResult;
import com.ycwl.basic.pricing.dto.ProductItem;
import com.ycwl.basic.pricing.entity.PriceProductConfig;
import com.ycwl.basic.pricing.enums.ProductType;
import com.ycwl.basic.pricing.service.impl.PriceCalculationServiceImpl;
import com.ycwl.basic.product.capability.PricingMode;
import com.ycwl.basic.product.capability.ProductTypeCapability;
import com.ycwl.basic.product.service.IProductTypeCapabilityService;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
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.Collections;

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

/**
 * 测试新增的照片打印 SKU（PHOTO_PRINT_MU 和 PHOTO_PRINT_FX）的价格计算逻辑
 * <p>
 * 测试范围：
 * 1. 枚举定义正确性
 * 2. 价格计算逻辑（单价×数量）
 * 3. 价格回退机制（阶梯→具体→default）
 * 4. 与现有 PHOTO_PRINT 行为一致性
 */
@ExtendWith(MockitoExtension.class)
@DisplayName("新照片打印 SKU 价格计算测试")
class NewPhotoPrintSkuTest {

    @Mock
    private IProductConfigService productConfigService;

    @Mock
    private ICouponService couponService;

    @Mock
    private IPriceBundleService bundleService;

    @Mock
    private IDiscountDetectionService discountDetectionService;

    @Mock
    private IVoucherService voucherService;

    @Mock
    private IProductTypeCapabilityService productTypeCapabilityService;

    @InjectMocks
    private PriceCalculationServiceImpl priceCalculationService;

    @BeforeEach
    void setUp() {
        ProductTypeCapability capability = new ProductTypeCapability();
        capability.setPricingModeEnum(PricingMode.QUANTITY_BASED);
        lenient().when(productTypeCapabilityService.getCapability(anyString())).thenReturn(capability);
        lenient().when(discountDetectionService.previewOptimalCombination(any())).thenReturn(buildEmptyDiscountResult());
    }

    /**
     * 测试1：验证新枚举类型定义正确
     */
    @Test
    @DisplayName("验证 PHOTO_PRINT_MU 和 PHOTO_PRINT_FX 枚举定义")
    void testNewProductTypeEnumDefinition() {
        // 验证枚举值存在
        assertNotNull(ProductType.PHOTO_PRINT_MU);
        assertNotNull(ProductType.PHOTO_PRINT_FX);

        // 验证枚举属性
        assertEquals("PHOTO_PRINT_MU", ProductType.PHOTO_PRINT_MU.getCode());
        assertEquals("手机照片打印", ProductType.PHOTO_PRINT_MU.getDescription());

        assertEquals("PHOTO_PRINT_FX", ProductType.PHOTO_PRINT_FX.getCode());
        assertEquals("特效照片打印", ProductType.PHOTO_PRINT_FX.getDescription());

        // 验证 fromCode 方法
        assertEquals(ProductType.PHOTO_PRINT_MU, ProductType.fromCode("PHOTO_PRINT_MU"));
        assertEquals(ProductType.PHOTO_PRINT_FX, ProductType.fromCode("PHOTO_PRINT_FX"));
    }

    /**
     * 测试2：手机照片打印 - 基础价格计算（单价×数量）
     */
    @Test
    @DisplayName("PHOTO_PRINT_MU - 基础价格计算（单价×数量）")
    void testPhotoPrintMuPriceCalculation() {
        // 准备测试数据
        BigDecimal unitPrice = new BigDecimal("3.00");
        BigDecimal originalPrice = new BigDecimal("5.00");
        int quantity = 20;

        PriceProductConfig config = new PriceProductConfig();
        config.setProductType("PHOTO_PRINT_MU");
        config.setProductId("default");
        config.setBasePrice(unitPrice);
        config.setOriginalPrice(originalPrice);

        // Mock 服务行为
        when(productConfigService.getTierConfig(anyString(), anyString(), anyInt(), isNull()))
                .thenReturn(null); // 不使用阶梯定价
        when(productConfigService.getProductConfig("PHOTO_PRINT_MU", "default", null))
                .thenReturn(config);

        // 构建请求
        ProductItem item = new ProductItem();
        item.setProductType(ProductType.PHOTO_PRINT_MU);
        item.setProductId("default");
        item.setQuantity(quantity);
        item.setPurchaseCount(1);

        PriceCalculationRequest request = new PriceCalculationRequest();
        request.setProducts(Collections.singletonList(item));
        request.setPreviewOnly(true);

        // 执行计算
        PriceCalculationResult result = priceCalculationService.calculatePrice(request);

        // 验证结果
        assertNotNull(result);
        assertEquals(0, unitPrice.multiply(BigDecimal.valueOf(quantity))
                .compareTo(result.getFinalAmount())); // 3.00 * 20 = 60.00

        // 验证服务调用
        verify(productConfigService, atLeastOnce())
                .getProductConfig("PHOTO_PRINT_MU", "default", null);
    }

    /**
     * 测试3：特效照片打印 - 基础价格计算
     */
    @Test
    @DisplayName("PHOTO_PRINT_FX - 基础价格计算（单价×数量）")
    void testPhotoPrintFxPriceCalculation() {
        // 准备测试数据
        BigDecimal unitPrice = new BigDecimal("5.00");
        BigDecimal originalPrice = new BigDecimal("8.00");
        int quantity = 15;

        PriceProductConfig config = new PriceProductConfig();
        config.setProductType("PHOTO_PRINT_FX");
        config.setProductId("default");
        config.setBasePrice(unitPrice);
        config.setOriginalPrice(originalPrice);

        // Mock 服务行为
        when(productConfigService.getTierConfig(anyString(), anyString(), anyInt(), isNull()))
                .thenReturn(null);
        when(productConfigService.getProductConfig("PHOTO_PRINT_FX", "default", null))
                .thenReturn(config);

        // 构建请求
        ProductItem item = new ProductItem();
        item.setProductType(ProductType.PHOTO_PRINT_FX);
        item.setProductId("default");
        item.setQuantity(quantity);
        item.setPurchaseCount(1);

        PriceCalculationRequest request = new PriceCalculationRequest();
        request.setProducts(Collections.singletonList(item));
        request.setPreviewOnly(true);

        // 执行计算
        PriceCalculationResult result = priceCalculationService.calculatePrice(request);

        // 验证结果
        assertNotNull(result);
        assertEquals(0, unitPrice.multiply(BigDecimal.valueOf(quantity))
                .compareTo(result.getFinalAmount())); // 5.00 * 15 = 75.00

        verify(productConfigService, atLeastOnce())
                .getProductConfig("PHOTO_PRINT_FX", "default", null);
    }

    /**
     * 测试4：景区特定配置价格计算
     */
    @Test
    @DisplayName("PHOTO_PRINT_MU - 景区特定配置")
    void testPhotoPrintMuWithScenicSpecificConfig() {
        String scenicId = "100";
        BigDecimal scenicPrice = new BigDecimal("2.50");
        int quantity = 30;

        PriceProductConfig scenicConfig = new PriceProductConfig();
        scenicConfig.setProductType("PHOTO_PRINT_MU");
        scenicConfig.setProductId(scenicId);
        scenicConfig.setBasePrice(scenicPrice);
        scenicConfig.setOriginalPrice(scenicPrice);

        when(productConfigService.getTierConfig(anyString(), anyString(), anyInt(), isNull()))
                .thenReturn(null);
        when(productConfigService.getProductConfig("PHOTO_PRINT_MU", scenicId, null))
                .thenReturn(scenicConfig);

        ProductItem item = new ProductItem();
        item.setProductType(ProductType.PHOTO_PRINT_MU);
        item.setProductId(scenicId);
        item.setQuantity(quantity);
        item.setPurchaseCount(1);

        PriceCalculationRequest request = new PriceCalculationRequest();
        request.setProducts(Collections.singletonList(item));
        request.setPreviewOnly(true);

        PriceCalculationResult result = priceCalculationService.calculatePrice(request);

        assertNotNull(result);
        // 验证使用景区特定价格：2.50 * 30 = 75.00
        assertEquals(0, scenicPrice.multiply(BigDecimal.valueOf(quantity))
                .compareTo(result.getFinalAmount()));

        verify(productConfigService).getProductConfig("PHOTO_PRINT_MU", scenicId, null);
    }

    /**
     * 测试5：价格回退机制 - 从景区配置回退到 default
     */
    @Test
    @DisplayName("价格回退机制 - 景区配置不存在时回退到 default")
    void testPriceFallbackMechanism() {
        String scenicId = "999";
        BigDecimal defaultPrice = new BigDecimal("3.00");
        int quantity = 10;

        PriceProductConfig defaultConfig = new PriceProductConfig();
        defaultConfig.setProductType("PHOTO_PRINT_MU");
        defaultConfig.setProductId("default");
        defaultConfig.setBasePrice(defaultPrice);
        defaultConfig.setOriginalPrice(defaultPrice);

        // 景区配置不存在，抛出异常
        when(productConfigService.getTierConfig(anyString(), anyString(), anyInt(), isNull()))
                .thenReturn(null);
        when(productConfigService.getProductConfig("PHOTO_PRINT_MU", scenicId, null))
                .thenThrow(new RuntimeException("Not found"));
        // 回退到 default 配置
        when(productConfigService.getProductConfig("PHOTO_PRINT_MU", "default", null))
                .thenReturn(defaultConfig);

        ProductItem item = new ProductItem();
        item.setProductType(ProductType.PHOTO_PRINT_MU);
        item.setProductId(scenicId);
        item.setQuantity(quantity);
        item.setPurchaseCount(1);

        PriceCalculationRequest request = new PriceCalculationRequest();
        request.setProducts(Collections.singletonList(item));
        request.setPreviewOnly(true);

        PriceCalculationResult result = priceCalculationService.calculatePrice(request);

        assertNotNull(result);
        // 验证使用 default 价格：3.00 * 10 = 30.00
        assertEquals(0, defaultPrice.multiply(BigDecimal.valueOf(quantity))
                .compareTo(result.getFinalAmount()));

        // 验证回退逻辑被调用
        verify(productConfigService).getProductConfig("PHOTO_PRINT_MU", scenicId, null);
        verify(productConfigService, atLeastOnce())
                .getProductConfig("PHOTO_PRINT_MU", "default", null);
    }

    /**
     * 测试6：与现有 PHOTO_PRINT 行为一致性
     */
    @Test
    @DisplayName("新 SKU 与 PHOTO_PRINT 行为一致性")
    void testConsistencyWithExistingPhotoPrint() {
        BigDecimal unitPrice = new BigDecimal("2.00");
        int quantity = 25;
        BigDecimal expectedTotal = unitPrice.multiply(BigDecimal.valueOf(quantity));

        // 准备三种类型的配置
        PriceProductConfig photoPrintConfig = createConfig("PHOTO_PRINT", unitPrice);
        PriceProductConfig photoPrintMuConfig = createConfig("PHOTO_PRINT_MU", unitPrice);
        PriceProductConfig photoPrintFxConfig = createConfig("PHOTO_PRINT_FX", unitPrice);

        when(productConfigService.getTierConfig(anyString(), anyString(), anyInt(), isNull()))
                .thenReturn(null);
        when(productConfigService.getProductConfig("PHOTO_PRINT", "default", null))
                .thenReturn(photoPrintConfig);
        when(productConfigService.getProductConfig("PHOTO_PRINT_MU", "default", null))
                .thenReturn(photoPrintMuConfig);
        when(productConfigService.getProductConfig("PHOTO_PRINT_FX", "default", null))
                .thenReturn(photoPrintFxConfig);

        // 测试 PHOTO_PRINT
        PriceCalculationResult result1 = calculatePrice(ProductType.PHOTO_PRINT, quantity);
        // 测试 PHOTO_PRINT_MU
        PriceCalculationResult result2 = calculatePrice(ProductType.PHOTO_PRINT_MU, quantity);
        // 测试 PHOTO_PRINT_FX
        PriceCalculationResult result3 = calculatePrice(ProductType.PHOTO_PRINT_FX, quantity);

        // 验证三者计算逻辑一致（都是单价×数量）
        assertEquals(0, expectedTotal.compareTo(result1.getFinalAmount()));
        assertEquals(0, expectedTotal.compareTo(result2.getFinalAmount()));
        assertEquals(0, expectedTotal.compareTo(result3.getFinalAmount()));
    }

    /**
     * 测试7：数量为0或负数的边界情况
     */
    @Test
    @DisplayName("边界测试 - 数量为0或负数")
    void testEdgeCasesWithZeroOrNegativeQuantity() {
        BigDecimal unitPrice = new BigDecimal("3.00");

        PriceProductConfig config = new PriceProductConfig();
        config.setProductType("PHOTO_PRINT_MU");
        config.setProductId("default");
        config.setBasePrice(unitPrice);
        config.setOriginalPrice(unitPrice);

        when(productConfigService.getTierConfig(anyString(), anyString(), anyInt(), isNull()))
                .thenReturn(null);
        when(productConfigService.getProductConfig("PHOTO_PRINT_MU", "default", null))
                .thenReturn(config);

        // 测试数量为0
        PriceCalculationResult result0 = calculatePrice(ProductType.PHOTO_PRINT_MU, 0);
        assertEquals(0, BigDecimal.ZERO.compareTo(result0.getFinalAmount()));

        // 测试数量为1（边界）
        PriceCalculationResult result1 = calculatePrice(ProductType.PHOTO_PRINT_MU, 1);
        assertEquals(0, unitPrice.compareTo(result1.getFinalAmount()));
    }

    // ==================== 辅助方法 ====================

    /**
     * 创建价格配置对象
     */
    private PriceProductConfig createConfig(String productType, BigDecimal basePrice) {
        PriceProductConfig config = new PriceProductConfig();
        config.setProductType(productType);
        config.setProductId("default");
        config.setBasePrice(basePrice);
        config.setOriginalPrice(basePrice);
        return config;
    }

    private DiscountCombinationResult buildEmptyDiscountResult() {
        DiscountCombinationResult result = new DiscountCombinationResult();
        result.setSuccess(true);
        result.setDiscountDetails(Collections.emptyList());
        result.setAppliedDiscounts(Collections.emptyList());
        result.setAvailableDiscounts(Collections.emptyList());
        return result;
    }

    /**
     * 执行价格计算的辅助方法
     */
    private PriceCalculationResult calculatePrice(ProductType productType, int quantity) {
        ProductItem item = new ProductItem();
        item.setProductType(productType);
        item.setProductId("default");
        item.setQuantity(quantity);
        item.setPurchaseCount(1);

        PriceCalculationRequest request = new PriceCalculationRequest();
        request.setProducts(Collections.singletonList(item));
        request.setPreviewOnly(true);

        return priceCalculationService.calculatePrice(request);
    }
}
