<?php

declare(strict_types=1);

namespace Tests\Feature\Pwa;

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 Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
use Laravel\Sanctum\Sanctum;
use PHPUnit\Framework\Attributes\Test;
use Spatie\Permission\Models\Role;
use Tests\TestCase;

/**
 * Regresión #70: GET /api/pwa/team debe atribuir "cobrado hoy" al cobrador
 * ASIGNADO al crédito (credits.collector_user_id) sobre créditos hoja activos,
 * igual que el panel Filament (CollectionMetricsService::getCollectorPerformanceToday).
 *
 * Antes se agrupaba por registered_by_user_id sin filtrar estado/hoja, así que:
 *  - un pago registrado por el admin/supervisor NO se acreditaba al cobrador, y
 *  - pagos sobre créditos terminales/padre SÍ se contaban.
 */
class TeamCollectedTodayAttributionTest extends TestCase
{
    use DatabaseTransactions;

    private Company $company;

    private User $admin;

    private User $collectorA;

    private User $collectorB;

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

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

        $plan = Plan::factory()->create(['has_pwa_access' => true]);
        $this->company = Company::factory()->create();

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

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

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

        $this->collectorB = User::factory()->create(['company_id' => $this->company->id]);
        $this->collectorB->assignRole('collector');
    }

    private function insertPayment(int $creditId, string $amount, int $registeredBy): void
    {
        DB::table('payments')->insert([
            'company_id' => $this->company->id,
            'credit_id' => $creditId,
            'amount' => $amount,
            'applied_amount' => $amount,
            'extra_amount' => '0.00',
            'payment_date' => today()->toDateString(),
            'payment_method' => 'cash',
            'registered_by_user_id' => $registeredBy,
            'voided' => false,
            'idempotency_key' => (string) Str::uuid(),
            'created_at' => now(),
            'updated_at' => now(),
        ]);
    }

    #[Test]
    public function collected_today_is_attributed_to_the_assigned_collector_not_the_registrar(): void
    {
        // Crédito hoja activo de collectorA; el pago lo registra el admin.
        $creditA = Credit::factory()->create([
            'company_id' => $this->company->id,
            'collector_user_id' => $this->collectorA->id,
            'status' => Credit::STATUS_ACTIVE,
        ]);
        $this->insertPayment($creditA->id, '50000.00', registeredBy: $this->admin->id);

        // Crédito terminal (canceled) de collectorA: el pago NO debe contar,
        // aunque lo registre el propio collectorA.
        $creditCanceled = Credit::factory()->create([
            'company_id' => $this->company->id,
            'collector_user_id' => $this->collectorA->id,
            'status' => Credit::STATUS_CANCELED,
        ]);
        $this->insertPayment($creditCanceled->id, '99999.00', registeredBy: $this->collectorA->id);

        Sanctum::actingAs($this->admin->fresh());

        $response = $this->getJson('/api/pwa/team')->assertStatus(200);

        $data = collect($response->json('data'))->keyBy('id');

        // collectorA: solo el pago del crédito activo (50000), atribuido pese a
        // haberlo registrado el admin. El pago del crédito cancelado no cuenta.
        $this->assertEqualsWithDelta(50000.0, $data[$this->collectorA->id]['today']['collected_amount'], 0.001);
        $this->assertSame(1, $data[$this->collectorA->id]['today']['collected_count']);

        // collectorB no cobró nada.
        $this->assertEqualsWithDelta(0.0, $data[$this->collectorB->id]['today']['collected_amount'], 0.001);
        $this->assertSame(0, $data[$this->collectorB->id]['today']['collected_count']);
    }
}
