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

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.advertisement.vo.AdvertisementPageReqVO;
import com.cf.imes.module.system.controller.admin.funds.advertisement.vo.AdvertisementRePublishReqVO;
import com.cf.imes.module.system.controller.admin.funds.advertisement.vo.AdvertisementRespVO;
import com.cf.imes.module.system.controller.admin.funds.advertisement.vo.AdvertisementSaveReqVO;
import com.cf.imes.module.system.enums.advertisement.AdvertisementPositionEnum;
import com.cf.imes.module.system.service.funds.advertisement.AdvertisementService;
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.mock.web.MockMultipartFile;
import org.springframework.test.context.bean.override.mockito.MockitoBean;
import org.springframework.test.web.servlet.MockMvc;

import java.time.LocalDate;
import java.util.Collections;
import java.util.List;

import static org.mockito.ArgumentMatchers.any;
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.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.multipart;
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/28 15:05
 */
@WebMvcTest(controllers = AdvertisementController.class, excludeAutoConfiguration = SecurityAutoConfiguration.class)
class AdvertisementControllerTest extends BaseWebUnitTest {
    @Autowired
    private MockMvc mockMvc;

    @MockitoBean
    private AdvertisementService advertisementService;

    @Autowired
    private ObjectMapper objectMapper;

    @Test
    void testCreateAdvertisement() throws Exception {
        AdvertisementSaveReqVO reqVO = new AdvertisementSaveReqVO();
        reqVO.setAdName("测试广告");
        reqVO.setAdPosition(List.of(AdvertisementPositionEnum.WORKBENCH_CAROUSEL.getStatus()));
        reqVO.setAdImagePath("test.jpg");
        LocalDate now = LocalDate.now();
        reqVO.setStartTime(now);
        reqVO.setEndTime(now.plusDays(1));

        when(advertisementService.create(any())).thenReturn(101L);

        mockMvc.perform(post("/system/ad")
                        .contentType(MediaType.APPLICATION_JSON)
                        .content(objectMapper.writeValueAsString(reqVO)))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.data").value(101));

        verify(advertisementService).create(any());
    }

    @Test
    void testUpdateAdvertisement() throws Exception {
        AdvertisementSaveReqVO reqVO = new AdvertisementSaveReqVO();
        reqVO.setId(1L);
        reqVO.setAdName("测试更新广告");
        reqVO.setAdPosition(List.of(AdvertisementPositionEnum.WORKBENCH_CAROUSEL.getStatus()));
        reqVO.setAdImagePath("test.jpg");
        LocalDate now = LocalDate.now();
        reqVO.setStartTime(now);
        reqVO.setEndTime(now.plusDays(1));

        doNothing().when(advertisementService).update(any());

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

        verify(advertisementService).update(any());
    }

    @Test
    void testUploadAdImage() throws Exception {
        MockMultipartFile file = new MockMultipartFile("file", "ad.png", "image/png", "test data".getBytes());
        when(advertisementService.uploadAdImage(any())).thenReturn("https://cdn.example.com/ad.png");

        mockMvc.perform(multipart("/system/ad/image")
                        .file(file).contentType(MediaType.MULTIPART_FORM_DATA))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.data").value("https://cdn.example.com/ad.png"));

        verify(advertisementService).uploadAdImage(any());
    }

    @Test
    void testDeleteAdvertisement() throws Exception {
        mockMvc.perform(delete("/system/ad/{id}", 1L))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.data").value(true));

        verify(advertisementService).delete(1L);
    }

    @Test
    void testGetAdvertisement() throws Exception {
        AdvertisementRespVO respVO = new AdvertisementRespVO();
        respVO.setId(1L);
        respVO.setAdName("首页广告");

        when(advertisementService.get(1L)).thenReturn(respVO);

        mockMvc.perform(get("/system/ad/{id}", 1L))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.data.id").value(1L))
                .andExpect(jsonPath("$.data.adName").value("首页广告"));

        verify(advertisementService).get(1L);
    }

    @Test
    void testGetAdvertisementPage() throws Exception {
        AdvertisementPageReqVO reqVO = new AdvertisementPageReqVO();
        PageResult<AdvertisementRespVO> mockPage = new PageResult<>();
        mockPage.setTotal(1L);
        mockPage.setList(List.of(new AdvertisementRespVO().setId(1L).setAdName("分页广告")));
        when(advertisementService.getPage(any())).thenReturn(mockPage);

        mockMvc.perform(get("/system/ad/page")
                        .contentType(MediaType.APPLICATION_JSON)
                        .content(objectMapper.writeValueAsString(reqVO)))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.data.list[0].id").value(1L))
                .andExpect(jsonPath("$.data.list[0].adName").value("分页广告"));

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

    @Test
    void testGetAdvertisementByPosition() throws Exception {
        AdvertisementRespVO respVO = new AdvertisementRespVO();
        respVO.setId(1L);
        respVO.setAdName("首页banner");

        when(advertisementService.getAdvertisementByPosition(1))
                .thenReturn(Collections.singletonList(respVO));

        mockMvc.perform(get("/system/ad/position/page")
                        .param("adPosition", "1"))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.data[0].id").value(1L))
                .andExpect(jsonPath("$.data[0].adName").value("首页banner"));

        verify(advertisementService).getAdvertisementByPosition(1);
    }

    @Test
    void testPublish() throws Exception {
        mockMvc.perform(post("/system/ad/publish/{id}", 1L))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.data").value(true));

        verify(advertisementService).publish(1L);
    }

    @Test
    void testEndPublish() throws Exception {
        mockMvc.perform(post("/system/ad/endPublish/{id}", 1L))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.data").value(true));

        verify(advertisementService).endPublish(1L);
    }

    @Test
    void testRePublish() throws Exception {
        AdvertisementRePublishReqVO reqVO = new AdvertisementRePublishReqVO();
        reqVO.setId(1L);
        reqVO.setStartTime(LocalDate.now());
        reqVO.setEndTime(LocalDate.now().plusDays(1));

        mockMvc.perform(post("/system/ad/republish")
                        .contentType(MediaType.APPLICATION_JSON)
                        .content(objectMapper.writeValueAsString(reqVO)))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.data").value(true));

        verify(advertisementService).republish(any());
    }
}
