package com.mosquito.project.controller;

import com.mosquito.project.domain.Activity;
import com.mosquito.project.dto.ActivityStatsResponse;
import com.mosquito.project.dto.ApiResponse;
import com.mosquito.project.service.ActivityService;
import com.mosquito.project.permission.ApprovalFlowService;
import com.mosquito.project.permission.RequirePermission;
import com.mosquito.project.permission.SysApprovalRecord;
import com.mosquito.project.persistence.entity.DailyActivityStatsEntity;
import com.mosquito.project.persistence.repository.DailyActivityStatsRepository;
import com.mosquito.project.persistence.repository.LinkClickRepository;
import com.mosquito.project.persistence.repository.RiskAlertRepository;
import com.mosquito.project.persistence.repository.SysAuditLogRepository;
import com.mosquito.project.persistence.repository.UserInviteRepository;
import com.mosquito.project.persistence.repository.UserRewardRepository;
import com.mosquito.project.persistence.repository.SystemConfigRepository;
import com.mosquito.project.persistence.entity.SystemConfigEntity;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.jdbc.core.JdbcTemplate;

import javax.sql.DataSource;
import java.sql.Connection;

import jakarta.servlet.http.HttpServletRequest;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 仪表盘控制器 - 提供管理后台首页数据
 */
@RestController
@RequestMapping("/api/v1/dashboard")
public class DashboardController {

    private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(DashboardController.class);

    private final ActivityService activityService;
    private final ApprovalFlowService approvalFlowService;
    private final DailyActivityStatsRepository dailyActivityStatsRepository;
    private final UserInviteRepository userInviteRepository;
    private final UserRewardRepository userRewardRepository;
    private final LinkClickRepository linkClickRepository;
    private final RiskAlertRepository riskAlertRepository;
    private final SysAuditLogRepository auditLogRepository;
    private final SystemConfigRepository systemConfigRepository;
    private final StringRedisTemplate redisTemplate;
    private final JdbcTemplate jdbcTemplate;

    public DashboardController(
            ActivityService activityService,
            ApprovalFlowService approvalFlowService,
            DailyActivityStatsRepository dailyActivityStatsRepository,
            UserInviteRepository userInviteRepository,
            UserRewardRepository userRewardRepository,
            LinkClickRepository linkClickRepository,
            RiskAlertRepository riskAlertRepository,
            SysAuditLogRepository auditLogRepository,
            SystemConfigRepository systemConfigRepository,
            StringRedisTemplate redisTemplate,
            JdbcTemplate jdbcTemplate) {
        this.activityService = activityService;
        this.approvalFlowService = approvalFlowService;
        this.dailyActivityStatsRepository = dailyActivityStatsRepository;
        this.userInviteRepository = userInviteRepository;
        this.userRewardRepository = userRewardRepository;
        this.linkClickRepository = linkClickRepository;
        this.riskAlertRepository = riskAlertRepository;
        this.auditLogRepository = auditLogRepository;
        this.systemConfigRepository = systemConfigRepository;
        this.redisTemplate = redisTemplate;
        this.jdbcTemplate = jdbcTemplate;
    }

    /**
     * 获取仪表盘数据
     */
    @GetMapping
    @RequirePermission("dashboard.index.view.ALL")
    public ResponseEntity<ApiResponse<Map<String, Object>>> getDashboard(HttpServletRequest request) {
        Long currentUserId = getCurrentUserId(request);
        Map<String, Object> data = new HashMap<>();

        // KPI数据（若用户已登录则按用户过滤，否则显示全局数据）
        data.put("kpis", buildKpiData(currentUserId));

        // 活动列表
        data.put("activities", buildActivityList());

        // 告警/异常
        data.put("alerts", buildAlerts(currentUserId));

        // 待办事项
        data.put("todos", buildTodos(currentUserId));

        // 更新时间
        data.put("updatedAt", LocalDateTime.now().toString());

        return ResponseEntity.ok(ApiResponse.success(data));
    }

    /**
     * 获取KPI统计数据
     */
    @GetMapping("/kpis")
    @RequirePermission("dashboard.index.view.ALL")
    public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getKpis(HttpServletRequest request) {
        Long currentUserId = getCurrentUserId(request);
        return ResponseEntity.ok(ApiResponse.success(buildKpiData(currentUserId)));
    }

