<?php

declare(strict_types=1);

namespace Tests\Feature\Pwa;

use App\Models\Company;
use App\Models\Plan;
use App\Models\Subscription;
use App\Models\User;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Support\Facades\RateLimiter;
use Laravel\Sanctum\Sanctum;
use Spatie\Permission\Models\Role;
use Tests\TestCase;

/**
 * Tests de seguridad: rate limiting en endpoints de escritura PWA.
 *
 * Verifica que:
 * 1. El limiter 'pwa-write' está registrado en AppServiceProvider.
 * 2. Los endpoints de escritura devuelven 429 cuando se supera el límite.
 */
class RateLimitingTest extends TestCase
{
    use DatabaseTransactions;

    private ?User $user = null;

    protected function setUp(): void
    {
        parent::setUp();

        // Crear roles necesarios para pwa.access middleware
        foreach (['admin', 'supervisor', 'collector'] as $role) {
            Role::firstOrCreate(['name' => $role, 'guard_name' => 'web']);
        }
    }

    protected function tearDown(): void
    {
        // Limpiar el bucket del limiter para no afectar otros tests.
        // Laravel hashea la clave: md5(limiterName . limit->by)
        if ($this->user !== null) {
            RateLimiter::clear(md5('pwa-write'.'pwa-write|'.$this->user->id));
        }

        parent::tearDown();
    }

    /**
     * El rate limiter 'pwa-write' debe estar registrado en AppServiceProvider.
     */
    public function test_pwa_write_rate_limiter_is_registered(): void
    {
        $limiter = RateLimiter::limiter('pwa-write');

        $this->assertNotNull($limiter, "El rate limiter 'pwa-write' debe estar registrado");
    }

    /**
     * Los endpoints de escritura deben devolver 429 cuando se supera el límite.
     *
     * Se usa RateLimiter::hit() para agotar el bucket manualmente, evitando
     * hacer 60 peticiones HTTP reales en el test.
     */
    public function test_write_endpoints_return_429_when_rate_limit_exceeded(): void
    {
        // Empresa con plan y suscripción activa (requeridos por EnsurePwaAccess)
        $plan = Plan::factory()->create(['has_pwa_access' => true]);
        $company = Company::factory()->create();

        Subscription::factory()->active()->create([
            'company_id' => $company->id,
            'plan_id' => $plan->id,
            'ends_at' => now()->addYear(),
        ]);

        // Crear collector
        $this->user = User::factory()->create([
            'company_id' => $company->id,
        ]);
        $this->user->assignRole('collector');
        $this->user = $this->user->fresh();

        Sanctum::actingAs($this->user);

        // Agotar el bucket manualmente: 60 hits = límite alcanzado.
        // Laravel construye la clave como md5(limiterName . limit->by)
        // donde limit->by = 'pwa-write|{user->id}' (ver AppServiceProvider).
        $bucketKey = md5('pwa-write'.'pwa-write|'.$this->user->id);
        for ($i = 0; $i < 60; $i++) {
            RateLimiter::hit($bucketKey, 60);
        }

        // La siguiente petición real debe devolver 429
        $response = $this->postJson('/api/pwa/clients', [
            'name' => 'Cliente Test',
            'phone' => '3001234567',
        ]);

        $response->assertStatus(429);
    }
}
