<?php

namespace App\Service\Adapter;

use Redis;
use RedisException;
use Throwable;

class RedisClientService
{
    private ?Redis $redis = null;

    /**
     * @throws Throwable
     */
    public function get(): Redis
    {
        if ($this->redis === null) {
            $this->redis = $this->withRetry(function () {
                $host = $_ENV['REDIS_HOST'];
                $port = $_ENV['REDIS_PORT'];
                $timeout = 2.0;

                $redis = new Redis();

                try {
                    $redis->connect($host, (int)$port, $timeout);

                    if (!empty($_ENV['REDIS_PASS'])) {
                        $redis->auth($_ENV['REDIS_PASS']);
                    }

                    return $redis;
                } catch (\Throwable $e) {
                    throw $e;
                }
            });
        }

        return $this->redis;
    }


    /**
     * Generic retry wrapper with exponential backoff.
     * @throws Throwable
     */
    private function withRetry(callable $callback, int $maxAttempts = 3, int $baseDelayMs = 100)
    {
        $attempt = 0;
        do {
            try {
                return $callback();
            } catch (Throwable $e) {
                $attempt++;
                if ($attempt >= $maxAttempts) {
                    throw $e;
                }

                $delay = $baseDelayMs * (2 ** ($attempt - 1));
                usleep($delay * 1000); // Convert ms to microseconds
            }
        } while (true);
    }
}