    /**
     * 获取监控视图数据（统一的监控视图入口）
     * 对应权限: dashboard.monitor.view.ALL
     */
    @GetMapping("/monitor/view")
    @RequirePermission("dashboard.monitor.view.ALL")
    public ResponseEntity<ApiResponse<Map<String, Object>>> getMonitorView(HttpServletRequest request) {
        Map<String, Object> data = new HashMap<>();

        // 实时KPI数据
        data.put("currentOnline", getCurrentOnline());
        data.put("todayVisits", getTodayVisits());
        data.put("realtimeConversion", getRealtimeConversion());
        data.put("apiRequests", getApiRequests());

        // 实时事件流
        data.put("recentEvents", getRecentEvents());

        // 系统健康状态
        data.put("systemHealth", getSystemHealth());

        data.put("timestamp", LocalDateTime.now().toString());

        return ResponseEntity.ok(ApiResponse.success(data));
    }

    /**
     * 获取实时监控数据
     * 对应权限: dashboard.chart.realtime.ALL
     */
    @GetMapping("/monitor/realtime")
    @RequirePermission("dashboard.chart.realtime.ALL")
    public ResponseEntity<ApiResponse<Map<String, Object>>> getRealtimeData(HttpServletRequest request) {
        Map<String, Object> data = new HashMap<>();

        // 实时KPI数据
        data.put("currentOnline", getCurrentOnline());
        data.put("todayVisits", getTodayVisits());
        data.put("realtimeConversion", getRealtimeConversion());
        data.put("apiRequests", getApiRequests());

        // 最近24小时访问趋势
        data.put("hourlyTrend", getHourlyTrend());

        // 系统健康状态
        data.put("systemHealth", getSystemHealth());

        // 实时事件流
        data.put("recentEvents", getRecentEvents());

        data.put("timestamp", LocalDateTime.now().toString());

        return ResponseEntity.ok(ApiResponse.success(data));
    }

    /**
     * 获取历史图表数据
     * 对应权限: dashboard.chart.history.ALL
     */
    @GetMapping("/monitor/history")
    @RequirePermission("dashboard.chart.history.ALL")
    public ResponseEntity<ApiResponse<Map<String, Object>>> getHistoryData(
            @RequestParam(defaultValue = "7") int days,
            @RequestParam(required = false) String metric,
            HttpServletRequest request) {
        Map<String, Object> data = new HashMap<>();

        // 验证days参数
        int validDays = Math.min(Math.max(days, 1), 90);

        // 获取时间趋势数据
        data.put("timeTrend", getTimeTrend(validDays, metric));

        // 获取对比数据（本周vs上周）
        data.put("comparison", getComparisonData(validDays));

        data.put("timestamp", LocalDateTime.now().toString());

        return ResponseEntity.ok(ApiResponse.success(data));
    }

    /**
     * 配置KPI阈值（持久化到数据库）
     * 对应权限: dashboard.kpi.config.ALL
     */
    @PostMapping("/kpis/config")
    @RequirePermission("dashboard.kpi.config.ALL")
    public ResponseEntity<ApiResponse<Map<String, Object>>> configKpi(
            @RequestBody Map<String, Object> config,
            HttpServletRequest request) {
        Long currentUserId = getCurrentUserId(request);

        // 保存KPI配置到系统配置表
        String kpiKey = config.get("kpiKey") != null ? config.get("kpiKey").toString() : "";
        String configKey = "dashboard.kpi.thresholds." + kpiKey;
        String configValue = config.get("threshold") != null ? config.get("threshold").toString() : "";
        String configWarning = config.get("warning") != null ? config.get("warning").toString() : "";

        // 查询或创建配置
        SystemConfigEntity configEntity = systemConfigRepository.findByConfigKey(configKey)
                .orElse(new SystemConfigEntity());

        configEntity.setConfigKey(configKey);
        configEntity.setConfigValue(configValue + "|" + configWarning); // 用|分隔threshold和warning
        configEntity.setValueType("STRING");
        configEntity.setCategory("DASHBOARD");
        configEntity.setDescription("KPI阈值配置 - " + kpiKey);
        configEntity.setUpdatedAt(OffsetDateTime.now(ZoneOffset.UTC));

        if (configEntity.getCreatedAt() == null) {
            configEntity.setCreatedAt(OffsetDateTime.now(ZoneOffset.UTC));
        }

        systemConfigRepository.save(configEntity);

        log.info("KPI配置已保存: userId={}, kpiKey={}, threshold={}, warning={}",
                currentUserId, kpiKey, configValue, configWarning);

        Map<String, Object> result = new HashMap<>();
        result.put("kpiKey", kpiKey);
        result.put("threshold", configValue);
        result.put("warning", configWarning);
        result.put("updatedAt", LocalDateTime.now().toString());

        return ResponseEntity.ok(ApiResponse.success(result));
    }

