<?php

declare(strict_types=1);

namespace Tests\Feature\Security;

use App\Models\Client;
use App\Models\Company;
use App\Models\Plan;
use App\Models\Subscription;
use App\Models\User;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use PHPUnit\Framework\Attributes\Test;
use Spatie\Permission\Models\Role;
use Tests\TestCase;

/**
 * FIX H-04: collector_user_id debe pertenecer a un usuario con rol 'collector'.
 *
 * Previene asignar créditos a supervisores/admins desde la PWA.
 */
class StoreCreditCollectorRoleTest extends TestCase
{
    use DatabaseTransactions;

    private const CREDITS_URL = '/api/pwa/credits';

    private Company $company;

    private User $admin;

    private Client $client;

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

        foreach (['admin', 'supervisor', 'collector'] as $role) {
            Role::firstOrCreate(['name' => $role, 'guard_name' => 'web']);
        }

        $plan = Plan::factory()->create();
        $this->company = Company::factory()->create();

        Subscription::factory()->create([
            'company_id' => $this->company->id,
            'plan_id' => $plan->id,
            'status' => Subscription::STATUS_ACTIVE,
            'is_active' => true,
            'starts_at' => now()->subMonth(),
            'ends_at' => now()->addYear(),
        ]);

        $this->admin = User::factory()->create(['company_id' => $this->company->id]);
        $this->admin->assignRole('admin');
        $this->admin = $this->admin->fresh();

        $this->client = Client::factory()->create(['company_id' => $this->company->id]);
    }

    private function adminToken(): string
    {
        return $this->admin->createToken('device', ['pwa:admin'])->plainTextToken;
    }

    private function baseCreditPayload(array $overrides = []): array
    {
        return array_merge([
            'client_id' => $this->client->id,
            'amount' => 1000,
            'interest_rate' => 5,
            'installments_count' => 4,
            'periodicity' => 'monthly',
            'start_date' => now()->addDay()->toDateString(),
        ], $overrides);
    }

    #[Test]
    public function assigning_to_user_with_collector_role_passes_validation(): void
    {
        $collector = User::factory()->create(['company_id' => $this->company->id]);
        $collector->assignRole('collector');

        $token = $this->adminToken();

        // Should reach credit creation logic (201) or fail for other business reasons — NOT 422 on collector_user_id
        $response = $this->withToken($token)
            ->postJson(self::CREDITS_URL, $this->baseCreditPayload([
                'collector_user_id' => $collector->id,
            ]));

        $response->assertJsonMissingValidationErrors(['collector_user_id']);
    }

    #[Test]
    public function assigning_to_user_with_supervisor_role_fails_validation(): void
    {
        $supervisor = User::factory()->create(['company_id' => $this->company->id]);
        $supervisor->assignRole('supervisor');

        $token = $this->adminToken();

        $this->withToken($token)
            ->postJson(self::CREDITS_URL, $this->baseCreditPayload([
                'collector_user_id' => $supervisor->id,
            ]))
            ->assertStatus(422)
            ->assertJsonValidationErrors(['collector_user_id']);
    }

    #[Test]
    public function assigning_to_user_with_admin_role_fails_validation(): void
    {
        $anotherAdmin = User::factory()->create(['company_id' => $this->company->id]);
        $anotherAdmin->assignRole('admin');

        $token = $this->adminToken();

        $this->withToken($token)
            ->postJson(self::CREDITS_URL, $this->baseCreditPayload([
                'collector_user_id' => $anotherAdmin->id,
            ]))
            ->assertStatus(422)
            ->assertJsonValidationErrors(['collector_user_id']);
    }
}
