package com.mosquito.project.controller;

import com.mosquito.project.dto.ApiResponse;
import com.mosquito.project.permission.RequirePermission;
import com.mosquito.project.persistence.repository.SysAuditLogRepository;
import com.mosquito.project.service.AuditService;
import jakarta.servlet.http.HttpServletRequest;
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 java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 审计日志控制器
 */
@RestController
@RequestMapping("/api/v1/audit")
public class AuditController {

    private final AuditService auditService;
    private final SysAuditLogRepository auditLogRepository;

    // 权限码常量 (使用PRD四段式格式)
    private static final String PERM_AUDIT_VIEW = "audit.index.view.ALL";
    private static final String PERM_AUDIT_EXPORT = "audit.index.export.ALL";
    private static final String PERM_AUDIT_REPORT = "audit.report.view.ALL";

    public AuditController(AuditService auditService, SysAuditLogRepository auditLogRepository) {
        this.auditService = auditService;
        this.auditLogRepository = auditLogRepository;
    }

    /**
     * 获取审计日志列表
     */
    @GetMapping("/logs")
    @RequirePermission(PERM_AUDIT_VIEW)
    public ResponseEntity<ApiResponse<Map<String, Object>>> getLogs(
            @RequestParam(required = false) Integer page,
            @RequestParam(required = false) Integer size,
            @RequestParam(required = false) Long userId,
            @RequestParam(required = false) String action,
            @RequestParam(required = false) String module,
            @RequestParam(required = false) String keyword,
            HttpServletRequest request) {

        Long currentUserId = getCurrentUserId(request);
        String user = userId != null ? userId.toString() : null;
        // 传递module参数，支持过滤
        Map<String, Object> data = auditService.getAuditLogsWithModule(page, size, keyword, action, module, user, currentUserId);
        return ResponseEntity.ok(ApiResponse.success(data));
    }

    /**
     * 获取当前用户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;
    }

    /**
     * 获取单个日志详情
     */
    @GetMapping("/logs/{id}")
    @RequirePermission(PERM_AUDIT_VIEW)
    public ResponseEntity<ApiResponse<Map<String, Object>>> getLogById(@PathVariable Long id) {
        Map<String, Object> data = auditService.getAuditLogById(id);
        return ResponseEntity.ok(ApiResponse.success(data));
    }

    /**
     * 获取操作类型列表
     */
    @GetMapping("/actions")
    @RequirePermission(PERM_AUDIT_VIEW)
    public ResponseEntity<ApiResponse<List<String>>> getActionTypes() {
        List<String> actions = Arrays.asList(
            "CREATE", "UPDATE", "DELETE", "VIEW", "LOGIN", "LOGOUT",
            "EXPORT", "IMPORT", "APPROVE", "REJECT"
        );
        return ResponseEntity.ok(ApiResponse.success(actions));
    }

    /**
     * 获取模块列表
     */
    @GetMapping("/modules")
    @RequirePermission(PERM_AUDIT_VIEW)
    public ResponseEntity<ApiResponse<List<String>>> getModules() {
        List<String> modules = Arrays.asList(
            "ACTIVITY", "USER", "REWARD", "RISK", "APPROVAL", "SYSTEM"
        );
        return ResponseEntity.ok(ApiResponse.success(modules));
    }

