<?php

declare(strict_types=1);

namespace Tests\Feature\Pwa;

use App\Models\Client;
use App\Models\Company;
use App\Models\CompanyCollectorGoal;
use App\Models\Credit;
use App\Models\Installment;
use App\Models\Plan;
use App\Models\Subscription;
use App\Models\User;
use App\Services\PaymentManager;
use Carbon\Carbon;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Laravel\Sanctum\Sanctum;
use PHPUnit\Framework\Attributes\Test;
use Spatie\Permission\Models\Role;
use Tests\TestCase;

class SupervisorDashboardBreakdownTest extends TestCase
{
    use DatabaseTransactions;

    #[Test]
    public function supervisor_dashboard_exposes_collector_breakdown_and_team_goal(): void
    {
        foreach (['admin', 'supervisor', 'collector'] as $r) {
            Role::firstOrCreate(['name' => $r, 'guard_name' => 'web']);
        }

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

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

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

        // Visibilidad: el supervisor por defecto es 'unassigned' (sees_all_collectors=false
        // y sin asignaciones) → CollectorVisibilityResolver lo dejaría sin ver a nadie.
        // Se asigna el collector a su equipo para que el desglose lo incluya.
        $supervisor->assignedCollectors()->attach($collector->id);

        // Meta diaria del cobrador: 100.000
        CompanyCollectorGoal::create([
            'company_id' => $company->id,
            'collector_user_id' => $collector->id,
            'daily_goal' => 100000,
        ]);

        // Un crédito de ese cobrador con sus 4 cuotas (patrón de VoidPaymentTest —
        // dejar una sola cuota total pagaría el crédito por completo y su status
        // saldría de Credit::ACTIVE_STATUSES, excluyéndolo del desglose por cobrador),
        // y un pago hoy de 30.000 que solo cubre la primera cuota.
        $client = Client::factory()->create(['company_id' => $company->id]);
        $credit = Credit::create([
            'company_id' => $company->id,
            'client_id' => $client->id,
            'created_by_user_id' => $supervisor->id,
            'collector_user_id' => $collector->id,
            'status' => Credit::STATUS_ACTIVE,
            'amount' => 100000,
            'interest_rate' => 20,
            'installments_count' => 4,
            'periodicity' => 'weekly',
            'start_date' => Carbon::now(),
        ]);
        for ($i = 1; $i <= 4; $i++) {
            Installment::create([
                'company_id' => $company->id,
                'credit_id' => $credit->id,
                'installment_number' => $i,
                'status' => Installment::STATUS_PENDING,
                'due_date' => Carbon::now()->addWeeks($i),
                'principal_amount' => 25000,
                'interest_amount' => 5000,
                'total_amount' => 30000,
                'principal_balance_after' => 30000,
                'amount_paid' => 0,
            ]);
        }
        app(PaymentManager::class)->registerPaymentForCredit(
            $credit->fresh(), 30000, Carbon::now(), $supervisor->id, 'cash',
        );

        Sanctum::actingAs($supervisor->fresh());

        $stats = $this->getJson('/api/pwa/dashboard')
            ->assertStatus(200)
            ->json('stats');

        // Desglose por cobrador presente e incluye a nuestro cobrador con lo cobrado hoy.
        $this->assertArrayHasKey('collector_performance', $stats);
        $row = collect($stats['collector_performance'])->firstWhere('collector_id', $collector->id);
        $this->assertNotNull($row, 'el cobrador del equipo aparece en el desglose');
        $this->assertEquals(30000, $row['collected_today']);
        $this->assertEquals(100000, (float) $row['goal']);

        // Meta de equipo = suma de metas del scope.
        $this->assertArrayHasKey('team_goal', $stats);
        $this->assertEquals(100000, $stats['team_goal']['amount']);
        $this->assertEquals(30000, $stats['team_goal']['collected']);
        $this->assertEquals(30, $stats['team_goal']['percentage']); // 30k / 100k
    }
}
