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 LogService {

    private final Map<Long, LoginLog> loginLogMap = new ConcurrentHashMap<>();
    private final Map<Long, OperationLog> operationLogMap = new ConcurrentHashMap<>();
    private final Map<Long, ExceptionLog> exceptionLogMap = new ConcurrentHashMap<>();
    private final AtomicLong loginIdCounter = new AtomicLong(1);
    private final AtomicLong operIdCounter = new AtomicLong(1);
    private final AtomicLong exIdCounter = new AtomicLong(1);

    public LogService() {
        // 初始化假数据
        loginLogMap.put(loginIdCounter.getAndIncrement(),
                new LoginLog(1L, "admin", "2026-01-10 08:00:00", "192.168.1.1", "Chrome", "success", null));
        loginLogMap.put(loginIdCounter.getAndIncrement(),
                new LoginLog(2L, "zhangsan", "2026-01-10 08:30:00", "192.168.1.2", "Firefox", "success", null));
        loginLogMap.put(loginIdCounter.getAndIncrement(),
                new LoginLog(3L, "test", "2026-01-10 09:00:00", "192.168.1.3", "Safari", "fail", "密码错误"));

        operationLogMap.put(operIdCounter.getAndIncrement(),
                new OperationLog(1L, "admin", "2026-01-10 08:05:00", "add", "user", "1",
                        "{\"before\":null,\"after\":{\"username\":\"test\"}}", "192.168.1.1"));
        operationLogMap.put(operIdCounter.getAndIncrement(),
                new OperationLog(2L, "zhangsan", "2026-01-11 10:30:00", "submit", "business", "2",
                        "{\"before\":{\"status\":\"draft\"},\"after\":{\"status\":\"submitted\"}}", "192.168.1.2"));

        exceptionLogMap.put(exIdCounter.getAndIncrement(),
                new ExceptionLog(1L, "2026-01-10 10:00:00", "NullPointerException",
                        "空指针异常", "at com.example.demo.service...", "/api/business/list", "page=1"));
    }

    /**
     * 查询登录日志。
     *
     * @requirement(name="登录日志", id="SRS-F-05-001")
     * 记录并查询用户登录成功或失败的日志信息。
     */
    public List<LoginLog> listLoginLogs(String username, String dateFrom, String dateTo) {
        List<LoginLog> all = new ArrayList<>(loginLogMap.values());
        if (username != null && !username.isEmpty()) {
            all = all.stream().filter(l -> username.equals(l.getUsername())).collect(Collectors.toList());
        }
        if (dateFrom != null && !dateFrom.isEmpty()) {
            all = all.stream().filter(l -> l.getLoginTime() != null && l.getLoginTime().compareTo(dateFrom) >= 0)
                    .collect(Collectors.toList());
        }
        if (dateTo != null && !dateTo.isEmpty()) {
            all = all.stream().filter(l -> l.getLoginTime() != null && l.getLoginTime().compareTo(dateTo) <= 0)
                    .collect(Collectors.toList());
        }
        return all;
    }

    /**
     * 查询操作日志。
     *
     * @requirement(name="操作日志", id="SRS-F-05-002")
     * 记录并查询用户的关键操作日志，支持操作前后数据对比。
     */
    public List<OperationLog> listOperationLogs(String operator, String operationType,
                                                  String dateFrom, String dateTo) {
        List<OperationLog> all = new ArrayList<>(operationLogMap.values());
        if (operator != null && !operator.isEmpty()) {
            all = all.stream().filter(l -> operator.equals(l.getOperator())).collect(Collectors.toList());
        }
        if (operationType != null && !operationType.isEmpty()) {
            all = all.stream().filter(l -> operationType.equals(l.getOperationType())).collect(Collectors.toList());
        }
        if (dateFrom != null && !dateFrom.isEmpty()) {
            all = all.stream().filter(l -> l.getOperationTime() != null && l.getOperationTime().compareTo(dateFrom) >= 0)
                    .collect(Collectors.toList());
        }
        if (dateTo != null && !dateTo.isEmpty()) {
            all = all.stream().filter(l -> l.getOperationTime() != null && l.getOperationTime().compareTo(dateTo) <= 0)
                    .collect(Collectors.toList());
        }
        return all;
    }

    /**
     * 查询异常日志。
     *
     * @requirement(name="异常日志留存", id="SRS-F-05-003")
     * 记录并查询程序运行中的异常信息及堆栈。
     */
    public List<ExceptionLog> listExceptionLogs(String exceptionType, String dateFrom, String dateTo) {
        List<ExceptionLog> all = new ArrayList<>(exceptionLogMap.values());
        if (exceptionType != null && !exceptionType.isEmpty()) {
            all = all.stream().filter(l -> exceptionType.equals(l.getExceptionType())).collect(Collectors.toList());
        }
        if (dateFrom != null && !dateFrom.isEmpty()) {
            all = all.stream().filter(l -> l.getExceptionTime() != null && l.getExceptionTime().compareTo(dateFrom) >= 0)
                    .collect(Collectors.toList());
        }
        if (dateTo != null && !dateTo.isEmpty()) {
            all = all.stream().filter(l -> l.getExceptionTime() != null && l.getExceptionTime().compareTo(dateTo) <= 0)
                    .collect(Collectors.toList());
        }
        return all;
    }

    /**
     * 溯源查询。
     *
     * @requirement(name="支持溯源查询", id="SRS-F-05-004")
     * 支持按时间、用户、操作类型等条件检索审计日志。
     */
    public Map<String, Object> traceQuery(String keyword, String dateFrom, String dateTo) {
        Map<String, Object> result = new LinkedHashMap<>();
        result.put("keyword", keyword);
        result.put("dateFrom", dateFrom);
        result.put("dateTo", dateTo);
        List<OperationLog> matchedOps = operationLogMap.values().stream()
                .filter(l -> keyword == null || keyword.isEmpty()
                        || (l.getOperator() != null && l.getOperator().contains(keyword))
                        || (l.getBusinessType() != null && l.getBusinessType().contains(keyword)))
                .filter(l -> dateFrom == null || dateFrom.isEmpty()
                        || (l.getOperationTime() != null && l.getOperationTime().compareTo(dateFrom) >= 0))
                .filter(l -> dateTo == null || dateTo.isEmpty()
                        || (l.getOperationTime() != null && l.getOperationTime().compareTo(dateTo) <= 0))
                .collect(Collectors.toList());
        result.put("operationLogs", matchedOps);
        return result;
    }
}
