package com.cf.imes.module.system.controller.admin.dict;

import com.cf.imes.framework.common.enums.CommonStatusEnum;
import com.cf.imes.framework.common.pojo.PageResult;
import com.cf.imes.framework.excel.core.util.ExcelUtils;
import com.cf.imes.framework.test.core.ut.BaseWebUnitTest;
import com.cf.imes.module.system.controller.admin.dict.vo.type.DictTypeRespVO;
import com.cf.imes.module.system.controller.admin.dict.vo.type.DictTypeSaveReqVO;
import com.cf.imes.module.system.dal.dataobject.dict.DictTypeDO;
import com.cf.imes.module.system.service.dict.DictTypeService;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.http.HttpServletResponse;
import org.junit.jupiter.api.Test;
import org.mockito.MockedStatic;
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.util.List;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyList;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.mockStatic;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
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 2026/1/14 17:25
 */
@WebMvcTest(controllers = DictTypeController.class, excludeAutoConfiguration = SecurityAutoConfiguration.class)
class DictTypeControllerTest extends BaseWebUnitTest {
    @Autowired
    private MockMvc mockMvc;

    @MockitoBean
    private DictTypeService dictTypeService;

    @Autowired
    private ObjectMapper objectMapper;

    @Test
    void testCreateDictType_success() throws Exception {
        DictTypeSaveReqVO reqVO = new DictTypeSaveReqVO();
        reqVO.setName("测试类型");
        reqVO.setType("test_type");
        reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus());

        when(dictTypeService.createDictType(any())).thenReturn(100L);

        mockMvc.perform(post("/system/dict-type/create")
                        .contentType(MediaType.APPLICATION_JSON)
                        .content(objectMapper.writeValueAsString(reqVO)))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.data").value(100));

        verify(dictTypeService).createDictType(any());
    }

    @Test
    void testUpdateDictType_success() throws Exception {
        DictTypeSaveReqVO reqVO = new DictTypeSaveReqVO();
        reqVO.setId(1L);
        reqVO.setName("类型B");
        reqVO.setType("typeB");
        reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus());

        doNothing().when(dictTypeService).updateDictType(any());

        mockMvc.perform(put("/system/dict-type/update")
                        .contentType(MediaType.APPLICATION_JSON)
                        .content(objectMapper.writeValueAsString(reqVO)))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.data").value(true));

        verify(dictTypeService).updateDictType(any());
    }

    @Test
    void testDeleteDictType_success() throws Exception {
        doNothing().when(dictTypeService).deleteDictType(1L);

        mockMvc.perform(delete("/system/dict-type/delete")
                        .param("id", "1"))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.data").value(true));

        verify(dictTypeService).deleteDictType(1L);
    }


    @Test
    void testPageDictTypes_success() throws Exception {
        PageResult<DictTypeDO> pageResult = new PageResult<>();
        DictTypeDO dictTypeDO = new DictTypeDO();
        dictTypeDO.setId(1L);
        dictTypeDO.setName("类型C");
        dictTypeDO.setType("typeC");
        pageResult.setList(List.of(dictTypeDO));
        pageResult.setTotal(1L);

        when(dictTypeService.getDictTypePage(any())).thenReturn(pageResult);

        mockMvc.perform(get("/system/dict-type/page")
                        .param("pageNo", "1")
                        .param("pageSize", "10"))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.data.list[0].id").value(1))
                .andExpect(jsonPath("$.data.list[0].name").value("类型C"))
                .andExpect(jsonPath("$.data.list[0].type").value("typeC"));
    }

    @Test
    void testGetDictType_success() throws Exception {
        DictTypeDO dictTypeDO = new DictTypeDO();
        dictTypeDO.setId(1L);
        dictTypeDO.setName("类型D");
        dictTypeDO.setType("typeD");

        when(dictTypeService.getDictType(1L)).thenReturn(dictTypeDO);

        mockMvc.perform(get("/system/dict-type/get")
                        .param("id", "1"))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.data.id").value(1))
                .andExpect(jsonPath("$.data.name").value("类型D"))
                .andExpect(jsonPath("$.data.type").value("typeD"));
    }

    @Test
    void testGetSimpleDictTypeList_success() throws Exception {
        DictTypeDO dictTypeDO = new DictTypeDO();
        dictTypeDO.setId(1L);
        dictTypeDO.setName("类型E");
        dictTypeDO.setType("typeE");

        when(dictTypeService.getDictTypeList()).thenReturn(List.of(dictTypeDO));

        mockMvc.perform(get("/system/dict-type/list-all-simple"))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.data[0].id").value(1))
                .andExpect(jsonPath("$.data[0].name").value("类型E"))
                .andExpect(jsonPath("$.data[0].type").value("typeE"));
    }

    @Test
    void testExport_success() throws Exception {
        // mock Service 返回分页数据
        DictTypeDO dictTypeDO = new DictTypeDO();
        dictTypeDO.setId(1L);
        dictTypeDO.setName("类型A");
        dictTypeDO.setType("typeA");

        PageResult<DictTypeDO> pageResult = new PageResult<>();
        pageResult.setList(List.of(dictTypeDO));
        when(dictTypeService.getDictTypePage(any())).thenReturn(pageResult);

        // mock ExcelUtils.write 静态方法
        try (MockedStatic<ExcelUtils> excelMock = mockStatic(ExcelUtils.class)) {

            mockMvc.perform(get("/system/dict-type/export")
                            .param("pageNo", "1")
                            .param("pageSize", "10"))
                    .andExpect(status().isOk());

            // 验证 ExcelUtils.write 被调用
            excelMock.verify(() -> ExcelUtils.write(
                    any(HttpServletResponse.class),
                    eq("字典类型.xls"),
                    eq("数据"),
                    eq(DictTypeRespVO.class),
                    anyList()
            ));
        }

        // 验证 Service 被调用
        verify(dictTypeService).getDictTypePage(any());
    }
}
