package com.example.demo.service;

import com.example.demo.model.ExceptionLog;
import com.example.demo.model.LoginLog;
import com.example.demo.model.OperationLog;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.Collectors;

/**
 * 审计日志服务。
 * <p>基于内存数据，提供登录日志、操作日志、异常日志的留存与溯源查询。</p>
 */
@Service
public class AuditLogService {

    private final Map<Long, LoginLog> loginLogStore = new ConcurrentHashMap<>();
    private final Map<Long, OperationLog> operationLogStore = new ConcurrentHashMap<>();
    private final Map<Long, ExceptionLog> exceptionLogStore = new ConcurrentHashMap<>();
    private final AtomicLong idGen = new AtomicLong(1);

    public AuditLogService() {
        initMockData();
    }

    private void initMockData() {
        loginLogStore.put(1L, new LoginLog(1L, "admin", "2024-01-15 09:00:00",
                "192.168.1.1", "Chrome 120", "成功", null));
        loginLogStore.put(2L, new LoginLog(2L, "zhangsan", "2024-01-15 09:30:00",
                "192.168.1.2", "Firefox 121", "成功", null));
        loginLogStore.put(3L, new LoginLog(3L, "test_user", "2024-01-15 08:00:00",
                "10.0.0.1", "Safari", "失败", "密码错误"));

        operationLogStore.put(1L, new OperationLog(1L, "admin", "2024-01-15 10:00:00",
                "新增", "用户管理", 1L, "{}", "{\"username\":\"new_user\"}", "192.168.1.1"));
        operationLogStore.put(2L, new OperationLog(2L, "admin", "2024-01-15 11:00:00",
                "审核", "业务管理", 2L, "{\"status\":\"待审核\"}", "{\"status\":\"通过\"}", "192.168.1.1"));

        exceptionLogStore.put(1L, new ExceptionLog(1L, "2024-01-15 12:00:00",
                "java.lang.NullPointerException", "空指针异常",
                "at com.example.demo.service...", "/api/user/list", "{\"page\":1}"));

        idGen.set(4);
    }

    // ========== 登录日志 ==========

    /**
     * 记录登录日志。
     *
     * @requirement(name="登录日志", id="SRS-F-05-001")
     * @param log 登录日志
     * @return 已保存的日志
     */
    public LoginLog saveLoginLog(LoginLog log) {
        if (log.getLogId() == null) {
            log.setLogId(idGen.getAndIncrement());
        }
        if (log.getLoginTime() == null) {
            log.setLoginTime(java.time.LocalDateTime.now().toString().replace("T", " "));
        }
        loginLogStore.put(log.getLogId(), log);
        return log;
    }

    /**
     * 查询登录日志，支持按用户名、时间范围筛选。
     *
     * @requirement(name="支持溯源查询", id="SRS-F-05-004")
     * @param username    用户名（可选）
     * @param startDate   开始日期（可选）
     * @param endDate     结束日期（可选）
     * @return 登录日志列表
     */
    public List<LoginLog> queryLoginLogs(String username, String startDate, String endDate) {
        return loginLogStore.values().stream()
                .filter(l -> username == null || l.getUsername().contains(username))
                .filter(l -> startDate == null || l.getLoginTime().compareTo(startDate) >= 0)
                .filter(l -> endDate == null || l.getLoginTime().compareTo(endDate) <= 0)
                .sorted(Comparator.comparing(LoginLog::getLoginTime).reversed())
                .collect(Collectors.toList());
    }

    // ========== 操作日志 ==========

    /**
     * 记录操作日志。
     *
     * @requirement(name="操作日志", id="SRS-F-05-002")
     * @param log 操作日志
     * @return 已保存的日志
     */
    public OperationLog saveOperationLog(OperationLog log) {
        if (log.getLogId() == null) {
            log.setLogId(idGen.getAndIncrement());
        }
        if (log.getOperateTime() == null) {
            log.setOperateTime(java.time.LocalDateTime.now().toString().replace("T", " "));
        }
        operationLogStore.put(log.getLogId(), log);
        return log;
    }

    /**
     * 查询操作日志，支持按操作人、操作类型、业务类型筛选。
     *
     * @requirement(name="支持溯源查询", id="SRS-F-05-004")
     * @param operator     操作人（可选）
     * @param operateType  操作类型（可选）
     * @param businessType 业务类型（可选）
     * @return 操作日志列表
     */
    public List<OperationLog> queryOperationLogs(String operator, String operateType, String businessType) {
        return operationLogStore.values().stream()
                .filter(l -> operator == null || l.getOperator().contains(operator))
                .filter(l -> operateType == null || l.getOperateType().equals(operateType))
                .filter(l -> businessType == null || l.getBusinessType().equals(businessType))
                .sorted(Comparator.comparing(OperationLog::getOperateTime).reversed())
                .collect(Collectors.toList());
    }

    // ========== 异常日志 ==========

    /**
     * 记录异常日志。
     *
     * @requirement(name="异常日志留存", id="SRS-F-05-003")
     * @param log 异常日志
     * @return 已保存的日志
     */
    public ExceptionLog saveExceptionLog(ExceptionLog log) {
        if (log.getLogId() == null) {
            log.setLogId(idGen.getAndIncrement());
        }
        if (log.getExceptionTime() == null) {
            log.setExceptionTime(java.time.LocalDateTime.now().toString().replace("T", " "));
        }
        exceptionLogStore.put(log.getLogId(), log);
        return log;
    }

    /**
     * 查询异常日志，支持按异常类型、时间范围筛选。
     *
     * @requirement(name="支持溯源查询", id="SRS-F-05-004")
     * @param exceptionType 异常类型（可选）
     * @param startDate     开始日期（可选）
     * @param endDate       结束日期（可选）
     * @return 异常日志列表
     */
    public List<ExceptionLog> queryExceptionLogs(String exceptionType, String startDate, String endDate) {
        return exceptionLogStore.values().stream()
                .filter(l -> exceptionType == null || l.getExceptionType().contains(exceptionType))
                .filter(l -> startDate == null || l.getExceptionTime().compareTo(startDate) >= 0)
                .filter(l -> endDate == null || l.getExceptionTime().compareTo(endDate) <= 0)
                .sorted(Comparator.comparing(ExceptionLog::getExceptionTime).reversed())
                .collect(Collectors.toList());
    }

    /**
     * 全链路溯源查询（登录+操作+异常）。
     *
     * @requirement(name="支持溯源查询", id="SRS-F-05-004")
     * @param traceId 溯源标识
     * @return 溯源结果
     */
    public Map<String, Object> trace(String traceId) {
        Map<String, Object> result = new LinkedHashMap<>();
        result.put("traceId", traceId);
        result.put("loginLogs", loginLogStore.values().stream().limit(5).collect(Collectors.toList()));
        result.put("operationLogs", operationLogStore.values().stream().limit(5).collect(Collectors.toList()));
        result.put("exceptionLogs", exceptionLogStore.values().stream().limit(5).collect(Collectors.toList()));
        return result;
    }
}
