<?php

declare(strict_types=1);

namespace ContextPaging;

use Predis\ClientInterface;

/**
 * Redis-backed cache implementation for persistent storage.
 */
class RedisCache implements CacheInterface
{
    private ClientInterface $redis;
    private string $prefix;
    private ?int $defaultTtl;

    /**
     * @param ClientInterface $redis Predis client instance
     * @param string $prefix Key prefix for namespacing (e.g., 'context_paging:')
     * @param int|null $defaultTtl Default TTL in seconds (null = no expiry)
     */
    public function __construct(
        ClientInterface $redis,
        string $prefix = 'ctx:',
        ?int $defaultTtl = null
    ) {
        $this->redis = $redis;
        $this->prefix = $prefix;
        $this->defaultTtl = $defaultTtl;
    }

    /**
     * Create from a Redis URL.
     *
     * @param string $url Redis connection URL (redis:// or rediss://)
     * @param string $prefix Key prefix
     * @param int|null $defaultTtl Default TTL
     */
    public static function fromUrl(
        string $url,
        string $prefix = 'ctx:',
        ?int $defaultTtl = null
    ): self {
        $redis = new \Predis\Client($url);
        return new self($redis, $prefix, $defaultTtl);
    }

    public function get(string $key): mixed
    {
        $value = $this->redis->get($this->prefix . $key);

        if ($value === null) {
            return null;
        }

        return json_decode($value, true);
    }

    public function set(string $key, mixed $value, ?int $ttl = null): void
    {
        $fullKey = $this->prefix . $key;
        $serialized = json_encode($value, JSON_UNESCAPED_UNICODE);

        $ttl = $ttl ?? $this->defaultTtl;

        if ($ttl !== null) {
            $this->redis->setex($fullKey, $ttl, $serialized);
        } else {
            $this->redis->set($fullKey, $serialized);
        }
    }

    public function has(string $key): bool
    {
        return (bool) $this->redis->exists($this->prefix . $key);
    }

    public function delete(string $key): void
    {
        $this->redis->del([$this->prefix . $key]);
    }

    public function clear(): void
    {
        // Use KEYS for simplicity (fine for dev/small datasets)
        // For production with large datasets, use SCAN with proper cursor handling
        $pattern = $this->prefix . '*';
        $keys = $this->redis->keys($pattern);

        if (!empty($keys)) {
            $this->redis->del($keys);
        }
    }

    /**
     * Get the underlying Redis client.
     */
    public function getRedis(): ClientInterface
    {
        return $this->redis;
    }
}
