<?php

declare(strict_types=1);

namespace Tests\Unit;

use App\Http\Controllers\Api\Pwa\Traits\RoleAwareQueries;
use App\Models\Credit;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use PHPUnit\Framework\Attributes\Test;
use Tests\TestCase;

/**
 * Tests for RoleAwareQueries::getFrequencyDisplay().
 *
 * Verifies the human-readable frequency label returned for each
 * periodicity variant, including edge cases for weekly credits where
 * due_day_1 holds an ISO weekday (1 = Lunes … 7 = Domingo).
 *
 * OJO: aunque el Credit se construye con make() (no se persiste), Laravel SÍ
 * persiste las relaciones BelongsTo que CreditFactory declara como factories
 * (company, client, user): expandAttributes() les hace create(). Sin
 * DatabaseTransactions esas filas quedaban committeadas para siempre — 45 por
 * corrida — y en el CI (BD limpia) terminaban chocando contra el
 * `faker->unique()->safeEmail()` de UserFactory, cuyo registro de unicidad se
 * reinicia en cada test al reconstruirse la app.
 */
class FrequencyDisplayTest extends TestCase
{
    use DatabaseTransactions;

    private object $subject;

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

        // Anonymous class that exposes the protected method for testing.
        $this->subject = new class
        {
            use RoleAwareQueries;

            public function getLabel(Credit $credit): string
            {
                return $this->getFrequencyDisplay($credit);
            }
        };
    }

    // ── Weekly ───────────────────────────────────────────────────────────────

    #[Test]
    public function test_weekly_with_valid_weekday_returns_day_name(): void
    {
        $credit = Credit::factory()->make([
            'periodicity' => 'weekly',
            'due_day_1' => 3, // ISO weekday 3 = Miércoles
        ]);

        $label = $this->subject->getLabel($credit);

        $this->assertStringContainsString('Miércoles', $label);
        $this->assertStringStartsWith('Cada ', $label);
    }

    #[Test]
    public function test_weekly_with_out_of_range_day_returns_generic_label(): void
    {
        $credit = Credit::factory()->make([
            'periodicity' => 'weekly',
            'due_day_1' => 15, // Out of ISO weekday range (1-7)
        ]);

        $label = $this->subject->getLabel($credit);

        $this->assertSame('Cada semana', $label);
    }

    #[Test]
    public function test_weekly_with_null_day_returns_generic_label(): void
    {
        $credit = Credit::factory()->make([
            'periodicity' => 'weekly',
            'due_day_1' => null,
        ]);

        $label = $this->subject->getLabel($credit);

        $this->assertSame('Cada semana', $label);
    }

    // ── Monthly ──────────────────────────────────────────────────────────────

    #[Test]
    public function test_monthly_returns_day_of_month(): void
    {
        $credit = Credit::factory()->make([
            'periodicity' => 'monthly',
            'due_day_1' => 15,
        ]);

        $label = $this->subject->getLabel($credit);

        $this->assertSame('Día 15', $label);
    }

    // ── Biweekly ─────────────────────────────────────────────────────────────

    #[Test]
    public function test_biweekly_returns_both_days(): void
    {
        $credit = Credit::factory()->make([
            'periodicity' => 'biweekly',
            'due_day_1' => 5,
            'due_day_2' => 20,
        ]);

        $label = $this->subject->getLabel($credit);

        $this->assertStringContainsString('Días 5 y 20', $label);
    }
}