    /**
     * 获取审计统计
     */
    @GetMapping("/stats")
    @RequirePermission(PERM_AUDIT_VIEW)
    public ResponseEntity<ApiResponse<Map<String, Object>>> getStats(
            @RequestParam(required = false) String startDate,
            @RequestParam(required = false) String endDate) {

        // 解析时间范围
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        LocalDateTime start = startDate != null ? LocalDateTime.parse(startDate + "T00:00:00") : LocalDateTime.now().minusDays(30);
        LocalDateTime end = endDate != null ? LocalDateTime.parse(endDate + "T23:59:59") : LocalDateTime.now();

        // 统计总数
        long totalCount = auditLogRepository.countByCreatedAtBetween(start, end);

        // 按操作类型统计
        Map<String, Long> actionCounts = new LinkedHashMap<>();
        List<Object[]> actionResults = auditLogRepository.countByOperationGrouped(start, end);
        for (Object[] row : actionResults) {
            String operation = (String) row[0];
            Long count = (Long) row[1];
            actionCounts.put(operation, count);
        }

        // 按用户统计
        Map<String, Long> userCounts = new LinkedHashMap<>();
        List<Object[]> userResults = auditLogRepository.countByUserGrouped(start, end);
        for (Object[] row : userResults) {
            Long userId = (Long) row[0];
            String userName = (String) row[1];
            Long count = (Long) row[2];
            String key = userName != null ? userName + " (" + userId + ")" : String.valueOf(userId);
            userCounts.put(key, count);
        }

        // 按日期统计
        Map<String, Long> dailyCounts = new LinkedHashMap<>();
        List<Object[]> dailyResults = auditLogRepository.countByDateGrouped(start, end);
        for (Object[] row : dailyResults) {
            Object dateObj = row[0];
            Long count = (Long) row[1];
            String dateStr = dateObj != null ? dateObj.toString() : "";
            dailyCounts.put(dateStr, count);
        }

        Map<String, Object> stats = new HashMap<>();
        stats.put("totalCount", totalCount);
        stats.put("actionCounts", actionCounts);
        stats.put("userCounts", userCounts);
        stats.put("dailyCounts", dailyCounts);

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

    /**
     * 导出审计日志
     */
    @GetMapping("/logs/export")
    @RequirePermission(PERM_AUDIT_EXPORT)
    public ResponseEntity<byte[]> exportLogs(
            @RequestParam(required = false) String keyword,
            @RequestParam(required = false) String operation,
            @RequestParam(required = false) String user,
            HttpServletRequest request) {

        Long currentUserId = getCurrentUserId(request);
        List<Map<String, Object>> logs = auditService.exportAuditLogs(keyword, operation, user, currentUserId);

        // 转换为CSV格式
        StringBuilder csv = new StringBuilder();
        csv.append("ID,用户ID,用户名,IP地址,操作类型,资源类型,资源ID,操作详情,请求方法,请求URL,响应状态,时间\n");

        for (Map<String, Object> log : logs) {
            csv.append(log.getOrDefault("id", "")).append(",");
            csv.append(log.getOrDefault("userId", "")).append(",");
            csv.append(log.getOrDefault("userName", "")).append(",");
            csv.append(log.getOrDefault("userIp", "")).append(",");
            csv.append(log.getOrDefault("operation", "")).append(",");
            csv.append(log.getOrDefault("resource", "")).append(",");
            csv.append(log.getOrDefault("resourceId", "")).append(",");
            csv.append(log.getOrDefault("details", "")).append(",");
            csv.append(log.getOrDefault("requestMethod", "")).append(",");
            csv.append(log.getOrDefault("requestUrl", "")).append(",");
            csv.append(log.getOrDefault("responseStatus", "")).append(",");
            csv.append(log.getOrDefault("timestamp", "")).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=\"audit_logs.csv\"");

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

    /**
     * 获取审计报告
     * PRD要求: 审计报告能力 (audit.report.view)
     * 支持按时间范围、用户、操作类型等维度生成报告
     */
    @GetMapping("/reports")
    @RequirePermission(PERM_AUDIT_REPORT)
    public ResponseEntity<ApiResponse<Map<String, Object>>> getAuditReports(
            @RequestParam(required = false) String startDate,
            @RequestParam(required = false) String endDate,
            @RequestParam(required = false) String reportType,
            @RequestParam(required = false) Long userId,
            @RequestParam(required = false) String groupBy,
            HttpServletRequest request) {

        // 解析时间范围
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        LocalDateTime start = startDate != null ? LocalDateTime.parse(startDate + "T00:00:00") : LocalDateTime.now().minusDays(30);
        LocalDateTime end = endDate != null ? LocalDateTime.parse(endDate + "T23:59:59") : LocalDateTime.now();

        Long currentUserId = getCurrentUserId(request);
        Map<String, Object> report = auditService.generateReport(start, end, reportType, userId, groupBy, currentUserId);
        return ResponseEntity.ok(ApiResponse.success(report));
    }

    /**
     * 导出审计报告
     */
    @GetMapping("/reports/export")
    @RequirePermission(PERM_AUDIT_REPORT)
    public ResponseEntity<byte[]> exportAuditReport(
            @RequestParam(required = false) String startDate,
            @RequestParam(required = false) String endDate,
            @RequestParam(required = false) String reportType,
            @RequestParam(required = false) Long userId,
            @RequestParam(required = false) String groupBy,
            HttpServletRequest request) {

        // 解析时间范围
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        LocalDateTime start = startDate != null ? LocalDateTime.parse(startDate + "T00:00:00") : LocalDateTime.now().minusDays(30);
        LocalDateTime end = endDate != null ? LocalDateTime.parse(endDate + "T23:59:59") : LocalDateTime.now();

        Long currentUserId = getCurrentUserId(request);
        Map<String, Object> report = auditService.generateReport(start, end, reportType, userId, groupBy, currentUserId);

        // 转换为CSV格式
        StringBuilder csv = new StringBuilder();
        csv.append("审计报告\n");
        csv.append("时间范围: ").append(startDate).append(" 至 ").append(endDate).append("\n");
        csv.append("报告类型: ").append(reportType != null ? reportType : "综合").append("\n");
        csv.append("\n");

        if (report.containsKey("summary")) {
            @SuppressWarnings("unchecked")
            Map<String, Object> summary = (Map<String, Object>) report.get("summary");
            csv.append("概要统计\n");
            for (Map.Entry<String, Object> entry : summary.entrySet()) {
                csv.append(entry.getKey()).append(": ").append(entry.getValue()).append("\n");
            }
            csv.append("\n");
        }

        if (report.containsKey("data")) {
            csv.append("详细数据\n");
            @SuppressWarnings("unchecked")
            List<Map<String, Object>> data = (List<Map<String, Object>>) report.get("data");
            if (!data.isEmpty()) {
                // 表头
                csv.append(String.join(",", data.get(0).keySet())).append("\n");
                // 数据行
                for (Map<String, Object> row : data) {
                    csv.append(String.join(",", row.values().stream().map(v -> v != null ? v.toString() : "").toList())).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=\"audit_report.csv\"");

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