package dev.lions.unionflow.server.service;

import dev.lions.unionflow.server.entity.SystemLog;
import dev.lions.unionflow.server.repository.SystemLogRepository;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import jakarta.transaction.Transactional;
import lombok.extern.slf4j.Slf4j;

import java.time.LocalDateTime;

/**
 * Service centralisé pour la création de logs système.
 * Gère la persistence des logs dans la base de données.
 *
 * @author UnionFlow Team
 * @version 1.0
 * @since 2026-03-15
 */
@Slf4j
@ApplicationScoped
public class SystemLoggingService {

    @Inject
    SystemLogRepository systemLogRepository;

    /**
     * Logger une requête HTTP
     */
    @Transactional
    public void logRequest(
            String method,
            String endpoint,
            Integer httpStatusCode,
            String userId,
            String ipAddress,
            String sessionId,
            Long durationMs
    ) {
        try {
            SystemLog systemLog = new SystemLog();
            systemLog.setLevel(getLogLevelFromStatusCode(httpStatusCode));
            systemLog.setSource("API");
            systemLog.setMessage(String.format("%s %s - %d (%dms)", method, endpoint, httpStatusCode, durationMs));
            systemLog.setDetails(String.format("User: %s, IP: %s, Duration: %dms", userId, ipAddress, durationMs));
            systemLog.setTimestamp(LocalDateTime.now());
            systemLog.setUserId(userId);
            systemLog.setIpAddress(ipAddress);
            systemLog.setSessionId(sessionId);
            systemLog.setEndpoint(endpoint);
            systemLog.setHttpStatusCode(httpStatusCode);

            systemLogRepository.persist(systemLog);
        } catch (Exception e) {
            // Ne pas propager les erreurs de logging pour ne pas casser l'application
            log.error("Failed to persist request log", e);
        }
    }

    /**
     * Logger une erreur (exception)
     */
    @Transactional
    public void logError(
            String source,
            String message,
            String details,
            String userId,
            String ipAddress,
            String endpoint,
            Integer httpStatusCode
    ) {
        try {
            SystemLog systemLog = new SystemLog();
            systemLog.setLevel("ERROR");
            systemLog.setSource(source);
            systemLog.setMessage(message);
            systemLog.setDetails(details);
            systemLog.setTimestamp(LocalDateTime.now());
            systemLog.setUserId(userId);
            systemLog.setIpAddress(ipAddress);
            systemLog.setEndpoint(endpoint);
            systemLog.setHttpStatusCode(httpStatusCode);

            systemLogRepository.persist(systemLog);
        } catch (Exception e) {
            log.error("Failed to persist error log", e);
        }
    }

    /**
     * Logger une erreur critique
     */
    @Transactional
    public void logCritical(
            String source,
            String message,
            String details,
            String userId,
            String ipAddress
    ) {
        try {
            SystemLog systemLog = new SystemLog();
            systemLog.setLevel("CRITICAL");
            systemLog.setSource(source);
            systemLog.setMessage(message);
            systemLog.setDetails(details);
            systemLog.setTimestamp(LocalDateTime.now());
            systemLog.setUserId(userId);
            systemLog.setIpAddress(ipAddress);

            systemLogRepository.persist(systemLog);
        } catch (Exception e) {
            log.error("Failed to persist critical log", e);
        }
    }

    /**
     * Logger un warning
     */
    @Transactional
    public void logWarning(
            String source,
            String message,
            String details,
            String userId,
            String ipAddress
    ) {
        try {
            SystemLog systemLog = new SystemLog();
            systemLog.setLevel("WARNING");
            systemLog.setSource(source);
            systemLog.setMessage(message);
            systemLog.setDetails(details);
            systemLog.setTimestamp(LocalDateTime.now());
            systemLog.setUserId(userId);
            systemLog.setIpAddress(ipAddress);

            systemLogRepository.persist(systemLog);
        } catch (Exception e) {
            log.error("Failed to persist warning log", e);
        }
    }

    /**
     * Logger une info
     */
    @Transactional
    public void logInfo(
            String source,
            String message,
            String details
    ) {
        try {
            SystemLog systemLog = new SystemLog();
            systemLog.setLevel("INFO");
            systemLog.setSource(source);
            systemLog.setMessage(message);
            systemLog.setDetails(details);
            systemLog.setTimestamp(LocalDateTime.now());

            systemLogRepository.persist(systemLog);
        } catch (Exception e) {
            log.error("Failed to persist info log", e);
        }
    }

    /**
     * Logger un événement de debug
     */
    @Transactional
    public void logDebug(
            String source,
            String message,
            String details
    ) {
        try {
            SystemLog systemLog = new SystemLog();
            systemLog.setLevel("DEBUG");
            systemLog.setSource(source);
            systemLog.setMessage(message);
            systemLog.setDetails(details);
            systemLog.setTimestamp(LocalDateTime.now());

            systemLogRepository.persist(systemLog);
        } catch (Exception e) {
            log.error("Failed to persist debug log", e);
        }
    }

    /**
     * Déterminer le niveau de log selon le code HTTP
     */
    private String getLogLevelFromStatusCode(Integer statusCode) {
        if (statusCode == null) {
            return "INFO";
        }

        if (statusCode >= 500) {
            return "ERROR";
        } else if (statusCode >= 400) {
            return "WARNING";
        } else if (statusCode >= 300) {
            return "INFO";
        } else {
            return "DEBUG";
        }
    }
}
