<?php
/**
 * Structured logger with file rotation.
 * Usage: Logger::info('action_name', 'message', ['key' => 'value']);
 */
class Logger {
    const DEBUG = 0;
    const INFO  = 1;
    const WARN  = 2;
    const ERROR = 3;

    private static $levelNames = ['DEBUG', 'INFO', 'WARN', 'ERROR'];
    private static $logFile;
    private static $minLevel = self::INFO;
    private static $maxSize  = 5 * 1024 * 1024; // 5MB
    private static $maxFiles = 5;

    public static function init(string $logDir = null, int $minLevel = self::INFO): void {
        $dir = $logDir ?: __DIR__ . '/logs';
        if (!is_dir($dir)) @mkdir($dir, 0755, true);
        self::$logFile  = $dir . '/app.log';
        self::$minLevel = $minLevel;
    }

    public static function log(int $level, string $action, string $message, array $context = []): void {
        if ($level < self::$minLevel) return;
        if (!self::$logFile) self::init();

        self::rotateIfNeeded();

        $ts       = gmdate('c');
        $levelStr = self::$levelNames[$level] ?? 'UNKNOWN';
        $ip       = $_SERVER['REMOTE_ADDR'] ?? 'cli';
        $line     = "[{$ts}] [{$levelStr}] [{$action}] {$message}";
        if (!empty($context)) {
            $line .= ' ' . json_encode($context, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
        }
        $line .= " ip={$ip}";
        @file_put_contents(self::$logFile, $line . "\n", FILE_APPEND | LOCK_EX);
    }

    public static function debug(string $action, string $msg, array $ctx = []): void { self::log(self::DEBUG, $action, $msg, $ctx); }
    public static function info(string $action, string $msg, array $ctx = []): void  { self::log(self::INFO, $action, $msg, $ctx); }
    public static function warn(string $action, string $msg, array $ctx = []): void  { self::log(self::WARN, $action, $msg, $ctx); }
    public static function error(string $action, string $msg, array $ctx = []): void { self::log(self::ERROR, $action, $msg, $ctx); }

    private static function rotateIfNeeded(): void {
        if (!file_exists(self::$logFile)) return;
        if (@filesize(self::$logFile) < self::$maxSize) return;
        for ($i = self::$maxFiles - 1; $i >= 1; $i--) {
            $old = self::$logFile . '.' . $i;
            $new = self::$logFile . '.' . ($i + 1);
            if (file_exists($old)) @rename($old, $new);
        }
        @rename(self::$logFile, self::$logFile . '.1');
    }
}
