<?php
/**
 * Redis Cache Implementation for Enterprise Scale
 * Provides high-performance in-memory caching for 50+ concurrent users
 */

class RedisCache {
    private static ?\Redis $redis = null;
    private static string $prefix = 'tellerpro:';
    private static int $defaultTTL = 3600; // 1 hour default
    private static bool $enabled = false;

    public static function init(): void {
        if (self::$redis !== null) {
            return;
        }

        // Check if Redis is configured
        $host = getenv('REDIS_HOST') ?: '127.0.0.1';
        $port = getenv('REDIS_PORT') ?: 6379;
        $password = getenv('REDIS_PASSWORD') ?: null;

        try {
            self::$redis = new \Redis();
            self::$redis->connect($host, $port, 2);
            
            if ($password) {
                self::$redis->auth($password);
            }
            
            self::$redis->setOption(\Redis::OPT_SERIALIZER, \Redis::SERIALIZER_PHP);
            self::$redis->setOption(\Redis::OPT_PREFIX, self::$prefix);
            self::$enabled = true;
        } catch (\RedisException $e) {
            // Redis not available, fall back to file cache
            self::$enabled = false;
        }
    }

    public static function get(string $key, mixed $default = null): mixed {
        if (!self::isEnabled()) {
            return \Cache::get($key, $default);
        }

        self::init();
        try {
            $value = self::$redis->get($key);
            return $value === false ? $default : $value;
        } catch (\RedisException $e) {
            return $default;
        }
    }

    public static function set(string $key, mixed $value, int $ttl = null): bool {
        if (!self::isEnabled()) {
            return \Cache::set($key, $value, $ttl);
        }

        self::init();
        $ttl = $ttl ?? self::$defaultTTL;
        try {
            return self::$redis->setex($key, $ttl, $value);
        } catch (\RedisException $e) {
            return false;
        }
    }

    public static function delete(string $key): bool {
        if (!self::isEnabled()) {
            return \Cache::delete($key);
        }

        self::init();
        try {
            return self::$redis->del($key) > 0;
        } catch (\RedisException $e) {
            return false;
        }
    }

    public static function clear(string $pattern = null): bool {
        if (!self::isEnabled()) {
            return \Cache::clear($pattern);
        }

        self::init();
        try {
            if ($pattern === null) {
                return self::$redis->flushDB();
            }
            
            $keys = self::$redis->keys($pattern);
            if (!empty($keys)) {
                return self::$redis->del($keys) > 0;
            }
            return true;
        } catch (\RedisException $e) {
            return false;
        }
    }

    public static function remember(string $key, callable $callback, int $ttl = null): mixed {
        $value = self::get($key);
        
        if ($value !== null) {
            return $value;
        }
        
        $value = $callback();
        self::set($key, $value, $ttl);
        return $value;
    }

    public static function cleanExpired(): int {
        if (!self::isEnabled()) {
            return \Cache::cleanExpired();
        }

        // Redis handles TTL automatically
        return 0;
    }

    public static function getStats(): array {
        if (!self::isEnabled()) {
            return \Cache::getStats();
        }

        self::init();
        try {
            return [
                'type' => 'redis',
                'keys' => self::$redis->dbSize(),
                'memory' => self::$redis->info('memory'),
                'connected' => true
            ];
        } catch (\RedisException $e) {
            return [
                'type' => 'redis',
                'connected' => false,
                'error' => $e->getMessage()
            ];
        }
    }

    public static function isEnabled(): bool {
        if (self::$redis === null) {
            self::init();
        }
        return self::$enabled;
    }

    /**
     * Increment a counter atomically
     */
    public static function increment(string $key, int $value = 1): int {
        if (!self::isEnabled()) {
            // Fallback to file-based counter
            $current = self::get($key, 0);
            $new = $current + $value;
            self::set($key, $new);
            return $new;
        }

        self::init();
        try {
            return self::$redis->incrBy($key, $value);
        } catch (\RedisException $e) {
            return 0;
        }
    }

    /**
     * Get multiple keys at once (pipeline for performance)
     */
    public static function getMultiple(array $keys): array {
        if (!self::isEnabled()) {
            $result = [];
            foreach ($keys as $key) {
                $result[$key] = self::get($key);
            }
            return $result;
        }

        self::init();
        try {
            $values = self::$redis->mget($keys);
            return array_combine($keys, $values);
        } catch (\RedisException $e) {
            return array_fill_keys($keys, null);
        }
    }

    /**
     * Set multiple keys at once (pipeline for performance)
     */
    public static function setMultiple(array $data, int $ttl = null): bool {
        if (!self::isEnabled()) {
            foreach ($data as $key => $value) {
                self::set($key, $value, $ttl);
            }
            return true;
        }

        self::init();
        try {
            $pipe = self::$redis->multi();
            foreach ($data as $key => $value) {
                $ttl = $ttl ?? self::$defaultTTL;
                $pipe->setex($key, $ttl, $value);
            }
            $pipe->exec();
            return true;
        } catch (\RedisException $e) {
            return false;
        }
    }
}
