package com.erp.audit.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.erp.audit.dto.ComplianceReportRequest;
import com.erp.audit.entity.AuditLog;
import com.erp.audit.entity.ComplianceReport;
import com.erp.audit.repository.AuditLogRepository;
import com.erp.audit.repository.ComplianceReportRepository;
import com.erp.audit.service.ComplianceService;
import com.erp.audit.service.AuditLogService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 合规审计服务实现
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class ComplianceServiceImpl implements ComplianceService {

    private final ComplianceReportRepository reportRepository;
    private final AuditLogRepository auditLogRepository;
    private final AuditLogService auditLogService;

    @Override
    @Transactional
    public ComplianceReport generateReport(ComplianceReportRequest request) {
        log.info("📋 开始生成合规报告 - 类型: {}", request.getReportType());

        LocalDateTime startTime = request.getStartTime() != null ? request.getStartTime() : LocalDateTime.now().minusDays(30);
        LocalDateTime endTime = request.getEndTime() != null ? request.getEndTime() : LocalDateTime.now();

        // 查询审计日志
        LambdaQueryWrapper<AuditLog> wrapper = new LambdaQueryWrapper<>();
        wrapper.between(AuditLog::getCreatedAt, startTime, endTime);
        if (request.getModules() != null && !request.getModules().isEmpty()) {
            wrapper.in(AuditLog::getModule, request.getModules());
        }
        if (!Boolean.TRUE.equals(request.getIncludeFailed())) {
            wrapper.eq(AuditLog::getAuditStatus, "SUCCESS");
        }
        List<AuditLog> logs = auditLogRepository.selectList(wrapper);

        // 统计分析
        Map<String, Object> stats = analyzeLogs(logs, request);

        // 构建报告
        String reportNo = generateReportNo(request.getReportType());
        ComplianceReport report = ComplianceReport.builder()
                .reportNo(reportNo)
                .reportType(request.getReportType())
                .reportName(request.getReportName() != null ? request.getReportName() : reportNo)
                .startTime(startTime)
                .endTime(endTime)
                .auditScope(request.getModules() != null ? String.join(",", request.getModules()) : "全部")
                .auditConclusion(determineConclusion(stats))
                .issueCount((Integer) stats.get("issueCount"))
                .highRiskCount((Integer) stats.get("highRiskCount"))
                .mediumRiskCount((Integer) stats.get("mediumRiskCount"))
                .lowRiskCount((Integer) stats.get("lowRiskCount"))
                .reportStatus("GENERATED")
                .contentJson(toJson(stats))
                .generatedBy(request.getGeneratedBy())
                .createdAt(LocalDateTime.now())
                .build();

        reportRepository.insert(report);
        log.info("✅ 合规报告生成完成 - 报告编号: {}", reportNo);

        return report;
    }

    private Map<String, Object> analyzeLogs(List<AuditLog> logs, ComplianceReportRequest request) {
        Map<String, Object> stats = new HashMap<>();

        long total = logs.size();
        long success = logs.stream().filter(l -> "SUCCESS".equals(l.getAuditStatus())).count();
        long fail = logs.stream().filter(l -> "FAIL".equals(l.getAuditStatus())).count();
        long sensitive = logs.stream().filter(l -> Boolean.TRUE.equals(l.getSensitive())).count();

        // 操作类型分布
        Map<String, Long> opTypeDist = logs.stream()
                .collect(Collectors.groupingBy(AuditLog::getOperationType, Collectors.counting()));

        // 模块分布
        Map<String, Long> moduleDist = logs.stream()
                .collect(Collectors.groupingBy(AuditLog::getModule, Collectors.counting()));

        // 失败操作分析
        List<AuditLog> failedLogs = logs.stream()
                .filter(l -> "FAIL".equals(l.getAuditStatus()))
                .collect(Collectors.toList());

        // 高风险：敏感操作失败
        long highRisk = failedLogs.stream()
                .filter(l -> Boolean.TRUE.equals(l.getSensitive()))
                .count();

        // 中风险：数据删除/修改类操作失败
        long mediumRisk = failedLogs.stream()
                .filter(l -> !Boolean.TRUE.equals(l.getSensitive()))
                .filter(l -> "DELETE".equals(l.getOperationType()) || "UPDATE".equals(l.getOperationType()))
                .count();

        // 低风险：一般查询操作失败
        long lowRisk = fail - highRisk - mediumRisk;

        stats.put("totalCount", total);
        stats.put("successCount", success);
        stats.put("failCount", fail);
        stats.put("sensitiveCount", sensitive);
        stats.put("operationTypeDistribution", opTypeDist);
        stats.put("moduleDistribution", moduleDist);
        stats.put("failedOperations", failedLogs.stream().limit(50).collect(Collectors.toList()));
        stats.put("issueCount", (int) fail);
        stats.put("highRiskCount", (int) highRisk);
        stats.put("mediumRiskCount", (int) mediumRisk);
        stats.put("lowRiskCount", (int) lowRisk);

        return stats;
    }

    private String determineConclusion(Map<String, Object> stats) {
        int highRisk = (Integer) stats.get("highRiskCount");
        int total = ((Long) stats.get("totalCount")).intValue();
        if (total == 0) return "PASS";
        double failRate = (Integer) stats.get("failCount") * 1.0 / total;
        if (highRisk > 0 || failRate > 0.1) return "FAIL";
        if (failRate > 0.05) return "WARNING";
        return "PASS";
    }

    private String generateReportNo(String reportType) {
        String prefix = switch (reportType) {
            case "DAILY" -> "DR";
            case "WEEKLY" -> "WR";
            case "MONTHLY" -> "MR";
            case "QUARTERLY" -> "QR";
            case "ANNUAL" -> "AR";
            default -> "CR";
        };
        return prefix + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
    }

    private String toJson(Map<String, Object> stats) {
        try {
            return new com.fasterxml.jackson.databind.ObjectMapper()
                    .writeValueAsString(stats);
        } catch (Exception e) {
            return "{}";
        }
    }

    @Override
    public IPage<ComplianceReport> listReports(Long tenantId, int pageNum, int pageSize) {
        return reportRepository.selectPage(new Page<>(pageNum, pageSize), tenantId);
    }

    @Override
    public ComplianceReport getReportById(Long id) {
        return reportRepository.selectById(id);
    }

    @Override
    public ComplianceReport getReportByNo(String reportNo) {
        return reportRepository.selectByReportNo(reportNo);
    }

    @Override
    @Transactional
    public void reviewReport(Long id, String reviewer, String conclusion) {
        ComplianceReport report = reportRepository.selectById(id);
        if (report == null) {
            throw new RuntimeException("报告不存在: " + id);
        }
        report.setReviewedBy(reviewer);
        report.setReviewedAt(LocalDateTime.now());
        report.setAuditConclusion(conclusion);
        report.setReportStatus("DISTRIBUTED");
        reportRepository.updateById(report);
    }

    @Override
    public Object getComplianceSummary(Long tenantId, LocalDateTime startTime, LocalDateTime endTime) {
        LambdaQueryWrapper<AuditLog> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(tenantId != null, AuditLog::getTenantId, tenantId);
        wrapper.between(AuditLog::getCreatedAt, startTime, endTime);
        List<AuditLog> logs = auditLogRepository.selectList(wrapper);

        Map<String, Object> summary = new HashMap<>();
        summary.put("totalOperations", logs.size());
        summary.put("successRate", logs.isEmpty() ? 100.0 : 
                logs.stream().filter(l -> "SUCCESS".equals(l.getAuditStatus())).count() * 100.0 / logs.size());
        summary.put("sensitiveOperations", logs.stream().filter(l -> Boolean.TRUE.equals(l.getSensitive())).count());
        summary.put("uniqueUsers", logs.stream().map(AuditLog::getUserId).filter(Objects::nonNull).distinct().count());
        summary.put("topModules", logs.stream()
                .collect(Collectors.groupingBy(AuditLog::getModule, Collectors.counting()))
                .entrySet().stream().sorted(Map.Entry.<String, Long>comparingByValue().reversed()).limit(5)
                .collect(Collectors.toList()));
        return summary;
    }

    @Override
    public Object riskAssessment(Long tenantId, LocalDateTime startTime, LocalDateTime endTime) {
        LambdaQueryWrapper<AuditLog> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(tenantId != null, AuditLog::getTenantId, tenantId);
        wrapper.between(AuditLog::getCreatedAt, startTime, endTime);
        List<AuditLog> logs = auditLogRepository.selectList(wrapper);

        List<AuditLog> failedLogs = logs.stream()
                .filter(l -> "FAIL".equals(l.getAuditStatus()))
                .collect(Collectors.toList());

        Map<String, Object> assessment = new HashMap<>();
        assessment.put("overallRisk", failedLogs.isEmpty() ? "LOW" : 
                failedLogs.stream().anyMatch(l -> Boolean.TRUE.equals(l.getSensitive())) ? "HIGH" : "MEDIUM");
        assessment.put("failedOperationCount", failedLogs.size());
        assessment.put("highRiskOperations", failedLogs.stream()
                .filter(l -> Boolean.TRUE.equals(l.getSensitive()))
                .collect(Collectors.toList()));
        assessment.put("riskByModule", failedLogs.stream()
                .collect(Collectors.groupingBy(AuditLog::getModule, Collectors.counting())));
        return assessment;
    }
}