    /**
     * 获取KPI阈值配置（从数据库读取）
     * 对应权限: dashboard.kpi.config.ALL
     */
    @GetMapping("/kpis/config")
    @RequirePermission("dashboard.kpi.config.ALL")
    public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getKpiConfig(HttpServletRequest request) {
        List<Map<String, Object>> configs = new ArrayList<>();

        // 默认KPI配置
        String[] defaultKpis = {"visits", "uv", "shares", "conversions", "newUsers", "kFactor", "cac"};

        for (String kpi : defaultKpis) {
            String configKey = "dashboard.kpi.thresholds." + kpi;
            Map<String, Object> config = new HashMap<>();
            config.put("kpiKey", kpi);

            // 尝试从数据库读取配置
            Optional<SystemConfigEntity> savedConfig = systemConfigRepository.findByConfigKey(configKey);
            if (savedConfig.isPresent()) {
                String savedValue = savedConfig.get().getConfigValue();
                if (savedValue != null && savedValue.contains("|")) {
                    String[] parts = savedValue.split("\\|");
                    config.put("threshold", parts[0]);
                    config.put("warning", parts.length > 1 ? parts[1] : "0");
                } else {
                    config.put("threshold", savedValue);
                    config.put("warning", "0");
                }
            } else {
                // 使用默认值
                config.put("threshold", 0);
                config.put("warning", 0);
            }
            configs.add(config);
        }

        return ResponseEntity.ok(ApiResponse.success(configs));
    }

    // ========== 私有辅助方法 ==========

    private Long getCurrentOnline() {
        // 从link_clicks表获取最近5分钟内的独立访问者
        try {
            OffsetDateTime fiveMinutesAgo = OffsetDateTime.now().minusMinutes(5);
            return linkClickRepository.countRecentVisitors(fiveMinutesAgo);
        } catch (Exception e) {
            return 0L;
        }
    }

    private Long getTodayVisits() {
        try {
            LocalDate today = LocalDate.now();
            Optional<DailyActivityStatsEntity> stats = dailyActivityStatsRepository.findByStatDate(today);
            return stats.map(s -> (long)(s.getViews() != null ? s.getViews() : 0)).orElse(0L);
        } catch (Exception e) {
            return 0L;
        }
    }

    private Double getRealtimeConversion() {
        try {
            long totalViews = 0;
            long totalConversions = 0;
            List<DailyActivityStatsEntity> allStats = dailyActivityStatsRepository.findAll();
            for (DailyActivityStatsEntity stats : allStats) {
                totalViews += (stats.getViews() != null ? stats.getViews() : 0);
                totalConversions += (stats.getConversions() != null ? stats.getConversions() : 0);
            }
            if (totalViews > 0) {
                return Math.round((double) totalConversions / totalViews * 10000) / 100.0;
            }
            return 0.0;
        } catch (Exception e) {
            return 0.0;
        }
    }

    private Long getApiRequests() {
        // 从审计日志表统计API请求数量
        try {
            LocalDateTime startOfDay = LocalDate.now().atStartOfDay();
            LocalDateTime endOfDay = LocalDateTime.now();
            return auditLogRepository.countByCreatedAtBetween(startOfDay, endOfDay);
        } catch (Exception e) {
            log.warn("Failed to get API requests count from audit log: {}", e.getMessage());
            return 0L;
        }
    }

    private List<Map<String, Object>> getHourlyTrend() {
        List<Map<String, Object>> trend = new ArrayList<>();
        LocalDateTime now = LocalDateTime.now();
        ZoneOffset zoneOffset = ZoneOffset.ofHours(8); // 北京时间

        for (int i = 23; i >= 0; i--) {
            LocalDateTime hourStart = now.minusHours(i).withMinute(0).withSecond(0).withNano(0);
            LocalDateTime hourEnd = hourStart.plusHours(1);
            OffsetDateTime start = hourStart.atOffset(zoneOffset);
            OffsetDateTime end = hourEnd.atOffset(zoneOffset);

            Map<String, Object> point = new HashMap<>();
            point.put("hour", hourStart.format(DateTimeFormatter.ofPattern("HH:00")));

            try {
                // 从link_clicks表统计每小时的点击量
                List<com.mosquito.project.persistence.entity.LinkClickEntity> clicks =
                    linkClickRepository.findByCreatedAtBetween(start, end);
                point.put("visits", clicks != null ? clicks.size() : 0);
            } catch (Exception e) {
                // 降级处理
                point.put("visits", 0);
            }

            trend.add(point);
        }

        return trend;
    }

