<?php

namespace ControleFrotas\Utils;

use ControleFrotas\Config\Database;

/**
 * Classe para logging do sistema
 */
class Logger
{
    private static bool $logToDatabase = true;
    private static bool $logToFile = true;
    private static string $logPath = 'logs/';

    /**
     * Configura o logger
     */
    public static function configure(bool $logToDatabase = true, bool $logToFile = true, string $logPath = 'logs/'): void
    {
        self::$logToDatabase = $logToDatabase;
        self::$logToFile = $logToFile;
        self::$logPath = rtrim($logPath, '/') . '/';
        
        // Criar diretório de logs se não existir
        if (self::$logToFile && !is_dir(self::$logPath)) {
            mkdir(self::$logPath, 0755, true);
        }
    }

    /**
     * Log de debug
     */
    public static function debug(string $message, array $context = []): void
    {
        self::log('debug', $message, $context);
    }

    /**
     * Log de informação
     */
    public static function info(string $message, array $context = []): void
    {
        self::log('info', $message, $context);
    }

    /**
     * Log de warning
     */
    public static function warning(string $message, array $context = []): void
    {
        self::log('warning', $message, $context);
    }

    /**
     * Log de erro
     */
    public static function error(string $message, array $context = []): void
    {
        self::log('error', $message, $context);
    }

    /**
     * Log crítico
     */
    public static function critical(string $message, array $context = []): void
    {
        self::log('critical', $message, $context);
    }

    /**
     * Método principal de logging
     */
    private static function log(string $level, string $message, array $context = []): void
    {
        $timestamp = date('Y-m-d H:i:s');
        $userId = $context['user_id'] ?? self::getCurrentUserId();
        $ipAddress = $_SERVER['REMOTE_ADDR'] ?? null;
        $userAgent = $_SERVER['HTTP_USER_AGENT'] ?? null;
        $endpoint = $_SERVER['REQUEST_URI'] ?? null;
        $method = $_SERVER['REQUEST_METHOD'] ?? null;

        // Log para banco de dados
        if (self::$logToDatabase) {
            try {
                Database::execute(
                    "INSERT INTO system_logs (level, message, context, user_id, ip_address, user_agent, endpoint, method) 
                     VALUES (?, ?, ?, ?, ?, ?, ?, ?)",
                    [
                        $level,
                        $message,
                        !empty($context) ? json_encode($context, JSON_UNESCAPED_UNICODE) : null,
                        $userId,
                        $ipAddress,
                        $userAgent,
                        $endpoint,
                        $method
                    ]
                );
            } catch (\Exception $e) {
                // Se falhar ao salvar no banco, salva apenas em arquivo
                self::logToFile($level, $message, $context, $timestamp);
                self::logToFile('error', 'Falha ao salvar log no banco: ' . $e->getMessage(), [], $timestamp);
            }
        }

        // Log para arquivo
        if (self::$logToFile) {
            self::logToFile($level, $message, $context, $timestamp);
        }
    }

    /**
     * Salva log em arquivo
     */
    private static function logToFile(string $level, string $message, array $context, string $timestamp): void
    {
        $logFile = self::$logPath . 'app-' . date('Y-m-d') . '.log';
        
        $contextString = !empty($context) ? ' | Context: ' . json_encode($context, JSON_UNESCAPED_UNICODE) : '';
        $logLine = "[$timestamp] [$level] $message$contextString" . PHP_EOL;
        
        file_put_contents($logFile, $logLine, FILE_APPEND | LOCK_EX);
    }

    /**
     * Obtém o ID do usuário atual (se disponível)
     */
    private static function getCurrentUserId(): ?string
    {
        $token = JWT::extractFromHeader();
        if (!$token) {
            return null;
        }

        $payload = JWT::decode($token);
        return $payload['user_id'] ?? null;
    }

    /**
     * Log de requisição HTTP
     */
    public static function httpRequest(string $method, string $endpoint, array $params = [], ?string $userId = null): void
    {
        self::info('HTTP Request', [
            'method' => $method,
            'endpoint' => $endpoint,
            'params' => $params,
            'user_id' => $userId,
            'ip' => $_SERVER['REMOTE_ADDR'] ?? null,
            'user_agent' => $_SERVER['HTTP_USER_AGENT'] ?? null
        ]);
    }

    /**
     * Log de resposta HTTP
     */
    public static function httpResponse(int $statusCode, ?string $message = null, ?string $userId = null): void
    {
        $level = $statusCode >= 500 ? 'error' : ($statusCode >= 400 ? 'warning' : 'info');
        
        self::log($level, "HTTP Response: $statusCode" . ($message ? " - $message" : ''), [
            'status_code' => $statusCode,
            'message' => $message,
            'user_id' => $userId
        ]);
    }

    /**
     * Log de login de usuário
     */
    public static function userLogin(string $userId, string $email, bool $success = true): void
    {
        $level = $success ? 'info' : 'warning';
        $message = $success ? 'Login realizado com sucesso' : 'Tentativa de login falhada';
        
        self::log($level, $message, [
            'user_id' => $userId,
            'email' => $email,
            'ip' => $_SERVER['REMOTE_ADDR'] ?? null,
            'user_agent' => $_SERVER['HTTP_USER_AGENT'] ?? null
        ]);
    }

    /**
     * Log de operações no banco de dados
     */
    public static function databaseOperation(string $operation, string $table, array $data = [], ?string $userId = null): void
    {
        self::info("Database $operation on $table", [
            'operation' => $operation,
            'table' => $table,
            'data' => $data,
            'user_id' => $userId
        ]);
    }

    /**
     * Log de sincronização de dados
     */
    public static function syncOperation(string $type, int $count, bool $success = true, ?string $error = null): void
    {
        $level = $success ? 'info' : 'error';
        $message = $success ? "Sincronização de $type concluída: $count registros" : "Falha na sincronização de $type";
        
        self::log($level, $message, [
            'sync_type' => $type,
            'count' => $count,
            'success' => $success,
            'error' => $error
        ]);
    }

    /**
     * Limpa logs antigos
     */
    public static function cleanup(int $daysToKeep = 30): int
    {
        $deleted = 0;
        
        // Limpar logs do banco
        if (self::$logToDatabase) {
            try {
                $deleted = Database::execute(
                    "DELETE FROM system_logs WHERE created_at < DATE_SUB(NOW(), INTERVAL ? DAY)",
                    [$daysToKeep]
                );
            } catch (\Exception $e) {
                self::error('Erro ao limpar logs do banco', ['error' => $e->getMessage()]);
            }
        }

        // Limpar logs de arquivo
        if (self::$logToFile && is_dir(self::$logPath)) {
            $files = glob(self::$logPath . '*.log');
            $cutoffDate = strtotime("-$daysToKeep days");
            
            foreach ($files as $file) {
                if (filemtime($file) < $cutoffDate) {
                    unlink($file);
                }
            }
        }

        return $deleted;
    }
} 
