package org.xyzh.system.controller;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.xyzh.api.news.resource.ResourceService;
import org.xyzh.api.study.course.CourseService;
import org.xyzh.api.study.task.LearningTaskService;
import org.xyzh.common.core.domain.ResultDomain;
import org.xyzh.common.dto.resource.TbResource;
import org.xyzh.common.dto.study.TbCourse;
import org.xyzh.common.dto.study.TbLearningTask;
import org.xyzh.common.dto.system.TbSysVisitStatistics;
import org.xyzh.common.dto.user.TbSysUser;
import org.xyzh.common.utils.TimeUtils;
import org.xyzh.common.vo.UserDeptRoleVO;
import org.xyzh.common.redis.service.RedisService;
import org.xyzh.system.mapper.SysVisitStatisticsMapper;
import org.xyzh.system.mapper.UserMapper;
import org.xyzh.system.utils.LoginUtil;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Date;
/**
 * @description 系统总览控制器
 * @filename SystemOverviewController.java
 * @author yslg
 * @copyright xyzh
 * @since 2025-10-15
 */
@RestController
@RequestMapping("/system/overview")
public class SystemOverviewController {
    private static final Logger logger = LoggerFactory.getLogger(SystemOverviewController.class);

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private SysVisitStatisticsMapper sysVisitStatisticsMapper;

    @Autowired
    private ResourceService resourceService;

    @Autowired
    private RedisService redisService;

    @Autowired
    private CourseService courseService;

    @Autowired
    private LearningTaskService learningTaskService;

    /**
     * 获取系统总览数据统计
     */
    @GetMapping("/statistics")
    public ResultDomain<Map<String, Object>> getSystemStatistics() {
        ResultDomain<Map<String, Object>> result = new ResultDomain<>();
        Map<String, Object> data = new HashMap<>();
        List<UserDeptRoleVO> voList = LoginUtil.getCurrentDeptRole();
        // 顶部统计卡片：总用户数、总资源数、今日PV、今日UV
        // 1. 总用户数：直接统计用户表数量（后续可增加状态/逻辑删除过滤）
        try {
            TbSysUser filterUser = new TbSysUser();

            long totalUsers = userMapper.countDeptUser(voList.get(0).getDeptID(), filterUser);
            data.put("totalUsers", totalUsers);
            filterUser.setEndTime(TimeUtils.getEndTimeOfYesterday());
            long yesterdayUsers = userMapper.countDeptUser(voList.get(0).getDeptID(), filterUser);
            // 目前未记录按天的用户总量，这里先返回"+0%"，后续可根据用户注册表统计
            data.put("totalUsersChange", formatPercentChange(totalUsers, yesterdayUsers));

            // 2. 总资源数：当前总量 & 与昨日总量对比
            long totalResources = 0L;
            long yesterdayTotalResources = 0L;

            // 今天总资源数（不带时间过滤）
            ResultDomain<Integer> totalResResult = resourceService.getResourceCount(new TbResource());
            if (totalResResult.isSuccess() && totalResResult.getData() != null) {
                totalResources = totalResResult.getData();
            }

            // 昨日结束时的资源总数：publish_time <= 昨日结束时间
            TbResource yesterdayFilter = new TbResource();
            yesterdayFilter.setStartTime(TimeUtils.getStartTimeOfYesterday());
            yesterdayFilter.setEndTime(TimeUtils.getEndTimeOfYesterday());
            ResultDomain<Integer> yesterdayResResult = resourceService.getResourceCount(yesterdayFilter);
            if (yesterdayResResult.isSuccess() && yesterdayResResult.getData() != null) {
                yesterdayTotalResources = yesterdayResResult.getData();
            }

            data.put("totalResources", totalResources);
            data.put("totalResourcesChange", formatPercentChange(totalResources, yesterdayTotalResources));
        } catch (Exception e) {
            logger.error("统计总用户数失败", e);
            data.put("totalUsers", 0);
        }

        // 3. 今日访问量 & 活跃用户：优先从Redis读取今日数据，必要时从系统访问统计表回退
        try {
            LocalDate todayDate = LocalDate.now();
            LocalDate yesterdayDate = todayDate.minusDays(1);

            String todayKeySuffix = todayDate.format(java.time.format.DateTimeFormatter.BASIC_ISO_DATE);
            String pvKey = "stat:pv:" + todayKeySuffix;
            String uvKey = "stat:uv:" + todayKeySuffix;

            String yesterdayKeySuffix = yesterdayDate.format(java.time.format.DateTimeFormatter.BASIC_ISO_DATE);
            String yesterdayPvKey = "stat:pv:" + yesterdayKeySuffix;
            String yesterdayUvKey = "stat:uv:" + yesterdayKeySuffix;

            long todayPv = 0L;
            long todayUv = 0L;
            long yesterdayPv = 0L;
            long yesterdayUv = 0L;

            try {
                Object pvObj = redisService.get(pvKey);
                if (pvObj instanceof Number) {
                    todayPv = ((Number) pvObj).longValue();
                }
            } catch (Exception e) {
                logger.warn("从Redis读取PV失败: {}", e.getMessage());
            }

            try {
                todayUv = redisService.sCard(uvKey);
            } catch (Exception e) {
                logger.warn("从Redis读取UV失败: {}", e.getMessage());
            }

            try {
                Object yesterdayPvObj = redisService.get(yesterdayPvKey);
                if (yesterdayPvObj instanceof Number) {
                    yesterdayPv = ((Number) yesterdayPvObj).longValue();
                }
            } catch (Exception e) {
                logger.warn("从Redis读取昨日PV失败: {}", e.getMessage());
            }

            try {
                yesterdayUv = redisService.sCard(yesterdayUvKey);
            } catch (Exception e) {
                logger.warn("从Redis读取昨日UV失败: {}", e.getMessage());
            }

            // 从统计表中获取活跃用户，作为顶部卡片展示
            // 顶部卡片：今日PV / 今日UV
            data.put("totalPv", todayPv);
            data.put("totalPvChange", formatPercentChange(todayPv, yesterdayPv));

            data.put("totalUv", todayUv);
            data.put("totalUvChange", formatPercentChange(todayUv, yesterdayUv));
        } catch (Exception e) {
            logger.error("统计访问量/活跃用户失败", e);
            data.put("totalPv", 0L);
            data.put("totalPvChange", "+0%");
            data.put("totalUv", 0L);
            data.put("totalUvChange", "+0%");
        }

        result.success("获取系统总览统计成功", data);
        return result;
    }

