<?php
/**
 * Sistema de logging estructurado con Monolog
 * Configuración centralizada para toda la aplicación
 */

require_once __DIR__ . '/../vendor/autoload.php';

use Monolog\Logger;
use Monolog\Handler\StreamHandler;
use Monolog\Handler\RotatingFileHandler;
use Monolog\Handler\ErrorLogHandler;
use Monolog\Formatter\LineFormatter;
use Monolog\Formatter\JsonFormatter;
use Monolog\Processor\WebProcessor;
use Monolog\Processor\IntrospectionProcessor;

class LoggerFactory {
    private static $loggers = [];
    private static $defaultLevel = Logger::INFO;
    private static $logPath;
    
    /**
     * Inicializar configuración de logging
     */
    public static function init() {
        self::$logPath = getenv('LOG_PATH') ?: __DIR__ . '/../logs';
        
        // Crear directorio de logs si no existe
        if (!is_dir(self::$logPath)) {
            mkdir(self::$logPath, 0755, true);
        }
        
        // Configurar nivel según ambiente
        $level = getenv('LOG_LEVEL') ?: 'INFO';
        self::$defaultLevel = constant("Monolog\Logger::" . strtoupper($level));
    }
    
    /**
     * Obtener logger para un canal específico
     * 
     * @param string $channel Nombre del canal (ej: 'webhook', 'bot', 'api')
     * @param array $options Opciones adicionales
     * @return Logger
     */
    public static function getLogger(string $channel, array $options = []): Logger {
        // Retornar logger existente si ya está creado
        if (isset(self::$loggers[$channel])) {
            return self::$loggers[$channel];
        }
        
        if (!self::$logPath) {
            self::init();
        }
        
        $logger = new Logger($channel);
        
        // Opciones por defecto
        $defaultOptions = [
            'rotating' => true,          // Usar archivos rotativos
            'max_files' => 14,           // Mantener últimos 14 días
            'json' => false,             // Formato JSON (útil para parseo)
            'include_context' => true,   // Incluir información de contexto
            'level' => self::$defaultLevel
        ];
        
        $options = array_merge($defaultOptions, $options);
        
        // Handler para archivo
        if ($options['rotating']) {
            $handler = new RotatingFileHandler(
                self::$logPath . '/' . $channel . '.log',
                $options['max_files'],
                $options['level']
            );
        } else {
            $handler = new StreamHandler(
                self::$logPath . '/' . $channel . '.log',
                $options['level']
            );
        }
        
        // Formatter
        if ($options['json']) {
            $formatter = new JsonFormatter();
        } else {
            $formatter = new LineFormatter(
                "[%datetime%] %channel%.%level_name%: %message% %context% %extra%\n",
                "Y-m-d H:i:s",
                true,
                true
            );
        }
        
        $handler->setFormatter($formatter);
        $logger->pushHandler($handler);
        
        // Handler adicional para errores críticos (siempre a error_log de PHP)
        $errorLogHandler = new ErrorLogHandler(
            ErrorLogHandler::OPERATING_SYSTEM,
            Logger::ERROR
        );
        $logger->pushHandler($errorLogHandler);
        
        // Processors (agregar contexto automático)
        if ($options['include_context']) {
            // Agregar información de la petición web
            $logger->pushProcessor(new WebProcessor());
            
            // Agregar información de archivo/línea donde se generó el log
            $logger->pushProcessor(new IntrospectionProcessor(
                Logger::DEBUG,
                ['Monolog\\', 'LoggerFactory']
            ));
            
            // Agregar PID y memoria
            $logger->pushProcessor(function ($record) {
                $record['extra']['pid'] = getmypid();
                $record['extra']['memory_mb'] = round(memory_get_usage(true) / 1024 / 1024, 2);
                return $record;
            });
        }
        
        // Guardar logger en caché
        self::$loggers[$channel] = $logger;
        
        return $logger;
    }
    
    /**
     * Loggers predefinidos para componentes principales
     */
    public static function webhook(): Logger {
        return self::getLogger('webhook', [
            'rotating' => true,
            'max_files' => 7,
            'level' => Logger::INFO
        ]);
    }
    
    public static function worker(): Logger {
        return self::getLogger('worker', [
            'rotating' => true,
            'max_files' => 7,
            'level' => Logger::DEBUG
        ]);
    }
    