    private Map<String, Object> getSystemHealth() {
        Map<String, Object> health = new HashMap<>();

        // 后端服务状态（始终UP，因为服务能响应说明应用正常）
        Map<String, String> backend = new HashMap<>();
        backend.put("status", "UP");
        backend.put("message", "正常运行");
        health.put("backend", backend);

        // 数据库状态 - 真实健康检查
        Map<String, String> database = new HashMap<>();
        try {
            // 执行一个简单查询来验证数据库连接
            jdbcTemplate.execute("SELECT 1");
            database.put("status", "UP");
            database.put("message", "连接正常");
        } catch (Exception e) {
            database.put("status", "DOWN");
            database.put("message", "连接失败: " + e.getMessage());
        }
        health.put("database", database);

        // Redis状态 - 使用真实的Redis PING命令进行健康检查
        Map<String, String> redis = new HashMap<>();
        try {
            String pong = redisTemplate.getConnectionFactory().getConnection().ping();
            if ("PONG".equals(pong)) {
                redis.put("status", "UP");
                redis.put("message", "连接正常");
            } else {
                redis.put("status", "DEGRADED");
                redis.put("message", "响应异常: " + pong);
            }
        } catch (Exception e) {
            redis.put("status", "DOWN");
            redis.put("message", "连接失败: " + e.getMessage());
        }
        health.put("redis", redis);

        return health;
    }

    private List<Map<String, Object>> getRecentEvents() {
        List<Map<String, Object>> events = new ArrayList<>();

        // 从最近的审批记录生成事件
        try {
            List<SysApprovalRecord> recentRecords = approvalFlowService.getAllPendingApprovals();
            int count = 0;
            for (SysApprovalRecord record : recentRecords) {
                if (count >= 5) break;
                Map<String, Object> event = new HashMap<>();
                event.put("id", record.getId());
                event.put("description", "新的审批: " + record.getBizType());
                event.put("time", record.getCreatedAt() != null ?
                    record.getCreatedAt().format(DateTimeFormatter.ofPattern("HH:mm:ss")) : "--:--:--");
                events.add(event);
                count++;
            }
        } catch (Exception e) {
            // 静默处理
        }

        return events;
    }

    private List<Map<String, Object>> getTimeTrend(int days, String metric) {
        List<Map<String, Object>> trend = new ArrayList<>();
        LocalDate today = LocalDate.now();

        for (int i = days - 1; i >= 0; i--) {
            LocalDate date = today.minusDays(i);
            Map<String, Object> point = new HashMap<>();
            point.put("date", date.toString());

            try {
                Optional<DailyActivityStatsEntity> stats = dailyActivityStatsRepository.findByStatDate(date);
                if (stats.isPresent()) {
                    DailyActivityStatsEntity s = stats.get();
                    point.put("views", s.getViews() != null ? s.getViews() : 0);
                    point.put("shares", s.getShares() != null ? s.getShares() : 0);
                    point.put("conversions", s.getConversions() != null ? s.getConversions() : 0);
                    point.put("newUsers", s.getNewRegistrations() != null ? s.getNewRegistrations() : 0);
                } else {
                    point.put("views", 0);
                    point.put("shares", 0);
                    point.put("conversions", 0);
                    point.put("newUsers", 0);
                }
            } catch (Exception e) {
                point.put("views", 0);
                point.put("shares", 0);
                point.put("conversions", 0);
                point.put("newUsers", 0);
            }

            trend.add(point);
        }

        return trend;
    }

