<?php

declare(strict_types=1);

namespace Tests\Feature\Pwa;

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

/**
 * Tests de seguridad: protección IDOR en ReorderCollectorCreditsRequest.
 *
 * Verifica que un collector solo pueda reordenar créditos que le pertenecen,
 * y no los asignados a otros collectors de la misma empresa.
 */
class CreditReorderSecurityTest extends TestCase
{
    use DatabaseTransactions;

    private Company $company;

    private Plan $plan;

    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']);
        }

        // Empresa con plan y suscripción activa (requeridos por EnsurePwaAccess)
        $this->plan = Plan::factory()->create(['has_pwa_access' => true]);
        $this->company = Company::factory()->create();

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

    /**
     * Helper: crea un collector en la empresa de prueba.
     */
    private function makeCollector(string $name = 'Collector'): User
    {
        $user = User::factory()->create([
            'company_id' => $this->company->id,
            'name' => $name,
        ]);
        $user->assignRole('collector');

        return $user->fresh();
    }

    /**
     * Helper: crea un crédito activo (hoja) asignado al collector dado.
     */
    private function makeCredit(User $collector): Credit
    {
        $client = Client::factory()->create(['company_id' => $this->company->id]);

        return Credit::factory()->create([
            'company_id' => $this->company->id,
            'client_id' => $client->id,
            'collector_user_id' => $collector->id,
            'created_by_user_id' => $collector->id,
            'status' => Credit::STATUS_ACTIVE,
            'amount' => 100_000,
            'installments_count' => 2,
            'periodicity' => 'biweekly',
            'start_date' => now()->subDays(5),
            'due_date' => now()->addDays(25),
        ]);
    }

    /**
     * IDOR: Un collector NO debe poder reordenar créditos asignados a otro collector,
     * aunque ambos pertenezcan a la misma empresa.
     */
    public function test_collector_cannot_reorder_other_collector_credits(): void
    {
        $collector1 = $this->makeCollector('Collector 1');
        $collector2 = $this->makeCollector('Collector 2');

        // El crédito está asignado a collector2
        $creditOfCollector2 = $this->makeCredit($collector2);

        // Autenticar como collector1 e intentar reordenar el crédito de collector2
        Sanctum::actingAs($collector1);

        $response = $this->putJson('/api/pwa/credits/reorder', [
            'credit_ids' => [$creditOfCollector2->id],
        ]);

        // La validación IDOR debe rechazar la solicitud
        $response->assertStatus(422)
            ->assertJsonValidationErrors(['credit_ids']);
    }

    /**
     * Un collector SÍ puede reordenar sus propios créditos activos.
     */
    public function test_collector_can_reorder_own_credits(): void
    {
        $collector = $this->makeCollector('Collector');

        // Crear 2 créditos activos asignados al mismo collector
        $credit1 = $this->makeCredit($collector);
        $credit2 = $this->makeCredit($collector);

        // Autenticar como el collector
        Sanctum::actingAs($collector);

        // Enviar ambos créditos en orden invertido
        $response = $this->putJson('/api/pwa/credits/reorder', [
            'credit_ids' => [$credit2->id, $credit1->id],
        ]);

        $response->assertStatus(200);
    }
}
