package com.dne.ems.service.impl;

import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import com.dne.ems.dto.OperationLogDTO;
import com.dne.ems.model.OperationLog;
import com.dne.ems.model.UserAccount;
import com.dne.ems.model.enums.OperationType;
import com.dne.ems.repository.OperationLogRepository;
import com.dne.ems.repository.UserAccountRepository;
import com.dne.ems.security.CustomUserDetails;
import com.dne.ems.service.OperationLogService;

import jakarta.servlet.http.HttpServletRequest;

/**
 * 操作日志服务实现类，提供记录和查询用户操作日志的功能。
 *
 * @version 1.0
 * @since 2025-06-20
 */
@Service
public class OperationLogServiceImpl implements OperationLogService {

    private static final Logger log = LoggerFactory.getLogger(OperationLogServiceImpl.class);
    
    @Autowired
    private OperationLogRepository operationLogRepository;
    
    @Autowired
    private UserAccountRepository userAccountRepository;

    @Override
    public void recordOperation(OperationType operationType, String description, String targetId, String targetType) {
        UserAccount currentUser = getCurrentUser();
        if (currentUser == null) {
            log.warn("无法记录操作日志：未找到当前用户，操作描述: {}", description);
            return;
        }
        recordOperation(currentUser, operationType, description, targetId, targetType);
    }

    @Override
    public void recordOperation(UserAccount user, OperationType operationType, String description, String targetId, String targetType) {
        try {
            if (user == null) {
                log.warn("无法记录操作日志：用户为null");
                return;
            }
            
            String ipAddress = getClientIpAddress();
            
            OperationLog operationLog = new OperationLog(
                user, 
                operationType, 
                description, 
                targetId, 
                targetType, 
                ipAddress
            );
            
            operationLogRepository.save(operationLog);
            log.debug("已记录操作日志：用户={}, 操作={}, 描述={}", 
                    user.getName(), operationType, description);
        } catch (Exception e) {
            log.error("记录操作日志失败", e);
        }
    }

    @Override
    public void recordLogin(Long userId, String ipAddress, boolean success) {
        try {
            UserAccount user = userAccountRepository.findById(userId).orElse(null);
            if (user == null) {
                log.warn("无法记录登录操作：未找到用户ID={}", userId);
                return;
            }
            
            String description = success ? "用户登录成功" : "用户登录失败";
            
            OperationLog operationLog = new OperationLog(
                user, 
                OperationType.LOGIN, 
                description, 
                userId.toString(), 
                "UserAccount", 
                ipAddress
            );
            
            operationLogRepository.save(operationLog);
            log.debug("已记录登录操作：用户={}, 结果={}", user.getName(), success ? "成功" : "失败");
        } catch (Exception e) {
            log.error("记录登录操作失败", e);
        }
    }

    @Override
    public void recordLogout(Long userId) {
        try {
            UserAccount user = userAccountRepository.findById(userId).orElse(null);
            if (user == null) {
                log.warn("无法记录登出操作：未找到用户ID={}", userId);
                return;
            }
            
            String ipAddress = getClientIpAddress();
            
            OperationLog operationLog = new OperationLog(
                user, 
                OperationType.LOGOUT, 
                "用户登出系统", 
                userId.toString(), 
                "UserAccount", 
                ipAddress
            );
            
            operationLogRepository.save(operationLog);
            log.debug("已记录登出操作：用户={}", user.getName());
        } catch (Exception e) {
            log.error("记录登出操作失败", e);
        }
    }

    @Override
    public List<OperationLogDTO> getUserOperationLogs(Long userId) {
        List<OperationLog> logs = operationLogRepository.findByUserId(userId);
        return convertToDTO(logs);
    }

    @Override
    public List<OperationLogDTO> getAllOperationLogs() {
        List<OperationLog> logs = operationLogRepository.findAll();
        return convertToDTO(logs);
    }

    @Override
    public List<OperationLogDTO> queryOperationLogs(Long userId, OperationType operationType, 
                                                  LocalDateTime startTime, LocalDateTime endTime) {
        List<OperationLog> logs = operationLogRepository.findByConditions(userId, operationType, startTime, endTime);
        return convertToDTO(logs);
    }
    
    /**
     * 将操作日志实体列表转换为DTO列表
     * 
     * @param logs 操作日志实体列表
     * @return 操作日志DTO列表
     */
    private List<OperationLogDTO> convertToDTO(List<OperationLog> logs) {
        return logs.stream()
                .map(this::convertToDTO)
                .collect(Collectors.toList());
    }
    
    /**
     * 将操作日志实体转换为DTO
     * 
     * @param log 操作日志实体
     * @return 操作日志DTO
     */
    private OperationLogDTO convertToDTO(OperationLog log) {
        UserAccount user = log.getUser();
        
        return OperationLogDTO.builder()
                .id(log.getId())
                .userId(user != null ? user.getId() : null)
                .userName(user != null ? user.getName() : "未知用户")
                .operationType(log.getOperationType())
                .operationTypeDesc(OperationLogDTO.getOperationTypeDesc(log.getOperationType()))
                .description(log.getDescription())
                .targetId(log.getTargetId())
                .targetType(log.getTargetType())
                .ipAddress(log.getIpAddress())
                .createdAt(log.getCreatedAt())
                .build();
    }
    
    /**
     * 获取当前登录用户
     * 
     * @return 当前用户实体，如果未登录则返回null
     */
    private UserAccount getCurrentUser() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (authentication != null && authentication.getPrincipal() instanceof CustomUserDetails) {
            return ((CustomUserDetails) authentication.getPrincipal()).getUserAccount();
        }
        return null;
    }
    
    /**
     * 获取客户端IP地址
     * 
     * @return IP地址字符串
     */
    private String getClientIpAddress() {
        try {
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            if (attributes != null) {
                HttpServletRequest request = attributes.getRequest();
                String ip = request.getHeader("X-Forwarded-For");
                
                if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
                    ip = request.getHeader("Proxy-Client-IP");
                }
                if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
                    ip = request.getHeader("WL-Proxy-Client-IP");
                }
                if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
                    ip = request.getRemoteAddr();
                }
                
                return ip;
            }
        } catch (Exception e) {
            log.warn("获取客户端IP地址失败", e);
        }
        
        return "unknown";
    }
} 