<?php

app_require('classes/order_bookings_list_cache.php');

use classes\order_bookings_list_cache;

if (!class_exists('OrderBookingsListCacheRedisFake')) {
    class OrderBookingsListCacheRedisFake
    {
        /** @var array<string,string> */
        public array $store = [];

        public function reset(): void
        {
            $this->store = [];
        }

        public function get(string $key): ?string
        {
            return $this->store[$key] ?? null;
        }

        public function setEx(string $key, string $value, int $ttl): void
        {
            $this->store[$key] = $value;
        }

        public function clear_keys(string $pattern): void
        {
            $regex = '/^' . str_replace('\*', '.*', preg_quote($pattern, '/')) . '$/';
            foreach (array_keys($this->store) as $key) {
                if (preg_match($regex, $key) === 1) {
                    unset($this->store[$key]);
                }
            }
        }
    }
}

beforeEach(function (): void {
    $this->oldTtl = getenv('ORDER_BOOKINGS_LIST_CACHE_TTL');
    $this->redis = new OrderBookingsListCacheRedisFake();
    order_bookings_list_cache::setAdapterForTests($this->redis);
});

afterEach(function (): void {
    order_bookings_list_cache::setAdapterForTests(null);

    if ($this->oldTtl === false) {
        putenv('ORDER_BOOKINGS_LIST_CACHE_TTL');
        return;
    }

    putenv('ORDER_BOOKINGS_LIST_CACHE_TTL=' . $this->oldTtl);
});

it('uses sane ttl defaults and clamps negative ttl to zero', function (): void {
    putenv('ORDER_BOOKINGS_LIST_CACHE_TTL');
    expect(order_bookings_list_cache::getTtl())->toBe(30);

    putenv('ORDER_BOOKINGS_LIST_CACHE_TTL=45');
    expect(order_bookings_list_cache::getTtl())->toBe(45);

    putenv('ORDER_BOOKINGS_LIST_CACHE_TTL=-10');
    expect(order_bookings_list_cache::getTtl())->toBe(0);
});

it('builds deterministic keys for equivalent contexts', function (): void {
    $keyA = order_bookings_list_cache::buildKey([
        'route' => '/order-bookings',
        'page' => 1,
        'limit' => 100,
        'search' => '',
        'order' => ['datetime' => 'DESC'],
        'filters' => [
            'customer_number' => '42',
            'department' => ['3', '1'],
            'order_id' => null,
        ],
    ]);

    $keyB = order_bookings_list_cache::buildKey([
        'search' => '',
        'route' => '/order-bookings',
        'limit' => 100,
        'filters' => [
            'order_id' => null,
            'department' => [1, 3],
            'customer_number' => 42,
        ],
        'order' => ['datetime' => 'DESC'],
        'page' => 1,
    ]);

    expect($keyA)->toBe($keyB);
    expect($keyA)->toStartWith(order_bookings_list_cache::PREFIX);
});

it('stores and retrieves full order-bookings payloads', function (): void {
    $key = order_bookings_list_cache::buildKey([
        'route' => '/order-bookings',
        'page' => 1,
        'limit' => 100,
    ]);

    $payload = [
        'success' => true,
        'data' => [
            ['id' => 123],
        ],
        'meta' => [
            'pagination' => [
                'page' => 1,
                'per_page' => 100,
                'total' => 1,
            ],
        ],
        'includes' => [],
    ];

    order_bookings_list_cache::storePayload($key, $payload, 60);

    expect(order_bookings_list_cache::getPayload($key))->toBe($payload);
});

it('ignores malformed cached payloads and clears order-bookings list caches', function (): void {
    $validKey = order_bookings_list_cache::buildKey([
        'route' => '/order-bookings',
        'page' => 1,
    ]);

    $this->redis->store[$validKey] = '{"success":true,"data":[]}';
    $this->redis->store[order_bookings_list_cache::PREFIX . 'broken'] = '{"not":"a payload"}';
    $this->redis->store['other:cache:key'] = '{"leave":"me"}';

    expect(order_bookings_list_cache::getPayload(order_bookings_list_cache::PREFIX . 'broken'))->toBeNull();

    order_bookings_list_cache::clearAll();

    expect($this->redis->store)->toHaveKey('other:cache:key');
    expect($this->redis->store)->not->toHaveKey($validKey);
    expect($this->redis->store)->not->toHaveKey(order_bookings_list_cache::PREFIX . 'broken');
});
