package com.ruoyi.web.modules.screen.controller;

import static org.mockito.Mockito.when;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.junit.jupiter.MockitoSettings;
import org.mockito.quality.Strictness;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import com.github.pagehelper.PageHelper;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.web.modules.screen.domain.vo.EpidemicRiskScreenDashboardVo;
import com.ruoyi.web.modules.screen.domain.vo.EpidemicSituationVo;
import com.ruoyi.web.modules.screen.domain.vo.LabDetectionMonthlyVo;
import com.ruoyi.web.modules.screen.domain.vo.LabDetectionScreenVo;
import com.ruoyi.web.modules.screen.domain.vo.RiskFactorWeightsVo;
import com.ruoyi.web.modules.screen.domain.vo.RiskLevelStatVo;
import com.ruoyi.web.modules.screen.domain.vo.ScreenEpidemicReportListItemVo;
import com.ruoyi.web.modules.screen.service.IEpidemicRiskScreenService;
import com.ruoyi.web.modules.screen.support.EpidemicRiskScreenSupport;

/**
 * DP-DYFX-API-001～019
 */
@ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.LENIENT)
@DisplayName("大屏疫病风险 HTTP 接口 MockMvc")
class EpidemicRiskScreenControllerApiTest
{

    @Mock
    private IEpidemicRiskScreenService epidemicRiskScreenService;

    @InjectMocks
    private EpidemicRiskScreenController controller;

    private MockMvc mockMvc;

    @BeforeEach
    void setUp()
    {
        mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
        loginAsAllPermissions();
    }

    @AfterEach
    void tearDown()
    {
        SecurityContextHolder.clearContext();
        PageHelper.clearPage();
    }

    private static void loginAsAllPermissions()
    {
        SysUser u = new SysUser();
        u.setUserId(1L);
        u.setUserName("tester");
        u.setPassword("x");
        Set<String> perms = new HashSet<>();
        perms.add(Constants.ALL_PERMISSION);
        LoginUser lu = new LoginUser(1L, 100L, u, perms);
        UsernamePasswordAuthenticationToken auth =
                new UsernamePasswordAuthenticationToken(lu, "", lu.getAuthorities());
        SecurityContextHolder.getContext().setAuthentication(auth);
    }

    @Test
    @DisplayName("DP-DYFX-API-001 GET dashboard 有数据")
    void api001_dashboardWithData() throws Exception
    {
        when(epidemicRiskScreenService.loadDashboard("2026")).thenReturn(sampleDashboard(true, true, true));
        mockMvc.perform(get("/bigScreen/epidemicRisk/dashboard").param("statYear", "2026"))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.code").value(200))
                .andExpect(jsonPath("$.data.statYear").value(2026))
                .andExpect(jsonPath("$.data.hasLabData").value(true))
                .andExpect(jsonPath("$.data.hasEpidemicData").value(true))
                .andExpect(jsonPath("$.data.labDetection.monthly.length()").value(12));
    }

    @Test
    @DisplayName("DP-DYFX-API-011 全年无检测")
    void api011_noLab() throws Exception
    {
        when(epidemicRiskScreenService.loadDashboard("2026")).thenReturn(sampleDashboard(false, false, false));
        mockMvc.perform(get("/bigScreen/epidemicRisk/dashboard").param("statYear", "2026"))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.data.hasLabData").value(false))
                .andExpect(jsonPath("$.data.labDetection").doesNotExist());
    }

    @Test
    @DisplayName("DP-DYFX-API-012 全年无疫情")
    void api012_noEpidemic() throws Exception
    {
        EpidemicRiskScreenDashboardVo vo = sampleDashboard(true, false, false);
        when(epidemicRiskScreenService.loadDashboard("2026")).thenReturn(vo);
        mockMvc.perform(get("/bigScreen/epidemicRisk/dashboard").param("statYear", "2026"))
                .andExpect(jsonPath("$.data.hasEpidemicData").value(false));
    }

    @Test
    @DisplayName("DP-DYFX-API-016 缺 statYear")
    void api016_missingStatYear() throws Exception
    {
        mockMvc.perform(get("/bigScreen/epidemicRisk/dashboard"))
                .andExpect(status().isBadRequest());
    }

