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

import com.cf.imes.framework.test.core.ut.BaseWebUnitTest;
import com.cf.imes.module.system.controller.admin.dept.vo.dept.DeptListReqVO;
import com.cf.imes.module.system.controller.admin.dept.vo.dept.DeptSaveReqVO;
import com.cf.imes.module.system.dal.dataobject.dept.DeptDO;
import com.cf.imes.module.system.service.dept.DeptService;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
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.Mockito.when;
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.request.MockMvcRequestBuilders.delete;
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/10 10:32
 */
@WebMvcTest(controllers = DeptController.class, excludeAutoConfiguration = SecurityAutoConfiguration.class)
class DeptControllerTest extends BaseWebUnitTest {
    @Autowired
    private MockMvc mockMvc;

    @MockitoBean
    private DeptService deptService;

    @Autowired
    private ObjectMapper objectMapper;

    private DeptSaveReqVO deptSaveReqVO;

    @BeforeEach
    void setup() {
        deptSaveReqVO = new DeptSaveReqVO();
        deptSaveReqVO.setName("测试部门");      // @NotBlank + @Size
        deptSaveReqVO.setParentId(1L);         // @NotNull
        deptSaveReqVO.setSort(1);               // @NotNull + @NumberValid
        deptSaveReqVO.setPhone("15601691000");  // @NotEmpty + @Mobile
        deptSaveReqVO.setEmail("test@cf.com");  // @NotEmpty + @Email
        deptSaveReqVO.setStatus(1);             // @NotNull + @CommonStatus
        deptSaveReqVO.setOrganId(100L);         // 可选字段
        deptSaveReqVO.setLeader("负责人");      // 可选字段
    }

    @Test
    void testCreateDept() throws Exception {
        when(deptService.createDept(any())).thenReturn(123L);

        mockMvc.perform(post("/system/dept/create")
                        .contentType(MediaType.APPLICATION_JSON)
                        .header("Authorization", "123")
                        .content(objectMapper.writeValueAsString(deptSaveReqVO)))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.data").value(123));
    }

    @Test
    void testUpdateDept() throws Exception {
        Mockito.doNothing().when(deptService).updateDept(any());

        mockMvc.perform(put("/system/dept/update")
                        .contentType(MediaType.APPLICATION_JSON)
                        .content(objectMapper.writeValueAsString(deptSaveReqVO)))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.data").value(true));
    }

    @Test
    void testDeleteDept() throws Exception {
        Mockito.doNothing().when(deptService).deleteDept(1024L);

        mockMvc.perform(delete("/system/dept/delete")
                        .param("id", "1024"))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.data").value(true));
    }

    @Test
    void testGetDeptList() throws Exception {
        DeptDO dept = new DeptDO().setId(1L).setName("测试部门").setStatus(1);
        when(deptService.getDeptList(any(DeptListReqVO.class)))
                .thenReturn(List.of(dept));

        mockMvc.perform(get("/system/dept/list")
                        .param("organId", "100")
                        .param("status", "1"))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.data[0].name").value("测试部门"));
    }

    @Test
    void testGetAllSimpleDeptList_withOrganId() throws Exception {
        DeptDO dept = new DeptDO().setId(2L).setName("精简部门").setStatus(1);

        // Mock getDeptList(DeptListReqVO)
        when(deptService.getDeptList(any(DeptListReqVO.class)))
                .thenReturn(List.of(dept));

        // Mock removeUnowndDept
        when(deptService.removeUnowndDept(any()))
                .thenReturn(List.of(dept));

        // 构造请求 VO，并设置 organId 不为 null
        DeptListReqVO reqVO = new DeptListReqVO();
        reqVO.setOrganId(100L);

        mockMvc.perform(get("/system/dept/list-all-simple")
                        .param("organId", reqVO.getOrganId().toString()))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.data[0].name").value("精简部门"));
    }

    @Test
    void testGetAllSimpleDeptList_withoutOrganId() throws Exception {
        DeptDO dept = new DeptDO().setId(2L).setName("精简部门").setStatus(1);

        when(deptService.getDeptList(any(DeptListReqVO.class)))
                .thenReturn(List.of(dept));
        when(deptService.removeUnowndDept(any()))
                .thenReturn(List.of(dept));

        // 不传 organId，触发 else 分支
        mockMvc.perform(get("/system/dept/list-all-simple"))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.data[0].name").value("精简部门"));
    }

    @Test
    void testGetSimpleDeptList_withNullOrganId() throws Exception {
        // 不传 organId，触发 if 分支
        mockMvc.perform(get("/system/dept/simple-list"))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.data").isArray())
                .andExpect(jsonPath("$.data").isEmpty());
    }

    @Test
    void testGetSimpleDeptList_withOrganId() throws Exception {
        DeptDO dept = new DeptDO().setId(3L).setName("简单部门").setStatus(1);

        // Mock getDeptList(DeptListReqVO)
        when(deptService.getDeptList(any(DeptListReqVO.class)))
                .thenReturn(List.of(dept));
        when(deptService.removeUnowndDept(any()))
                .thenReturn(List.of(dept));

        // 传入 organId，触发 else 分支
        mockMvc.perform(get("/system/dept/simple-list")
                        .param("organId", "100"))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.data[0].name").value("简单部门"));
    }

    @Test
    void testGetDept() throws Exception {
        // 准备 DeptDO 返回对象
        DeptDO dept = new DeptDO()
                .setId(1024L)
                .setName("测试部门")
                .setStatus(1);

        // Mock deptService.getDept 方法
        when(deptService.getDept(1024L)).thenReturn(dept);

        // 发起 GET 请求
        mockMvc.perform(get("/system/dept/get")
                        .param("id", "1024"))  // 注意 GET 查询参数
                .andExpect(status().isOk())  // 返回 200
                .andExpect(jsonPath("$.data.id").value(1024))
                .andExpect(jsonPath("$.data.name").value("测试部门"));
    }

}
