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

import com.cf.imes.framework.common.enums.CommonStatusEnum;
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.sms.vo.template.SmsTemplateSaveReqVO;
import com.cf.imes.module.system.controller.admin.sms.vo.template.SmsTemplateSendReqVO;
import com.cf.imes.module.system.dal.dataobject.sms.SmsTemplateDO;
import com.cf.imes.module.system.enums.sms.SmsTemplateTypeEnum;
import com.cf.imes.module.system.service.sms.SmsSendService;
import com.cf.imes.module.system.service.sms.SmsTemplateService;
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.util.List;
import java.util.Map;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyMap;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isNull;
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.put;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
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.result.MockMvcResultMatchers.header;
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/11 16:26
 */
@WebMvcTest(controllers = SmsTemplateController.class, excludeAutoConfiguration = SecurityAutoConfiguration.class)
class SmsTemplateControllerTest extends BaseWebUnitTest {
    @Autowired
    private MockMvc mockMvc;

    @MockitoBean
    private SmsTemplateService smsTemplateService;

    @MockitoBean
    private SmsSendService smsSendService;

    @Autowired
    private ObjectMapper objectMapper;

    // ========== create ==========
    @Test
    void testCreateSmsTemplate() throws Exception {
        SmsTemplateSaveReqVO req = new SmsTemplateSaveReqVO();
        req.setCode("REGISTER_CODE");
        req.setName("注册验证码");
        req.setContent("您的验证码是{code}");
        req.setType(SmsTemplateTypeEnum.NOTICE.getType());
        req.setStatus(CommonStatusEnum.ENABLE.getStatus());
        req.setApiTemplateId("TEMPLATE_001");

        when(smsTemplateService.createSmsTemplate(any())).thenReturn(1L);

        mockMvc.perform(post("/system/sms-template/create")
                        .contentType(MediaType.APPLICATION_JSON)
                        .content(objectMapper.writeValueAsString(req)))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.data").value(1));

        verify(smsTemplateService, times(1)).createSmsTemplate(any());
    }

    // ========== update ==========
    @Test
    void testUpdateSmsTemplate() throws Exception {
        SmsTemplateSaveReqVO req = new SmsTemplateSaveReqVO();
        req.setId(100L);
        req.setCode("REGISTER_CODE");
        req.setName("注册验证码");
        req.setContent("您的验证码是{code}");
        req.setType(SmsTemplateTypeEnum.NOTICE.getType());
        req.setStatus(CommonStatusEnum.ENABLE.getStatus());
        req.setApiTemplateId("TEMPLATE_001");

        doNothing().when(smsTemplateService).updateSmsTemplate(any());

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

        verify(smsTemplateService, times(1)).updateSmsTemplate(any());
    }

    // ========== delete ==========
    @Test
    void testDeleteSmsTemplate() throws Exception {
        doNothing().when(smsTemplateService).deleteSmsTemplate(1L);

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

        verify(smsTemplateService, times(1)).deleteSmsTemplate(1L);
    }

    // ========== get ==========
    @Test
    void testGetSmsTemplate() throws Exception {
        SmsTemplateDO templateDO = new SmsTemplateDO();
        templateDO.setId(1L);
        templateDO.setCode("REGISTER_CODE");
        templateDO.setName("注册验证码");
        when(smsTemplateService.getSmsTemplate(1L)).thenReturn(templateDO);

        mockMvc.perform(get("/system/sms-template/get")
                        .param("id", "1"))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.data.code").value("REGISTER_CODE"))
                .andExpect(jsonPath("$.data.name").value("注册验证码"));

        verify(smsTemplateService, times(1)).getSmsTemplate(1L);
    }

    // ========== page ==========
    @Test
    void testGetSmsTemplatePage() throws Exception {
        SmsTemplateDO templateDO = new SmsTemplateDO();
        templateDO.setCode("REGISTER_CODE");
        PageResult<SmsTemplateDO> pageResult = new PageResult<>(List.of(templateDO), 1L);
        when(smsTemplateService.getSmsTemplatePage(any())).thenReturn(pageResult);

        mockMvc.perform(get("/system/sms-template/page")
                        .param("pageNo", "1")
                        .param("pageSize", "10"))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.data.list[0].code").value("REGISTER_CODE"));

        verify(smsTemplateService, times(1)).getSmsTemplatePage(any());
    }

    // ========== send-sms ==========
    @Test
    void testSendSms() throws Exception {
        SmsTemplateSendReqVO sendReqVO = new SmsTemplateSendReqVO();
        sendReqVO.setMobile("13800000000");
        sendReqVO.setTemplateCode("SMS_CODE");
        sendReqVO.setTemplateParams(Map.of("code", "123456"));

        when(smsSendService.sendSingleSms(anyString(), isNull(), anyInt(), anyString(), anyMap()))
                .thenReturn(123L);

        mockMvc.perform(post("/system/sms-template/send-sms")
                        .contentType(MediaType.APPLICATION_JSON)
                        .content(objectMapper.writeValueAsString(sendReqVO)))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.data").value(123));

        verify(smsSendService, times(1)).sendSingleSms(
                eq("13800000000"),
                isNull(),
                anyInt(),
                eq("SMS_CODE"),
                anyMap()
        );
    }

    // ========== export ==========
    @Test
    void testExportSmsTemplateExcel() throws Exception {
        SmsTemplateDO templateDO = new SmsTemplateDO();
        templateDO.setId(1L);
        templateDO.setCode("REGISTER_CODE");
        templateDO.setName("注册验证码");
        PageResult<SmsTemplateDO> pageResult = new PageResult<>(List.of(templateDO), 1L);
        when(smsTemplateService.getSmsTemplatePage(any())).thenReturn(pageResult);
        mockMvc.perform(get("/system/sms-template/export-excel")
                        .contentType(MediaType.APPLICATION_JSON)
                        .param("pageNo", "1")
                        .param("pageSize", "10"))
                .andExpect(status().isOk())
                // 校验响应头是下载 Excel 文件
                .andExpect(header().string("Content-Disposition", org.hamcrest.Matchers.containsString("attachment")));
    }
}
