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

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import com.ruoyi.web.modules.screen.domain.dto.LivestockResourceBandCountDto;
import com.ruoyi.web.modules.screen.domain.dto.LivestockResourceCategoryCountDto;
import com.ruoyi.web.modules.screen.domain.dto.LivestockResourceDateCountDto;
import com.ruoyi.web.modules.screen.domain.dto.LivestockResourceOverviewDto;
import com.ruoyi.web.modules.screen.domain.dto.LivestockResourceUserStructureDto;
import com.ruoyi.web.modules.screen.domain.vo.LivestockResourceActivityTrendVo;
import com.ruoyi.web.modules.screen.domain.vo.LivestockResourceCategoryItemVo;
import com.ruoyi.web.modules.screen.domain.vo.LivestockResourceCategoryShareVo;
import com.ruoyi.web.modules.screen.domain.vo.LivestockResourceHourlyHeatVo;
import com.ruoyi.web.modules.screen.domain.vo.LivestockResourceOverviewVo;
import com.ruoyi.web.modules.screen.domain.vo.LivestockResourceReplyStatusVo;

/**
 * DP-XM-UT-003～020
 */
@DisplayName("LivestockResourceScreenSupport")
class LivestockResourceScreenSupportTest
{
    @Test
    @DisplayName("DP-XM-UT-004 历史年 statDate")
    void ut004_historicalStatDate()
    {
        assertEquals(LocalDate.of(2024, 12, 31), HomeScreenSupport.resolveStatDate(2024));
    }

    @Test
    @DisplayName("DP-XM-UT-008 历史年今日为 0")
    void ut008_todayZeroWhenNotCurrentYear()
    {
        LivestockResourceOverviewDto year = yearMetrics(10L, 5L, 20L, 1500.0);
        LivestockResourceOverviewVo vo = LivestockResourceScreenSupport.buildOverview(
                year, 8L, 2L, 3L, 4L, false);
        assertEquals(0, vo.getTodayActiveUsers());
        assertEquals(0, vo.getTodayNewUsers());
        assertEquals(0, vo.getTodaySessions());
        assertEquals(0, vo.getTodayQuestionCount());
        assertEquals(10, vo.getTotalUsers());
    }

    @Test
    @DisplayName("DP-XM-UT-010 平均耗时含 0")
    void ut010_avgIncludesZero()
    {
        LivestockResourceOverviewDto year = yearMetrics(1L, 1L, 2L, 0.0);
        LivestockResourceOverviewVo vo = LivestockResourceScreenSupport.buildOverview(
                year, null, null, null, null, false);
        assertEquals(new BigDecimal("0.0"), vo.getAvgResponseSeconds());
    }

    @Test
    @DisplayName("DP-XM-UT-011 7 日补零")
    void ut011_dailySevenPoints()
    {
        LivestockResourceDateCountDto d1 = dayCount("2026-05-14", 3L);
        LivestockResourceActivityTrendVo trend = LivestockResourceScreenSupport.buildActivityTrend(
                Collections.singletonList(d1),
                Collections.emptyList(),
                LocalDate.of(2026, 5, 20));
        assertEquals(7, trend.getDailySeries().size());
        assertEquals(3L, trend.getDailySeries().get(0).getSessionCount());
        assertEquals("2026-05-14", trend.getDailySeries().get(0).getDate());
        assertEquals(0L, trend.getDailySeries().get(6).getSessionCount());
        assertEquals("2026-05-20", trend.getDailySeries().get(6).getDate());
    }

    @Test
    @DisplayName("DP-XM-UT-012 统计日 24 自然小时桶")
    void ut012_hourlyTwentyFour()
    {
        LivestockResourceHourlyHeatVo heat = LivestockResourceScreenSupport.buildHourlyHeat(
                Collections.singletonList(hourCount("10", 2L)),
                Collections.singletonList(hourCount("10", 5L)),
                LocalDate.of(2026, 5, 20));
        assertEquals(24, heat.getHourlySeries().size());
        assertEquals("2026-05-20", heat.getWindowEnd());
        assertEquals("10:00", heat.getHourlySeries().get(10).getBucketStart());
        assertEquals(2L, heat.getHourlySeries().get(10).getSessionCount());
        assertEquals(5L, heat.getHourlySeries().get(10).getQuestionCount());
    }

    @Test
    @DisplayName("DP-XM-UT-013 用户结构 180 天")
    void ut013_userStructure()
    {
        LivestockResourceUserStructureDto raw = new LivestockResourceUserStructureDto();
        raw.setNewUserCount(3L);
        raw.setOldUserCount(2L);
        com.ruoyi.web.modules.screen.domain.vo.LivestockResourceUserStructureVo vo =
                LivestockResourceScreenSupport.buildUserStructure(raw);
        assertEquals(3, vo.getNewUserCount());
        assertEquals(new BigDecimal("60.0"), vo.getNewUserRatio());
        assertEquals(new BigDecimal("40.0"), vo.getOldUserRatio());
    }