    private Map<String, Object> getComparisonData(int days) {
        Map<String, Object> comparison = new HashMap<>();

        // 本周数据
        long thisWeekViews = 0;
        long thisWeekConversions = 0;

        // 上周数据
        long lastWeekViews = 0;
        long lastWeekConversions = 0;

        LocalDate today = LocalDate.now();

        // 统计本周
        for (int i = 0; i < days && i < 7; i++) {
            LocalDate date = today.minusDays(i);
            try {
                Optional<DailyActivityStatsEntity> stats = dailyActivityStatsRepository.findByStatDate(date);
                if (stats.isPresent()) {
                    thisWeekViews += stats.get().getViews() != null ? stats.get().getViews() : 0;
                    thisWeekConversions += stats.get().getConversions() != null ? stats.get().getConversions() : 0;
                }
            } catch (Exception e) {
                // 静默处理
            }
        }

        // 统计上周
        for (int i = 7; i < days + 7 && i < 14; i++) {
            LocalDate date = today.minusDays(i);
            try {
                Optional<DailyActivityStatsEntity> stats = dailyActivityStatsRepository.findByStatDate(date);
                if (stats.isPresent()) {
                    lastWeekViews += stats.get().getViews() != null ? stats.get().getViews() : 0;
                    lastWeekConversions += stats.get().getConversions() != null ? stats.get().getConversions() : 0;
                }
            } catch (Exception e) {
                // 静默处理
            }
        }

        comparison.put("thisWeek", Map.of("views", thisWeekViews, "conversions", thisWeekConversions));
        comparison.put("lastWeek", Map.of("views", lastWeekViews, "conversions", lastWeekConversions));

        // 计算增长率
        double viewsGrowth = lastWeekViews > 0 ?
            Math.round((double) (thisWeekViews - lastWeekViews) / lastWeekViews * 10000) / 100.0 : 0.0;
        double conversionsGrowth = lastWeekConversions > 0 ?
            Math.round((double) (thisWeekConversions - lastWeekConversions) / lastWeekConversions * 10000) / 100.0 : 0.0;

        comparison.put("growth", Map.of("views", viewsGrowth, "conversions", conversionsGrowth));

        return comparison;
    }

    /**
     * 获取活动统计摘要
     */
    @GetMapping("/activities")
    @RequirePermission("dashboard.index.view.ALL")
    public ResponseEntity<ApiResponse<Map<String, Object>>> getActivitiesSummary() {
        Map<String, Object> summary = new HashMap<>();

        List<Activity> activities = activityService.getAllActivities();

        // 统计活动数量
        summary.put("total", activities.size());

        // 活动列表（简要信息）
        List<Map<String, Object>> activityList = activities.stream()
                .limit(10)
                .map(this::convertActivitySummary)
                .collect(Collectors.toList());
        summary.put("list", activityList);

        return ResponseEntity.ok(ApiResponse.success(summary));
    }

    /**
     * 获取待办事项
     */
    @GetMapping("/todos")
    @RequirePermission("dashboard.index.view.ALL")
    public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getTodoList(HttpServletRequest request) {
        Long currentUserId = getCurrentUserId(request);
        return ResponseEntity.ok(ApiResponse.success(buildTodos(currentUserId)));
    }

