<?php

declare(strict_types=1);

namespace Tests\Feature\Filament;

use App\Filament\Resources\Users\Pages\EditUser;
use App\Models\Company;
use App\Models\Plan;
use App\Models\Subscription;
use App\Models\User;
use Filament\Facades\Filament;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Livewire\Livewire;
use PHPUnit\Framework\Attributes\Test;
use Spatie\Permission\Models\Role;
use Tests\TestCase;

/**
 * #170 — la guarda de cupo del plan solo corría en `CreateUser`; al EDITAR se
 * podía asignar el rol `collector` a un usuario existente y superar `max_collectors`.
 * `EditUser::beforeSave()` ahora bloquea el alta neta de cobrador.
 */
class EditUserPlanLimitTest extends TestCase
{
    use DatabaseTransactions;

    protected function setUp(): void
    {
        parent::setUp();
        foreach (['super_admin', 'admin', 'collector', 'supervisor'] as $r) {
            Role::firstOrCreate(['name' => $r, 'guard_name' => 'web']);
        }
        $super = User::factory()->create(['company_id' => null]);
        $super->assignRole('super_admin');
        $this->actingAs($super);
        Filament::setCurrentPanel(Filament::getDefaultPanel());
    }

    private function companyAtCollectorCap(int $max = 1): Company
    {
        $plan = Plan::factory()->create([
            'max_users' => 0, 'max_collectors' => $max, 'max_active_credits' => 0,
            'max_clients' => 0, 'max_monthly_volume' => 0,
        ]);
        $company = Company::factory()->create();
        Subscription::factory()->active()->create([
            'company_id' => $company->id,
            'plan_id' => $plan->id,
            'ends_at' => now()->addYear(),
        ]);

        // Llena el cupo con $max cobradores.
        for ($i = 0; $i < $max; $i++) {
            User::factory()->create(['company_id' => $company->id])->assignRole('collector');
        }

        return $company->refresh();
    }

    private function collectorRoleId(): int
    {
        return (int) Role::where('name', 'collector')->value('id');
    }

    #[Test]
    public function editing_a_user_into_a_collector_over_the_cap_is_blocked(): void
    {
        $company = $this->companyAtCollectorCap(1); // ya hay 1 cobrador (tope)
        $target = User::factory()->create(['company_id' => $company->id]);
        $target->assignRole('admin');

        Livewire::test(EditUser::class, ['record' => $target->getKey()])
            ->fillForm(['roles' => [$this->collectorRoleId()]])
            ->call('save')
            ->assertNotified('Límite del plan alcanzado');

        $this->assertFalse($target->fresh()->hasRole('collector'), 'el rol cobrador no se asignó por el cupo');
    }

    #[Test]
    public function editing_an_existing_collector_at_the_cap_is_allowed(): void
    {
        $company = $this->companyAtCollectorCap(1);
        $collector = User::where('company_id', $company->id)
            ->whereHas('roles', fn ($q) => $q->where('name', 'collector'))
            ->firstOrFail();

        Livewire::test(EditUser::class, ['record' => $collector->getKey()])
            ->fillForm(['name' => 'Nombre Editado', 'roles' => [$this->collectorRoleId()]])
            ->call('save')
            ->assertHasNoFormErrors();

        $this->assertSame('Nombre Editado', $collector->fresh()->name);
        $this->assertTrue($collector->fresh()->hasRole('collector'), 'sigue siendo cobrador');
    }
}