    @Test
    @DisplayName("DP-XM-UT-015 分类占比 100%")
    void ut015_categoryRatioSum()
    {
        List<LivestockResourceCategoryCountDto> rows = Arrays.asList(
                cat("1", 40L),
                cat("2", 30L),
                cat("UNCAT", 30L));
        LivestockResourceCategoryShareVo share = LivestockResourceScreenSupport.buildCategoryShare(rows, 100L);
        assertEquals(5, share.getItems().size());
        double sum = share.getItems().stream().mapToDouble(i -> i.getRatio().doubleValue()).sum();
        assertEquals(100.0, sum, 0.2);
    }

    @Test
    @DisplayName("DP-XM-UT-017 会话分档四档")
    void ut017_sessionBands()
    {
        List<LivestockResourceBandCountDto> rows = Arrays.asList(
                band(LivestockResourceScreenRules.BAND_LIGHT, 2L),
                band(LivestockResourceScreenRules.BAND_DEEP, 1L));
        List<com.ruoyi.web.modules.screen.domain.vo.LivestockResourceSessionBandVo> list =
                LivestockResourceScreenSupport.buildSessionReplyDistribution(rows, 10L);
        assertEquals(4, list.size());
        assertEquals(2L, list.get(0).getSessionCount());
        assertEquals(new BigDecimal("20.0"), list.get(0).getRatio());
    }

    @Test
    @DisplayName("DP-XM-UT-018 应答状态")
    void ut018_replyStatus()
    {
        LivestockResourceReplyStatusVo vo = LivestockResourceScreenSupport.buildReplyStatus(8L, 2L);
        assertEquals(10, vo.getTotalAiReplies());
        assertEquals(2, vo.getItems().size());
        assertEquals(new BigDecimal("80.0"), vo.getItems().get(0).getRatio());
    }

    @Test
    @DisplayName("DP-XM-UT-019 热点 Top5 条数优先")
    void ut019_hotTopics()
    {
        LivestockResourceCategoryCountDto a = cat("2", 50L);
        LivestockResourceCategoryCountDto b = cat("1", 30L);
        List<LivestockResourceCategoryItemVo> hot = LivestockResourceScreenSupport.buildHotTopics(
                Arrays.asList(a, b), 5);
        assertEquals(2, hot.size());
        assertEquals("2", hot.get(0).getCategoryCode());
        assertEquals(50L, hot.get(0).getCount());
    }

    @Test
    @DisplayName("DP-XM-UT-020 关键词仅文本分词")
    void ut020_keywords()
    {
        List<String> texts = Arrays.asList(
                "牦牛养殖防疫技巧",
                "牦牛养殖防疫技巧",
                "   ",
                null);
        java.util.List<com.ruoyi.web.modules.screen.domain.vo.LivestockResourceKeywordVo> list =
                LivestockResourceScreenSupport.extractTopKeywords(texts, 30);
        assertFalse(list.isEmpty());
        assertTrueMinCount(list.get(0).getCount(), 2L);
        org.junit.jupiter.api.Assertions.assertTrue(
                list.stream().anyMatch(k -> k.getKeyword().contains("牦牛")));
    }

    private static void assertTrueMinCount(long actual, long min)
    {
        org.junit.jupiter.api.Assertions.assertTrue(actual >= min);
    }

    private static LivestockResourceOverviewDto yearMetrics(
            Long users, Long sessions, Long questions, Double avgMs)
    {
        LivestockResourceOverviewDto dto = new LivestockResourceOverviewDto();
        dto.setTotalUsers(users);
        dto.setTotalSessions(sessions);
        dto.setTotalQuestionCount(questions);
        dto.setAvgCostTimeMs(avgMs);
        return dto;
    }

    private static LivestockResourceDateCountDto dayCount(String date, long count)
    {
        LivestockResourceDateCountDto dto = new LivestockResourceDateCountDto();
        dto.setBucketKey(date);
        dto.setCount(count);
        return dto;
    }

    private static LivestockResourceDateCountDto hourCount(String bucket, long count)
    {
        LivestockResourceDateCountDto dto = new LivestockResourceDateCountDto();
        dto.setBucketKey(bucket);
        dto.setCount(count);
        return dto;
    }

    private static LivestockResourceCategoryCountDto cat(String code, long count)
    {
        LivestockResourceCategoryCountDto dto = new LivestockResourceCategoryCountDto();
        dto.setCategoryCode(code);
        dto.setCount(count);
        return dto;
    }

    private static LivestockResourceBandCountDto band(String code, long count)
    {
        LivestockResourceBandCountDto dto = new LivestockResourceBandCountDto();
        dto.setBandCode(code);
        dto.setSessionCount(count);
        return dto;
    }

    private static LivestockResourceCategoryItemVo item(
            String code, String name, long count, BigDecimal ratio)
    {
        LivestockResourceCategoryItemVo vo = new LivestockResourceCategoryItemVo();
        vo.setCategoryCode(code);
        vo.setCategoryName(name);
        vo.setCount(count);
        vo.setRatio(ratio);
        return vo;
    }
}