    @Test
    @DisplayName("DP-DYFX-API-018 statYear 回显")
    void api018_statYearEcho() throws Exception
    {
        EpidemicRiskScreenDashboardVo vo = sampleDashboard(true, true, false);
        vo.setStatYear(2025);
        when(epidemicRiskScreenService.loadDashboard("2025")).thenReturn(vo);
        mockMvc.perform(get("/bigScreen/epidemicRisk/dashboard").param("statYear", "2025"))
                .andExpect(jsonPath("$.data.statYear").value(2025));
    }

    @Test
    @DisplayName("DP-DYFX-API-005 风险等级结构")
    void api005_riskLevelStats() throws Exception
    {
        when(epidemicRiskScreenService.loadDashboard("2026")).thenReturn(sampleDashboard(false, true, false));
        mockMvc.perform(get("/bigScreen/epidemicRisk/dashboard").param("statYear", "2026"))
                .andExpect(jsonPath("$.data.riskLevelStats[0].riskLevelName").value("高危"));
    }

    @Test
    @DisplayName("DP-DYFX-API-023 GET reports 列表")
    void api023_reportsList() throws Exception
    {
        ScreenEpidemicReportListItemVo item = new ScreenEpidemicReportListItemVo();
        item.setId(1L);
        item.setEpidemicName("口蹄疫");
        item.setRiskLevelName("高危");
        when(epidemicRiskScreenService.listReportsByReportYear("2026")).thenReturn(Collections.singletonList(item));
        mockMvc.perform(get("/bigScreen/epidemicRisk/reports").param("statYear", "2026"))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.code").value(200))
                .andExpect(jsonPath("$.rows[0].epidemicName").value("口蹄疫"));
    }

    @Test
    @DisplayName("DP-DYFX-API-027 空列表")
    void api027_emptyReports() throws Exception
    {
        when(epidemicRiskScreenService.listReportsByReportYear("2026")).thenReturn(Collections.emptyList());
        mockMvc.perform(get("/bigScreen/epidemicRisk/reports").param("statYear", "2026"))
                .andExpect(jsonPath("$.rows").isEmpty());
    }

    private static EpidemicRiskScreenDashboardVo sampleDashboard(boolean hasLab, boolean hasEpidemic,
            boolean hasRelieved)
    {
        EpidemicRiskScreenDashboardVo vo = new EpidemicRiskScreenDashboardVo();
        vo.setStatYear(2026);
        vo.setAvailableYears(Arrays.asList(2026, 2025));
        vo.setHasLabData(hasLab);
        vo.setHasEpidemicData(hasEpidemic);
        vo.setHasRelievedData(hasRelieved);
        if (hasLab)
        {
            LabDetectionScreenVo lab = new LabDetectionScreenVo();
            lab.setTestQuantityTotal(100);
            lab.setPositiveCountTotal(10);
            lab.setPositiveRate(new BigDecimal("0.1000"));
            List<LabDetectionMonthlyVo> monthly = new ArrayList<>(12);
            for (int i = 1; i <= 12; i++)
            {
                LabDetectionMonthlyVo m = new LabDetectionMonthlyVo();
                m.setMonth(i);
                m.setTestQuantity(i == 1 ? 100 : 0);
                m.setPositiveCount(i == 1 ? 10 : 0);
                monthly.add(m);
            }
            lab.setMonthly(monthly);
            vo.setLabDetection(lab);
            vo.setSampleSourceStats(EpidemicRiskScreenSupport.buildSampleSourceStats(Collections.emptyList(), true));
        }
        vo.setRiskLevelStats(EpidemicRiskScreenSupport.buildRiskLevelStats(
                hasEpidemic ? Collections.singletonList(com.ruoyi.web.modules.epidemic.EpidemicReportTestSamples.sampleOpen())
                        : Collections.emptyList()));
        EpidemicSituationVo situation = new EpidemicSituationVo();
        situation.setAvailableQuarantinePointCount(2);
        situation.setDisabledQuarantinePointCount(1);
        vo.setEpidemicSituation(situation);
        vo.setEpidemicTypeStats(EpidemicRiskScreenSupport.buildEpidemicTypeStats(Collections.emptyList()));
        vo.setTransmissionRouteStats(EpidemicRiskScreenSupport.buildTransmissionRouteStats(Collections.emptyList()));
        vo.setRelieveDurationByType(EpidemicRiskScreenSupport.buildRelieveDurationByType(Collections.emptyList()));
        RiskFactorWeightsVo rf = new RiskFactorWeightsVo();
        rf.setHasRiskFactorConfig(false);
        rf.setItems(Collections.emptyList());
        vo.setRiskFactorWeights(rf);
        return vo;
    }
}