    private List<Map<String, Object>> buildKpiData(Long currentUserId) {
        List<Map<String, Object>> kpis = new ArrayList<>();

        // 获取统计数据
        List<Activity> activities = activityService.getAllActivities();
        long totalActivities = activities.size();

        // 待审批数量（若用户已登录则显示该用户的待审批，否则显示全部）
        Long approverId = (currentUserId != null) ? currentUserId : null;
        long pendingApprovals = (approverId != null)
            ? approvalFlowService.getPendingApprovals(approverId).size()
            : approvalFlowService.getAllPendingApprovals().size();

        // 从数据库获取真实统计数据
        long totalUsers = 0L;
        long pendingRewards = 0L;
        // 从风险告警表获取真实的待处理告警数量
        long pendingRisks = riskAlertRepository.countByStatus("PENDING");

        // 获取真实PV/UV/分享/转化数据
        long totalViews = 0L;
        long totalShares = 0L;
        long totalConversions = 0L;
        long totalNewUsers = 0L;

        try {
            // 从每日统计表汇总
            List<DailyActivityStatsEntity> allStats = dailyActivityStatsRepository.findAll();
            for (DailyActivityStatsEntity stats : allStats) {
                totalViews += (stats.getViews() != null ? stats.getViews() : 0);
                totalShares += (stats.getShares() != null ? stats.getShares() : 0);
                totalConversions += (stats.getConversions() != null ? stats.getConversions() : 0);
                totalNewUsers += (stats.getNewRegistrations() != null ? stats.getNewRegistrations() : 0);
            }

            // 从邀请表统计新用户
            totalUsers = userInviteRepository.count();

            // 从奖励表统计待审批
            pendingRewards = userRewardRepository.countByStatus("PENDING");

        } catch (Exception e) {
            // 如果查询失败，使用备用方案
        }

        // PV（访问量）
        Map<String, Object> visits = new HashMap<>();
        visits.put("label", "访问(PV)");
        visits.put("value", totalViews);
        visits.put("status", totalActivities > 0 && totalViews > 0 ? "正常" : (totalActivities > 0 ? "待同步" : "无活动"));
        visits.put("hint", "页面访问总次数");
        kpis.add(visits);

        // UV（独立访客）- 从link_clicks表获取（按IP去重）
        long uv = 0L;
        try {
            uv = linkClickRepository.countUniqueVisitors();
        } catch (Exception e) {
            // 备用
        }
        Map<String, Object> uvMap = new HashMap<>();
        uvMap.put("label", "访客(UV)");
        uvMap.put("value", uv);
        uvMap.put("status", totalActivities > 0 ? "正常" : "待同步");
        uvMap.put("hint", "独立访客数");
        kpis.add(uvMap);

        // 分享数
        Map<String, Object> shares = new HashMap<>();
        shares.put("label", "分享");
        shares.put("value", totalShares);
        shares.put("status", totalActivities > 0 ? "正常" : "待同步");
        shares.put("hint", "分享总次数");
        kpis.add(shares);

        // 转化数
        Map<String, Object> conversions = new HashMap<>();
        conversions.put("label", "转化");
        conversions.put("value", totalConversions);
        conversions.put("status", totalActivities > 0 ? "正常" : "待同步");
        conversions.put("hint", "完成目标用户数");
        kpis.add(conversions);

        // 新增用户
        Map<String, Object> newUsers = new HashMap<>();
        newUsers.put("label", "新增用户");
        newUsers.put("value", totalNewUsers);
        newUsers.put("status", "正常");
        newUsers.put("hint", "新增注册用户数");
        kpis.add(newUsers);

        // K因子 = 新增用户数 / 参与邀请的用户数（每个邀请者带来的新增用户数）
        // K > 1 表示病毒式增长（每个邀请者平均邀请超过1人）
        double kFactor = 0.0;
        long totalInviters = 0L;
        try {
            totalInviters = userInviteRepository.countDistinctInviters();
        } catch (Exception e) {
            // 如果查询失败，使用被邀请者数作为近似
            totalInviters = totalUsers > 0 ? totalUsers : 1;
        }
        if (totalInviters > 0 && totalNewUsers > 0) {
            kFactor = (double) totalNewUsers / totalInviters;
        }
        Map<String, Object> kFactorMap = new HashMap<>();
        kFactorMap.put("label", "K因子");
        kFactorMap.put("value", String.format("%.2f", kFactor));
        kFactorMap.put("status", kFactor > 1.0 ? "增长中" : (kFactor > 0 ? "需关注" : "无数据"));
        kFactorMap.put("hint", "平均每个邀请者带来的新增用户数");
        kpis.add(kFactorMap);

        // CAC（获取成本）- 假设需要从奖励表计算
        double cac = 0.0;
        Long totalRewardPoints = userRewardRepository.sumPointsByStatus("GRANTED");
        if (totalRewardPoints != null && totalNewUsers > 0) {
            cac = (double) totalRewardPoints / totalNewUsers;
        }
        Map<String, Object> cacMap = new HashMap<>();
        cacMap.put("label", "CAC");
        cacMap.put("value", String.format("%.2f", cac));
        cacMap.put("status", cac > 0 ? "正常" : "无数据");
        cacMap.put("hint", "用户获取成本(积分/用户)");
        kpis.add(cacMap);

        // 奖励待审批
        Map<String, Object> pendingRewardKpi = new HashMap<>();
        pendingRewardKpi.put("label", "待审批奖励");
        pendingRewardKpi.put("value", pendingRewards);
        pendingRewardKpi.put("status", pendingRewards > 0 ? "待处理" : "已清零");
        pendingRewardKpi.put("hint", "待审批的奖励申请");
        kpis.add(pendingRewardKpi);

        // 待审批
        Map<String, Object> pendingApprovalKpi = new HashMap<>();
        pendingApprovalKpi.put("label", "待审批");
        pendingApprovalKpi.put("value", pendingApprovals);
        pendingApprovalKpi.put("status", pendingApprovals > 0 ? "待处理" : "已清零");
        pendingApprovalKpi.put("hint", "待审批的申请");
        kpis.add(pendingApprovalKpi);

        // 风险告警
        Map<String, Object> riskKpi = new HashMap<>();
        riskKpi.put("label", "风险告警");
        riskKpi.put("value", pendingRisks);
        riskKpi.put("status", pendingRisks > 0 ? "需关注" : "正常");
        riskKpi.put("hint", "待处理的风险告警");
        kpis.add(riskKpi);

        return kpis;
    }

