<?php

namespace Tests\Feature\Services;

use App\Services\ApiUsageTracker;
use Illuminate\Support\Facades\Redis;
use Mtc\MercuryDataModels\ApiUsage;
use Tests\DatabaseTestCase;

class ApiUsageTrackerTest extends DatabaseTestCase
{
    private ApiUsageTracker $tracker;
    private string $prefix;

    protected function setUp(): void
    {
        parent::setUp();
        // Isolate this test's Redis keys so parallel tests don't drain each other.
        $this->prefix = 'api-usage-test-' . uniqid();
        config(['api-usage.redis_prefix' => $this->prefix]);

        // These are Redis integration tests; skip where Redis (or the phpredis
        // extension) isn't available, e.g. CI runners without a Redis service.
        try {
            Redis::connection()->ping();
        } catch (\Throwable $exception) {
            $this->markTestSkipped('Redis is not available: ' . $exception->getMessage());
        }

        $this->tracker = new ApiUsageTracker();
    }

    protected function tearDown(): void
    {
        try {
            Redis::del($this->prefix . ':buckets');
        } catch (\Throwable) {
        }
        parent::tearDown();
    }

    public function testAggregatesRequestsAndFlushesOneRowToDatabase(): void
    {
        foreach ([0.10, 0.30, 0.20] as $length) {
            $this->tracker->record('tenant-a', '/api/x', null, 'GET', 200, $length);
        }

        $this->tracker->flush();

        $usage = ApiUsage::query()
            ->where('tenant_id', 'tenant-a')
            ->where('endpoint', '/api/x')
            ->where('method', 'GET')
            ->first();

        $this->assertNotNull($usage);
        $this->assertSame(3, (int) $usage->hits);
        $this->assertEqualsWithDelta(0.20, (float) $usage->avg, 0.0001);
        $this->assertEqualsWithDelta(0.10, (float) $usage->min, 0.0001);
        $this->assertEqualsWithDelta(0.30, (float) $usage->max, 0.0001);
    }

    public function testMergesAcrossFlushWindowsIntoSameRow(): void
    {
        $this->tracker->record('tenant-a', '/api/y', null, 'GET', 200, 0.40);
        $this->tracker->flush();

        $this->tracker->record('tenant-a', '/api/y', null, 'GET', 200, 0.20);
        $this->tracker->flush();

        $usage = ApiUsage::query()
            ->where('tenant_id', 'tenant-a')
            ->where('endpoint', '/api/y')
            ->first();

        $this->assertSame(2, (int) $usage->hits);
        $this->assertEqualsWithDelta(0.30, (float) $usage->avg, 0.0001);
        $this->assertEqualsWithDelta(0.20, (float) $usage->min, 0.0001);
        $this->assertEqualsWithDelta(0.40, (float) $usage->max, 0.0001);
    }

    public function testFlushWithNothingBufferedWritesNothing(): void
    {
        $this->tracker->flush();

        $this->assertSame(0, ApiUsage::query()->where('tenant_id', 'tenant-a')->count());
    }
}
