package com.cf.imes.module.system.controller.admin.funds.products;

import com.cf.imes.framework.common.pojo.PageResult;
import com.cf.imes.framework.test.core.ut.BaseWebUnitTest;
import com.cf.imes.module.system.controller.admin.funds.products.vo.productDetails.ProductDetailsPageReqVO;
import com.cf.imes.module.system.controller.admin.funds.products.vo.productDetails.ProductDetailsRespVO;
import com.cf.imes.module.system.controller.admin.funds.products.vo.productDetails.ProductDetailsSaveReqVO;
import com.cf.imes.module.system.dal.dataobject.funds.products.ProductsDetailDO;
import com.cf.imes.module.system.enums.pay.ProductDurationUnitEnum;
import com.cf.imes.module.system.service.funds.products.ProductsDetailService;
import com.cf.imes.module.system.service.funds.purchase.PurchaseService;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.http.MediaType;
import org.springframework.test.context.bean.override.mockito.MockitoBean;
import org.springframework.test.web.servlet.MockMvc;

import java.math.BigDecimal;
import java.util.List;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

/**
 * @author Gqr
 * @since 2025/10/24 9:41
 */
@WebMvcTest(controllers = ProductsDetailController.class, excludeAutoConfiguration = SecurityAutoConfiguration.class)
class ProductsDetailControllerTest extends BaseWebUnitTest {
    @Autowired
    private MockMvc mockMvc;

    @MockitoBean
    private ProductsDetailService productsDetailService;

    @MockitoBean
    private PurchaseService purchaseService;

    @Autowired
    private ObjectMapper objectMapper;

    @Test
    void testCreateProductDetails() throws Exception {
        ProductDetailsSaveReqVO vo = new ProductDetailsSaveReqVO();
        vo.setProductId(123L);
        vo.setDuration(1);
        vo.setDurationUnit(ProductDurationUnitEnum.YEAR.getCode());
        vo.setDiscount(BigDecimal.valueOf(100));

        // mock Service 返回
        when(productsDetailService.create(any())).thenReturn(100L);

        mockMvc.perform(post("/system/product-details")
                        .contentType(MediaType.APPLICATION_JSON)
                        .content(objectMapper.writeValueAsString(vo)))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.data").value(100));

        // 验证 Service 调用
        verify(productsDetailService, times(1)).create(any());
    }

    @Test
    void testUpdateProductDetails() throws Exception {
        ProductDetailsSaveReqVO vo = new ProductDetailsSaveReqVO();
        vo.setId(1L);
        vo.setProductId(123L);
        vo.setDuration(2);
        vo.setDurationUnit(ProductDurationUnitEnum.YEAR.getCode());
        vo.setDiscount(BigDecimal.valueOf(80));

        // mock Service 方法 void 不做实际处理
        doNothing().when(productsDetailService).update(any());

        mockMvc.perform(put("/system/product-details")
                        .contentType(MediaType.APPLICATION_JSON)
                        .content(objectMapper.writeValueAsString(vo)))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.data").value(true));

        verify(productsDetailService, times(1)).update(any());
    }

    @Test
    void testDeleteProductDetails() throws Exception {
        Long id = 3L;
        doNothing().when(productsDetailService).delete(anyLong());

        mockMvc.perform(delete("/system/product-details")
                        .param("id", id.toString()))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.data").value(true));

        verify(productsDetailService, times(1)).delete(id);
    }

    @Test
    void testGetProducts() throws Exception {
        Long id = 4L;
        ProductsDetailDO mockProduct = new ProductsDetailDO()
                .setId(id)
                .setProductId(123L);
        when(productsDetailService.get(id)).thenReturn(mockProduct);

        mockMvc.perform(get("/system/product-details/{id}", id))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.data.productId").value(123L));

        verify(productsDetailService, times(1)).get(id);
    }

    @Test
    void testGetProductsPage() throws Exception {
        ProductDetailsPageReqVO reqVO = new ProductDetailsPageReqVO();
        PageResult<ProductsDetailDO> mockPage = new PageResult<>();
        mockPage.setTotal(1L);
        mockPage.setList(List.of(new ProductsDetailDO().setId(1L).setProductId(123L)));
        when(productsDetailService.getPage(any())).thenReturn(mockPage);

        mockMvc.perform(get("/system/product-details/page")
                        .contentType(MediaType.APPLICATION_JSON)
                        .content(objectMapper.writeValueAsString(reqVO)))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.data.list[0].productId").value(123L));

        verify(productsDetailService, times(1)).getPage(any());
    }


    @Test
    void testGetOrgProductDetailList() throws Exception {
        // 模拟返回数据
        ProductDetailsRespVO mockVO = new ProductDetailsRespVO();
        mockVO.setId(1L);
        mockVO.setProductId(1001L);
        List<ProductDetailsRespVO> mockList = List.of(mockVO);

        // Mock Service 层行为
        when(purchaseService.getOrgProductDetailList(anyLong(), anyLong()))
                .thenReturn(mockList);

        // 执行请求
        mockMvc.perform(get("/system/product-details/organ/purchase")
                        .param("organId", "100")
                        .param("productId", "200")
                        .contentType(MediaType.APPLICATION_JSON))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.code").value(0))
                .andExpect(jsonPath("$.data[0].productId").value(1001))
                .andExpect(jsonPath("$.data[0].id").value(1L));

        // 验证 Service 是否被正确调用一次
        verify(purchaseService, times(1)).getOrgProductDetailList(100L, 200L);
    }

}