    private List<Map<String, Object>> buildActivityList() {
        List<Activity> activities = activityService.getAllActivities();
        return activities.stream()
                .limit(10)
                .map(this::convertActivitySummary)
                .collect(Collectors.toList());
    }

    private Map<String, Object> convertActivitySummary(Activity activity) {
        Map<String, Object> summary = new HashMap<>();
        summary.put("id", activity.getId());
        summary.put("name", activity.getName());
        summary.put("startTime", activity.getStartTime() != null ? activity.getStartTime().toString() : null);
        summary.put("endTime", activity.getEndTime() != null ? activity.getEndTime().toString() : null);
        // 添加后端状态，用于前端按状态机显示
        summary.put("status", activity.getStatus());

        // 获取活动统计
        try {
            ActivityStatsResponse stats = activityService.getActivityStats(activity.getId());
            summary.put("participants", stats.getTotalParticipants());
            summary.put("shares", stats.getTotalShares());
            // conversions应使用新增用户数(newUsers)，而不是参与人数(participants)
            summary.put("conversions", stats.getNewUsers());
        } catch (Exception e) {
            summary.put("participants", 0);
            summary.put("shares", 0);
            summary.put("conversions", 0);
        }

        return summary;
    }

    private List<Map<String, Object>> buildAlerts(Long currentUserId) {
        List<Map<String, Object>> alerts = new ArrayList<>();

        // 检查待审批记录（若用户已登录则显示该用户的待审批，否则显示全部）
        List<SysApprovalRecord> pendingRecords = (currentUserId != null)
            ? approvalFlowService.getPendingApprovals(currentUserId)
            : approvalFlowService.getAllPendingApprovals();
        if (!pendingRecords.isEmpty()) {
            Map<String, Object> alert = new HashMap<>();
            alert.put("title", "待审批事项");
            alert.put("detail", pendingRecords.size() + "条申请待审批");
            alert.put("type", "APPROVAL");
            alert.put("level", "INFO");
            alerts.add(alert);
        }

        return alerts;
    }

    private List<Map<String, Object>> buildTodos(Long currentUserId) {
        List<Map<String, Object>> todos = new ArrayList<>();

        // 待审批记录（若用户已登录则显示该用户的待审批，否则显示全部）
        List<SysApprovalRecord> pendingRecords = (currentUserId != null)
            ? approvalFlowService.getPendingApprovals(currentUserId)
            : approvalFlowService.getAllPendingApprovals();
        if (!pendingRecords.isEmpty()) {
            Map<String, Object> todo = new HashMap<>();
            todo.put("id", "approval-pending");
            todo.put("title", "审批申请");
            todo.put("description", pendingRecords.size() + "条申请待审批");
            todo.put("type", "APPROVAL");
            todo.put("link", "/approvals");
            todo.put("priority", "HIGH");
            todos.add(todo);
        }

        return todos;
    }

