package cn.novalon.manage.sys.audit.service;

import cn.novalon.manage.sys.audit.domain.AuditLog;
import cn.novalon.manage.sys.audit.repository.IAuditLogRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.core.scheduler.Schedulers;

import java.time.LocalDateTime;
import java.util.concurrent.Executor;

/**
 * 审计日志服务
 * 
 * 文件定义：封装审计日志的业务逻辑
 * 涉及业务：审计日志的保存、查询、统计等操作
 * 算法：使用异步线程池处理审计日志，不阻塞主流程
 * 
 * @author 张翔
 * @date 2026-04-01
 */
@Service
public class AuditLogService {

    private static final Logger logger = LoggerFactory.getLogger(AuditLogService.class);

    private final IAuditLogRepository auditLogRepository;
    private final Executor auditLogExecutor;

    public AuditLogService(IAuditLogRepository auditLogRepository, 
                          Executor auditLogExecutor) {
        this.auditLogRepository = auditLogRepository;
        this.auditLogExecutor = auditLogExecutor;
    }

    @Async("auditLogExecutor")
    public Mono<AuditLog> saveAsync(AuditLog auditLog) {
        logger.debug("异步保存审计日志: {} - {}", auditLog.getEntityType(), auditLog.getOperationType());
        
        return auditLogRepository.save(auditLog)
                .doOnSuccess(saved -> logger.debug("审计日志保存成功: ID={}", saved.getId()))
                .doOnError(error -> logger.error("审计日志保存失败: {}", error.getMessage()))
                .subscribeOn(Schedulers.fromExecutor(auditLogExecutor));
    }

    public Mono<AuditLog> findById(Long id) {
        return auditLogRepository.findById(id);
    }

    public Flux<AuditLog> findByEntityType(String entityType) {
        return auditLogRepository.findByEntityType(entityType);
    }

    public Flux<AuditLog> findByEntityId(Long entityId) {
        return auditLogRepository.findByEntityId(entityId);
    }

    public Flux<AuditLog> findByOperator(String operator) {
        return auditLogRepository.findByOperator(operator);
    }

    public Flux<AuditLog> findByOperationType(String operationType) {
        return auditLogRepository.findByOperationType(operationType);
    }

    public Flux<AuditLog> findByOperationTimeBetween(LocalDateTime startTime, LocalDateTime endTime) {
        return auditLogRepository.findByOperationTimeBetween(startTime, endTime);
    }

    public Flux<AuditLog> findByEntityTypeAndEntityId(String entityType, Long entityId) {
        return auditLogRepository.findByEntityTypeAndEntityId(entityType, entityId);
    }

    public Mono<Long> countByEntityType(String entityType) {
        return auditLogRepository.countByEntityType(entityType);
    }

    public Mono<Long> countByOperationType(String operationType) {
        return auditLogRepository.countByOperationType(operationType);
    }

    public Mono<Long> countByOperator(String operator) {
        return auditLogRepository.countByOperator(operator);
    }

    public Mono<Long> countByOperationTimeBetween(LocalDateTime startTime, LocalDateTime endTime) {
        return auditLogRepository.countByOperationTimeBetween(startTime, endTime);
    }
}
