<?php

app_require('classes/redis.php');

use classes\redis;
use Predis\Client as PredisClient;

class RedisAtomicReservationTestClient extends PredisClient
{
    public array $calls = [];

    public function __construct(private mixed $returnValue)
    {
    }

    public function mget(array $keyOrKeys): array
    {
        $this->calls[] = ['mget', $keyOrKeys];
        return $this->returnValue;
    }

    public function set(...$arguments): mixed
    {
        $this->calls[] = $arguments;
        return $this->returnValue;
    }

    public function disconnect(): void
    {
    }
}

function redis_test_inject_client(redis $redis, PredisClient $client): void
{
    $reflection = new ReflectionClass($redis);
    $property = $reflection->getProperty('redis');
    $property->setValue($redis, $client);
}

it('claims a slot atomically with nx and expiration', function (): void {
    global $REDIS_CONFIG;

    $REDIS_CONFIG = [
        'host' => 'redis',
        'database' => 0,
        'password' => '',
    ];

    $client = new RedisAtomicReservationTestClient('OK');

    $redis = new redis();
    redis_test_inject_client($redis, $client);

    expect($redis->set_if_absent_with_expiration('goal_alert_sent:22:2026-03-17', '1', 86400))->toBeTrue();
    expect($client->calls)->toBe([
        ['goal_alert_sent:22:2026-03-17', '1', 'EX', 86400, 'NX'],
    ]);
});

it('returns false when the slot is already claimed and clamps ttl to one second', function (): void {
    global $REDIS_CONFIG;

    $REDIS_CONFIG = [
        'host' => 'redis',
        'database' => 0,
        'password' => '',
    ];

    $client = new RedisAtomicReservationTestClient(null);

    $redis = new redis();
    redis_test_inject_client($redis, $client);

    expect($redis->set_if_absent_with_expiration('goal_alert_sent:22:2026-03-17', '1', 0))->toBeFalse();
    expect($client->calls)->toBe([
        ['goal_alert_sent:22:2026-03-17', '1', 'EX', 1, 'NX'],
    ]);
});

it('does not send empty mget commands to redis', function (): void {
    global $REDIS_CONFIG;

    $REDIS_CONFIG = [
        'host' => 'redis',
        'database' => 0,
        'password' => '',
    ];

    $client = new RedisAtomicReservationTestClient(['cached-value']);

    $redis = new redis();
    redis_test_inject_client($redis, $client);

    expect($redis->mget([]))->toBe([]);
    expect($client->calls)->toBe([]);

    expect($redis->mget(['cache-key']))->toBe(['cached-value']);
    expect($client->calls)->toBe([
        ['mget', ['cache-key']],
    ]);
});
