<?php

namespace App\Core\Cache;

/**
 * Redis Cache Implementation
 * يدعم Redis caching مع fallback إلى file cache
 */
class RedisCache
{
    private ?\Redis $redis = null;
    private bool $available = false;
    private string $prefix;
    private int $defaultTtl;

    public function __construct(array $config = [])
    {
        $this->prefix = $config['prefix'] ?? 'lab_lims:';
        $this->defaultTtl = $config['ttl'] ?? 3600;

        // محاولة الاتصال بـ Redis
        try {
            $host = $config['host'] ?? '127.0.0.1';
            $port = $config['port'] ?? 6379;
            $password = $config['password'] ?? null;
            $database = $config['database'] ?? 0;

            $this->redis = new \Redis();
            $connected = $this->redis->connect($host, $port, 2.0);
            
            if ($connected) {
                if ($password !== null) {
                    $this->redis->auth($password);
                }
                $this->redis->select($database);
                $this->available = true;
            }
        } catch (\Throwable $e) {
            $this->available = false;
            error_log("Redis connection failed: " . $e->getMessage());
        }
    }

    /**
     * التحقق من توفر Redis
     */
    public function isAvailable(): bool
    {
        return $this->available && $this->redis !== null;
    }

    /**
     * جلب قيمة من cache
     */
    public function get(string $key, $default = null)
    {
        if (!$this->isAvailable()) {
            return $default;
        }

        try {
            $value = $this->redis->get($this->prefix . $key);
            if ($value === false) {
                return $default;
            }
            return unserialize($value);
        } catch (\Throwable $e) {
            error_log("Redis get error: " . $e->getMessage());
            return $default;
        }
    }

    /**
     * حفظ قيمة في cache
     */
    public function set(string $key, $value, ?int $ttl = null): bool
    {
        if (!$this->isAvailable()) {
            return false;
        }

        try {
            $ttl = $ttl ?? $this->defaultTtl;
            $serialized = serialize($value);
            return $this->redis->setex($this->prefix . $key, $ttl, $serialized);
        } catch (\Throwable $e) {
            error_log("Redis set error: " . $e->getMessage());
            return false;
        }
    }

    /**
     * حذف قيمة من cache
     */
    public function delete(string $key): bool
    {
        if (!$this->isAvailable()) {
            return false;
        }

        try {
            return $this->redis->del($this->prefix . $key) > 0;
        } catch (\Throwable $e) {
            error_log("Redis delete error: " . $e->getMessage());
            return false;
        }
    }

    /**
     * حذف جميع القيم التي تطابق pattern
     */
    public function flush(string $pattern = '*'): int
    {
        if (!$this->isAvailable()) {
            return 0;
        }

        try {
            $keys = $this->redis->keys($this->prefix . $pattern);
            if (empty($keys)) {
                return 0;
            }
            return $this->redis->del($keys);
        } catch (\Throwable $e) {
            error_log("Redis flush error: " . $e->getMessage());
            return 0;
        }
    }

    /**
     * التحقق من وجود key
     */
    public function has(string $key): bool
    {
        if (!$this->isAvailable()) {
            return false;
        }

        try {
            return $this->redis->exists($this->prefix . $key) > 0;
        } catch (\Throwable $e) {
            return false;
        }
    }

    /**
     * تمديد TTL
     */
    public function extend(string $key, int $ttl): bool
    {
        if (!$this->isAvailable()) {
            return false;
        }

        try {
            return $this->redis->expire($this->prefix . $key, $ttl);
        } catch (\Throwable $e) {
            return false;
        }
    }

    /**
     * Remember pattern - جلب أو إنشاء وحفظ
     */
    public function remember(string $key, callable $callback, ?int $ttl = null)
    {
        $value = $this->get($key);
        if ($value !== null) {
            return $value;
        }

        $value = $callback();
        $this->set($key, $value, $ttl);
        return $value;
    }

    /**
     * Increment counter
     */
    public function increment(string $key, int $value = 1): int
    {
        if (!$this->isAvailable()) {
            return 0;
        }

        try {
            return $this->redis->incrBy($this->prefix . $key, $value);
        } catch (\Throwable $e) {
            return 0;
        }
    }

    /**
     * Decrement counter
     */
    public function decrement(string $key, int $value = 1): int
    {
        if (!$this->isAvailable()) {
            return 0;
        }

        try {
            return $this->redis->decrBy($this->prefix . $key, $value);
        } catch (\Throwable $e) {
            return 0;
        }
    }

    /**
     * جلب معلومات Redis
     */
    public function getInfo(): array
    {
        if (!$this->isAvailable()) {
            return ['available' => false];
        }

        try {
            return [
                'available' => true,
                'info' => $this->redis->info(),
                'dbSize' => $this->redis->dbSize()
            ];
        } catch (\Throwable $e) {
            return ['available' => false, 'error' => $e->getMessage()];
        }
    }
}