    /**
     * 导出仪表盘数据为CSV
     */
    @GetMapping("/export")
    @RequirePermission("dashboard.index.export.ALL")
    public ResponseEntity<byte[]> exportDashboard(@RequestParam(defaultValue = "csv") String format, HttpServletRequest request) {
        Long currentUserId = getCurrentUserId(request);
        StringBuilder csv = new StringBuilder();
        csv.append("导出时间:").append(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))).append("\n\n");

        // KPI数据
        csv.append("KPI指标\n");
        csv.append("指标,数值,状态,说明\n");
        for (Map<String, Object> kpi : buildKpiData(currentUserId)) {
            csv.append(kpi.get("label")).append(",")
               .append(kpi.get("value")).append(",")
               .append(kpi.get("status")).append(",")
               .append(kpi.get("hint")).append("\n");
        }
        csv.append("\n");

        // 活动数据
        csv.append("活动列表\n");
        csv.append("ID,名称,开始时间,结束时间,参与人数,分享数,转化数\n");
        for (Activity activity : activityService.getAllActivities()) {
            csv.append(activity.getId()).append(",")
               .append(escapeCsv(activity.getName())).append(",")
               .append(activity.getStartTime() != null ? activity.getStartTime().toString() : "").append(",")
               .append(activity.getEndTime() != null ? activity.getEndTime().toString() : "").append(",");
            try {
                ActivityStatsResponse stats = activityService.getActivityStats(activity.getId());
                csv.append(stats.getTotalParticipants()).append(",")
                   .append(stats.getTotalShares()).append(",")
                   .append(stats.getNewUsers()).append("\n");
            } catch (Exception e) {
                csv.append("0,0,0\n");
            }
        }

        byte[] body = csv.toString().getBytes(java.nio.charset.StandardCharsets.UTF_8);
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.parseMediaType("text/csv; charset=UTF-8"));
        headers.set(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"dashboard_export_" +
                LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")) + ".csv\"");

        return new ResponseEntity<>(body, headers, org.springframework.http.HttpStatus.OK);
    }

    /**
     * 导出KPI数据为CSV
     */
    @GetMapping("/kpis/export")
    @RequirePermission("dashboard.index.export.ALL")
    public ResponseEntity<byte[]> exportKpis(HttpServletRequest request) {
        Long currentUserId = getCurrentUserId(request);
        StringBuilder csv = new StringBuilder();
        csv.append("指标,数值,状态,说明\n");
        for (Map<String, Object> kpi : buildKpiData(currentUserId)) {
            csv.append(kpi.get("label")).append(",")
               .append(kpi.get("value")).append(",")
               .append(kpi.get("status")).append(",")
               .append(kpi.get("hint")).append("\n");
        }

        byte[] body = csv.toString().getBytes(java.nio.charset.StandardCharsets.UTF_8);
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.parseMediaType("text/csv; charset=UTF-8"));
        headers.set(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"kpi_export_" +
                LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")) + ".csv\"");

        return new ResponseEntity<>(body, headers, org.springframework.http.HttpStatus.OK);
    }

    /**
     * 导出活动数据为CSV
     */
    @GetMapping("/activities/export")
    @RequirePermission("dashboard.index.export.ALL")
    public ResponseEntity<byte[]> exportActivities() {
        StringBuilder csv = new StringBuilder();
        csv.append("ID,名称,开始时间,结束时间,参与人数,分享数,转化数\n");

        for (Activity activity : activityService.getAllActivities()) {
            csv.append(activity.getId()).append(",")
               .append(escapeCsv(activity.getName())).append(",")
               .append(activity.getStartTime() != null ? activity.getStartTime().toString() : "").append(",")
               .append(activity.getEndTime() != null ? activity.getEndTime().toString() : "").append(",");
            try {
                ActivityStatsResponse stats = activityService.getActivityStats(activity.getId());
                csv.append(stats.getTotalParticipants()).append(",")
                   .append(stats.getTotalShares()).append(",")
                   .append(stats.getNewUsers()).append("\n");
            } catch (Exception e) {
                csv.append("0,0,0\n");
            }
        }

        byte[] body = csv.toString().getBytes(java.nio.charset.StandardCharsets.UTF_8);
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.parseMediaType("text/csv; charset=UTF-8"));
        headers.set(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"activity_export_" +
                LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")) + ".csv\"");

        return new ResponseEntity<>(body, headers, org.springframework.http.HttpStatus.OK);
    }

    /**
     * 转义CSV特殊字符
     */
    private String escapeCsv(String value) {
        if (value == null) return "";
        if (value.contains(",") || value.contains("\"") || value.contains("\n")) {
            return "\"" + value.replace("\"", "\"\"") + "\"";
        }
        return value;
    }

    /**
     * 获取当前用户ID
     */
    private Long getCurrentUserId(HttpServletRequest request) {
        Object userIdObj = request.getAttribute("userId");
        if (userIdObj instanceof Long) {
            return (Long) userIdObj;
        } else if (userIdObj instanceof Integer) {
            return ((Integer) userIdObj).longValue();
        } else if (userIdObj instanceof String) {
            try {
                return Long.parseLong((String) userIdObj);
            } catch (NumberFormatException e) {
                return null;
            }
        }
        return null;
    }
}