    /**
     * 获取活跃用户图表数据（PV和UV）
     */
    @GetMapping("/active-users")
    public ResultDomain<Map<String, Object>> getActiveUsersChart(
            @RequestParam(required = true, name = "start") String start, @RequestParam(required = true, name = "end") String end) {
        ResultDomain<Map<String, Object>> result = new ResultDomain<>();
        Map<String, Object> data = new HashMap<>();

        LocalDate startDate = LocalDate.parse(start);
        LocalDate endDate = LocalDate.parse(end);
        LocalDate today = LocalDate.now();

        try {
            // 按天遍历统计区间内的PV和UV数据
            List<String> labels = new ArrayList<>();
            List<Integer> pvValues = new ArrayList<>();
            List<Integer> uvValues = new ArrayList<>();

            LocalDate cursor = startDate;
            while (!cursor.isAfter(endDate)) {
                labels.add(formatDayLabel(cursor));

                int pv = 0;
                int uv = 0;
                try {
                    String keySuffix = cursor.format(java.time.format.DateTimeFormatter.BASIC_ISO_DATE);
                    String pvKey = "stat:pv:" + keySuffix;
                    String uvKey = "stat:uv:" + keySuffix;

                    Object pvObj = redisService.get(pvKey);
                    if (pvObj instanceof Number) {
                        pv = ((Number) pvObj).intValue();
                    }
                    uv = (int) redisService.sCard(uvKey);
                } catch (Exception e) {
                    logger.warn("从Redis读取今日PV/UV失败，尝试从数据库读取: {}", e.getMessage());
                }

                pvValues.add(pv);
                uvValues.add(uv);

                cursor = cursor.plusDays(1);
            }

            data.put("labels", labels);
            data.put("pvValues", pvValues);
            data.put("uvValues", uvValues);
        } catch (Exception e) {
            logger.error("获取PV/UV图表数据失败", e);
            data.put("labels", List.of());
            data.put("pvValues", List.of());
            data.put("uvValues", List.of());
        }

        result.success("获取PV/UV图表数据成功", data);
        return result;
    }

    /**
     * 获取资源分类统计图表
     */
    @GetMapping("/resource-category-stats")
    public ResultDomain<Map<String, Object>> getResourceCategoryStats() {
        ResultDomain<Map<String, Object>> result = new ResultDomain<>();
        try {
            Map<String, Object> data = new HashMap<>();

            // 获取各类型资源数量
            ResultDomain<Integer> resourceCountResult = resourceService.getResourceCount(new TbResource());
            ResultDomain<Integer> courseCountResult = courseService.getCourseCount(new TbCourse());
            ResultDomain<Integer> taskCountResult = learningTaskService.getLearningTaskCount(new TbLearningTask());

            // 获取数量，失败时默认为0
            int resourceCount = (resourceCountResult.isSuccess() && resourceCountResult.getData() != null)
                ? resourceCountResult.getData() : 0;
            int courseCount = (courseCountResult.isSuccess() && courseCountResult.getData() != null)
                ? courseCountResult.getData() : 0;
            int taskCount = (taskCountResult.isSuccess() && taskCountResult.getData() != null)
                ? taskCountResult.getData() : 0;

            // 饼图数据：名称 + 数量
            List<Map<String, Object>> categories = List.of(
                    createCategory("文章", resourceCount),
                    createCategory("课程", courseCount),
                    createCategory("学习任务", taskCount)
            );

            data.put("items", categories);
            result.success("获取资源分类统计成功", data);
        } catch (Exception e) {
            logger.error("获取资源分类统计失败", e);
            result.fail("获取资源分类统计失败: " + e.getMessage());
        }
        return result;
    }

