<?php

declare(strict_types=1);

namespace Tests\Feature\Pwa;

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

/**
 * El formulario pregunta al servidor cuándo caería la primera cuota.
 *
 * La razón de que exista este endpoint: el formulario lo calculaba en
 * JavaScript, con su propia versión de las reglas, y lo mandaba como fecha
 * forzada — que gana sobre el día de cobro elegido. El cobrador elegía un día y
 * la cuota caía en otro.
 *
 * Lo que aquí se fija es que la respuesta salga del MISMO servicio que construye
 * el calendario al crear el crédito. Si eso se rompe, la pantalla enseñaría una
 * fecha y se guardaría otra, que es peor que no enseñar nada.
 */
class PrimeraCuotaPreviewTest extends TestCase
{
    use DatabaseTransactions;

    private User $collector;

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

        Role::firstOrCreate(['name' => 'collector', 'guard_name' => 'web']);

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

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

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

    /** @param  array<string, mixed>  $params */
    private function preguntar(array $params): TestResponse
    {
        return $this->actingAs($this->collector, 'sanctum')
            ->getJson('/api/pwa/credits/primera-cuota?'.http_build_query($params));
    }

    #[Test]
    public function la_fecha_sigue_al_dia_de_la_semana_elegido(): void
    {
        // 2026-03-02 es lunes. Eligiendo viernes, la cuota cae el viernes 6.
        $this->preguntar([
            'start_date' => '2026-03-02',
            'periodicity' => 'weekly',
            'due_day_1' => 5,
        ])->assertOk()->assertJson([
            'first_due_date' => '2026-03-06',
            'weekday_iso' => 5,
            'weekday_label' => 'Viernes',
        ]);
    }

    #[Test]
    public function elegir_el_mismo_dia_del_desembolso_pasa_a_la_semana_siguiente(): void
    {
        // El caso que rompía: desembolsar un lunes y elegir "lunes". La cuota no
        // puede vencer el mismo día en que se entrega la plata.
        $this->preguntar([
            'start_date' => '2026-03-02',
            'periodicity' => 'weekly',
            'due_day_1' => 1,
        ])->assertOk()->assertJson(['first_due_date' => '2026-03-09']);
    }

    #[Test]
    public function la_mensual_usa_el_dia_del_mes_y_salta_si_ya_paso(): void
    {
        $this->preguntar([
            'start_date' => '2026-03-10',
            'periodicity' => 'monthly',
            'due_day_1' => 25,
        ])->assertOk()->assertJson(['first_due_date' => '2026-03-25']);

        $this->preguntar([
            'start_date' => '2026-03-28',
            'periodicity' => 'monthly',
            'due_day_1' => 5,
        ])->assertOk()->assertJson(['first_due_date' => '2026-04-05']);
    }

    #[Test]
    public function la_diaria_vence_al_dia_siguiente(): void
    {
        $this->preguntar([
            'start_date' => '2026-03-02',
            'periodicity' => 'daily',
        ])->assertOk()->assertJson(['first_due_date' => '2026-03-03']);
    }

    #[Test]
    public function rechaza_datos_que_no_puede_calcular(): void
    {
        $this->preguntar(['periodicity' => 'weekly'])
            ->assertUnprocessable()
            ->assertJsonValidationErrors('start_date');

        $this->preguntar(['start_date' => '2026-03-02', 'periodicity' => 'cada-luna-llena'])
            ->assertUnprocessable()
            ->assertJsonValidationErrors('periodicity');
    }

    #[Test]
    public function exige_sesion(): void
    {
        $this->getJson('/api/pwa/credits/primera-cuota?start_date=2026-03-02&periodicity=daily')
            ->assertUnauthorized();
    }
}
