package com.ycwl.basic.pricing.service.impl;

import com.ycwl.basic.pricing.dto.BundleDiscountInfo;
import com.ycwl.basic.pricing.dto.ProductItem;
import com.ycwl.basic.pricing.dto.UpgradeCheckRequest;
import com.ycwl.basic.pricing.dto.UpgradeCheckResult;
import com.ycwl.basic.pricing.entity.PriceBundleConfig;
import com.ycwl.basic.pricing.entity.PriceProductConfig;
import com.ycwl.basic.pricing.enums.ProductType;
import com.ycwl.basic.pricing.service.IBundleDiscountService;
import com.ycwl.basic.pricing.service.ICouponService;
import com.ycwl.basic.pricing.service.IDiscountDetectionService;
import com.ycwl.basic.pricing.service.IPriceBundleService;
import com.ycwl.basic.pricing.service.IProductConfigService;
import com.ycwl.basic.pricing.service.IVoucherService;
import com.ycwl.basic.product.service.IProductTypeCapabilityService;
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.List;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.when;

@ExtendWith(MockitoExtension.class)
class PriceCalculationServiceImplUpgradeCheckTest {

    @Mock
    private IProductConfigService productConfigService;
    @Mock
    private ICouponService couponService;
    @Mock
    private IPriceBundleService bundleService;
    @Mock
    private IBundleDiscountService bundleDiscountService;
    @Mock
    private IDiscountDetectionService discountDetectionService;
    @Mock
    private IVoucherService voucherService;
    @Mock
    private IProductTypeCapabilityService productTypeCapabilityService;

    @InjectMocks
    private PriceCalculationServiceImpl priceCalculationService;

    @Test
    void shouldSelectOnePriceWhenCheaper() {
        mockProductConfig(new BigDecimal("100.00"));
        when(bundleService.getBundleConfig(any()))
                .thenReturn(buildBundleConfig(new BigDecimal("80.00")));
        when(bundleDiscountService.getBestBundleDiscount(any(), eq(1L)))
                .thenReturn(buildBundleDiscountInfo(new BigDecimal("10.00")));

        UpgradeCheckRequest request = buildRequest();
        UpgradeCheckResult result = priceCalculationService.checkUpgrade(request);

        assertEquals("ONE_PRICE", result.getBestUpgradeType());
        assertEquals(new BigDecimal("80.00"), result.getBestPayableAmount());
    }

    @Test
    void shouldSelectBundleDiscountWhenCheaper() {
        mockProductConfig(new BigDecimal("100.00"));
        when(bundleService.getBundleConfig(any()))
                .thenReturn(buildBundleConfig(new BigDecimal("80.00")));
        when(bundleDiscountService.getBestBundleDiscount(any(), eq(1L)))
                .thenReturn(buildBundleDiscountInfo(new BigDecimal("30.00")));

        UpgradeCheckRequest request = buildRequest();
        UpgradeCheckResult result = priceCalculationService.checkUpgrade(request);

        assertEquals("BUNDLE_DISCOUNT", result.getBestUpgradeType());
        assertEquals(new BigDecimal("70.00"), result.getBestPayableAmount());
    }

    @Test
    void shouldReturnNullBestWhenNoUpgradeApplicable() {
        mockProductConfig(new BigDecimal("100.00"));
        when(bundleService.getBundleConfig(any()))
                .thenReturn(null);
        when(bundleDiscountService.getBestBundleDiscount(any(), eq(1L)))
                .thenReturn(null);

        UpgradeCheckRequest request = buildRequest();
        UpgradeCheckResult result = priceCalculationService.checkUpgrade(request);

        assertNull(result.getBestUpgradeType());
        assertNull(result.getBestPayableAmount());
    }

    private void mockProductConfig(BigDecimal basePrice) {
        PriceProductConfig config = new PriceProductConfig();
        config.setProductType(ProductType.PHOTO_SET.getCode());
        config.setProductId("p1");
        config.setBasePrice(basePrice);
        config.setOriginalPrice(basePrice);
        config.setProductName("照片集");

        when(productConfigService.getProductConfig(anyString(), anyString(), anyLong()))
                .thenReturn(config);
    }

    private UpgradeCheckRequest buildRequest() {
        UpgradeCheckRequest request = new UpgradeCheckRequest();
        request.setScenicId(1L);
        request.setFaceId(2L);
        request.setPaidAmount(BigDecimal.ZERO);
        request.setPurchasedProducts(List.of());
        request.setIntendingProducts(List.of(buildProductItem()));
        return request;
    }

    private ProductItem buildProductItem() {
        ProductItem item = new ProductItem();
        item.setProductType(ProductType.PHOTO_SET);
        item.setProductId("p1");
        item.setQuantity(1);
        item.setPurchaseCount(1);
        return item;
    }

    private PriceBundleConfig buildBundleConfig(BigDecimal bundlePrice) {
        PriceBundleConfig config = new PriceBundleConfig();
        config.setId(20L);
        config.setBundleName("打包购买");
        config.setBundlePrice(bundlePrice);
        config.setScenicId("1");
        config.setDescription("打包购买测试");
        return config;
    }

    private BundleDiscountInfo buildBundleDiscountInfo(BigDecimal discountAmount) {
        BundleDiscountInfo info = new BundleDiscountInfo();
        info.setBundleConfigId(30L);
        info.setBundleName("打包购买");
        info.setBundleDescription("打包购买测试");
        info.setDiscountType("FIXED_DISCOUNT");
        info.setDiscountValue(discountAmount);
        info.setActualDiscountAmount(discountAmount);
        info.setMinQuantity(1);
        info.setMinAmount(BigDecimal.ZERO);
        return info;
    }
}