    /**
     * 获取今日访问量统计
     */
    @GetMapping("/today-visits")
    public ResultDomain<Map<String, Object>> getTodayVisits() {
        ResultDomain<Map<String, Object>> result = new ResultDomain<>();
        Map<String, Object> data = new HashMap<>();
        try {
            String todayKeySuffix = LocalDate.now().format(java.time.format.DateTimeFormatter.BASIC_ISO_DATE);
            String pvKey = "stat:pv:" + todayKeySuffix;
            String uvKey = "stat:uv:" + todayKeySuffix;

            long uvFromRedis = 0L;
            long pvFromRedis = 0L;

            try {
                pvFromRedis = 0L;
                Object pvObj = redisService.get(pvKey);
                if (pvObj instanceof Number) {
                    pvFromRedis = ((Number) pvObj).longValue();
                }
            } catch (Exception e) {
                logger.warn("从Redis读取PV失败: {}", e.getMessage());
            }

            try {
                uvFromRedis = redisService.sCard(uvKey);
            } catch (Exception e) {
                logger.warn("从Redis读取UV失败: {}", e.getMessage());
            }

            TbSysVisitStatistics filter = new TbSysVisitStatistics();
            filter.setStatDate(new Date());
            List<TbSysVisitStatistics> list = sysVisitStatisticsMapper.selectSysVisitStatistics(filter);
            TbSysVisitStatistics todayStat = (list != null && !list.isEmpty()) ? list.get(0) : null;

            int uvFromDb = todayStat != null && todayStat.getUniqueVisitors() != null ? todayStat.getUniqueVisitors() : 0;
            int pvFromDb = todayStat != null && todayStat.getPageViews() != null ? todayStat.getPageViews() : 0;
            int avgDurationSec = todayStat != null && todayStat.getAvgVisitDuration() != null ? todayStat.getAvgVisitDuration() : 0;

            // 优先使用Redis中的实时数据，若没有则回退到统计表
            data.put("uv", uvFromRedis > 0 ? uvFromRedis : uvFromDb);
            data.put("pv", pvFromRedis > 0 ? pvFromRedis : pvFromDb);
            data.put("avgVisitDuration", formatDuration(avgDurationSec));
            // 当前表中没有跳出率字段，这里先返回"-"，后续有字段后再计算
            data.put("bounceRate", "-");

            result.success("获取今日访问量统计成功", data);
            return result;
        } catch (Exception e) {
            logger.error("获取今日访问量统计失败", e);
            data.put("uv", 0);
            data.put("pv", 0);
            data.put("avgVisitDuration", "0秒");
            data.put("bounceRate", "-");
            result.success("获取今日访问量统计成功", data);
            return result;
        }
    }

    /**
     * 记录页面访问（PV），由前端在进入系统总览页面时主动调用
     */
    @GetMapping("/track-visit")
    public ResultDomain<String> trackVisit() {
        ResultDomain<String> result = new ResultDomain<>();
        try {
            String todayKeySuffix = LocalDate.now().format(java.time.format.DateTimeFormatter.BASIC_ISO_DATE);
            String pvKey = "stat:pv:" + todayKeySuffix;
            redisService.incr(pvKey, 1L);
            result.success("记录访问成功", "OK");
        } catch (Exception e) {
            logger.error("记录PV失败", e);
            result.fail("记录访问失败: " + e.getMessage());
        }
        return result;
    }

    /**
     * 获取系统运行状态
     */
    @GetMapping("/system-status")
    public ResultDomain<Map<String, Object>> getSystemStatus() {
        ResultDomain<Map<String, Object>> result = new ResultDomain<>();
        Map<String, Object> data = new HashMap<>();

        data.put("status", "UP");
        data.put("message", "系统运行正常");

        result.success("获取系统运行状态成功", data);
        return result;
    }

    private Map<String, Object> createCategory(String name, int value) {
        Map<String, Object> item = new HashMap<>();
        item.put("name", name);
        item.put("value", value);
        return item;
    }

    private String formatDayLabel(LocalDate date) {
        return date.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
    }

    private String formatDuration(int seconds) {
        if (seconds <= 0) {
            return "0秒";
        }
        int minutes = seconds / 60;
        int remain = seconds % 60;
        if (minutes == 0) {
            return remain + "秒";
        }
        return minutes + "分" + remain + "秒";
    }

    /**
     * 计算相对昨日的变化百分比，返回形如"+12%"或"-5%"，当昨日为0或无数据时返回"+0%"
     */
    private String formatPercentChange(long today, long yesterday) {
        if (yesterday <= 0) {
            return "+"+today+"%";
        }

        long diff = today - yesterday;
        double percent = diff * 100.0 / yesterday;
        // 保留一位小数
        String formatted = String.format("%.1f", Math.abs(percent));
        String sign = percent >= 0 ? "+" : "-";
        return sign + formatted + "%";
    }
}
