<?php

app_require('classes/order_bookings_counts_cache.php');

use classes\order_bookings_counts_cache;

if (!class_exists('OrderBookingsCountsCacheRedisFake')) {
    class OrderBookingsCountsCacheRedisFake
    {
        /** @var array<string,string> */
        public array $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_COUNTS_CACHE_TTL');
    $this->redis = new OrderBookingsCountsCacheRedisFake();
    order_bookings_counts_cache::setAdapterForTests($this->redis);
});

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

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

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

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

    putenv('ORDER_BOOKINGS_COUNTS_CACHE_TTL=20');
    expect(order_bookings_counts_cache::getTtl())->toBe(20);

    putenv('ORDER_BOOKINGS_COUNTS_CACHE_TTL=-1');
    expect(order_bookings_counts_cache::getTtl())->toBe(0);
});

it('builds deterministic keys for equivalent count contexts', function (): void {
    $keyA = order_bookings_counts_cache::buildKey([
        'route' => '/order-bookings/counts',
        'day' => '2026-04-21',
        'department_ids' => ['3', '1'],
        'customer_number' => null,
    ]);

    $keyB = order_bookings_counts_cache::buildKey([
        'customer_number' => null,
        'route' => '/order-bookings/counts',
        'department_ids' => [1, 3],
        'day' => '2026-04-21',
    ]);

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

it('stores and retrieves normalized booking counts', function (): void {
    $key = order_bookings_counts_cache::buildKey([
        'route' => '/order-bookings/counts',
        'day' => '2026-04-21',
        'department_ids' => [12],
    ]);

    order_bookings_counts_cache::storeCounts($key, [
        'past' => '2',
        'current' => 3,
        'future' => 1,
    ], 60);

    expect(order_bookings_counts_cache::getCounts($key))->toEqual([
        'past' => 2,
        'current' => 3,
        'future' => 1,
    ]);
});

it('ignores malformed payloads and clears order-bookings count caches', function (): void {
    $validKey = order_bookings_counts_cache::buildKey([
        'route' => '/order-bookings/counts',
        'day' => '2026-04-21',
    ]);

    $this->redis->store[$validKey] = '{"past":1,"current":2,"future":3}';
    $this->redis->store[order_bookings_counts_cache::PREFIX . 'broken'] = '{"count":5}';
    $this->redis->store['other:key'] = '{"keep":true}';

    expect(order_bookings_counts_cache::getCounts(order_bookings_counts_cache::PREFIX . 'broken'))->toBeNull();

    order_bookings_counts_cache::clearAll();

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