    public static function bot(): Logger {
        return self::getLogger('bot', [
            'rotating' => true,
            'max_files' => 14,
            'level' => Logger::INFO
        ]);
    }
    
    public static function api(): Logger {
        return self::getLogger('api', [
            'rotating' => true,
            'max_files' => 7,
            'level' => Logger::INFO
        ]);
    }
    
    public static function whatsapp(): Logger {
        return self::getLogger('whatsapp', [
            'rotating' => true,
            'max_files' => 7,
            'level' => Logger::INFO
        ]);
    }
    
    public static function queue(): Logger {
        return self::getLogger('queue', [
            'rotating' => true,
            'max_files' => 7,
            'level' => Logger::DEBUG
        ]);
    }
    
    public static function security(): Logger {
        return self::getLogger('security', [
            'rotating' => true,
            'max_files' => 30, // Mantener logs de seguridad por más tiempo
            'level' => Logger::WARNING
        ]);
    }
    
    /**
     * Logger general de aplicación
     */
    public static function app(): Logger {
        return self::getLogger('app', [
            'rotating' => true,
            'max_files' => 14,
            'level' => Logger::INFO
        ]);
    }
    
    /**
     * Limpiar logs antiguos (ejecutar con cron)
     */
    public static function cleanup(int $daysToKeep = 30): int {
        $cleaned = 0;
        $cutoff = time() - ($daysToKeep * 86400);
        
        if (!is_dir(self::$logPath)) {
            return 0;
        }
        
        $files = glob(self::$logPath . '/*.log*');
        
        foreach ($files as $file) {
            if (is_file($file) && filemtime($file) < $cutoff) {
                if (unlink($file)) {
                    $cleaned++;
                }
            }
        }
        
        return $cleaned;
    }
    
    /**
     * Obtener estadísticas de logs
     */
    public static function getStats(): array {
        if (!is_dir(self::$logPath)) {
            return ['error' => 'Log directory not found'];
        }
        
        $stats = [
            'total_files' => 0,
            'total_size_mb' => 0,
            'by_channel' => []
        ];
        
        $files = glob(self::$logPath . '/*.log*');
        
        foreach ($files as $file) {
            if (!is_file($file)) continue;
            
            $stats['total_files']++;
            $size = filesize($file);
            $stats['total_size_mb'] += $size / 1024 / 1024;
            
            // Extraer canal del nombre de archivo
            $basename = basename($file);
            preg_match('/^([^-\.]+)/', $basename, $matches);
            $channel = $matches[1] ?? 'unknown';
            
            if (!isset($stats['by_channel'][$channel])) {
                $stats['by_channel'][$channel] = [
                    'files' => 0,
                    'size_mb' => 0
                ];
            }
            
            $stats['by_channel'][$channel]['files']++;
            $stats['by_channel'][$channel]['size_mb'] += $size / 1024 / 1024;
        }
        
        // Redondear tamaños
        $stats['total_size_mb'] = round($stats['total_size_mb'], 2);
        foreach ($stats['by_channel'] as $channel => $data) {
            $stats['by_channel'][$channel]['size_mb'] = round($data['size_mb'], 2);
        }
        
        return $stats;
    }
}

/**
 * Función helper global para logging rápido
 * Mantiene compatibilidad con writeLog() existente
 */
if (!function_exists('writeLog')) {
    function writeLog(string $level, string $message, array $context = [], string $channel = 'app') {
        try {
            $logger = LoggerFactory::getLogger($channel);
            
            $level = strtolower($level);
            switch ($level) {
                case 'debug':
                    $logger->debug($message, $context);
                    break;
                case 'info':
                    $logger->info($message, $context);
                    break;
                case 'notice':
                    $logger->notice($message, $context);
                    break;
                case 'warning':
                case 'warn':
                    $logger->warning($message, $context);
                    break;
                case 'error':
                    $logger->error($message, $context);
                    break;
                case 'critical':
                    $logger->critical($message, $context);
                    break;
                case 'alert':
                    $logger->alert($message, $context);
                    break;
                case 'emergency':
                    $logger->emergency($message, $context);
                    break;
                default:
                    $logger->info($message, $context);
            }
        } catch (Exception $e) {
            // Fallback a error_log nativo de PHP
            error_log("[$level] $message " . json_encode($context));
        }
    }
}

// Inicializar al cargar el archivo
LoggerFactory::init();
