<?php

declare(strict_types=1);

namespace Tests\Feature;

use App\Filament\Pages\Auth\Login;
use App\Models\Plan;
use App\Models\Subscription;
use App\Models\SubscriptionRequest;
use App\Models\User;
use App\Services\TrialRegistrationService;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Support\Facades\Cache;
use Livewire\Livewire;
use PHPUnit\Framework\Attributes\Test;
use Spatie\Permission\Models\Role;
use Tests\TestCase;

/**
 * Fase 3: al expirar la prueba, el admin no cae en un 403 seco — llega a la
 * pantalla de reactivación `/suscripcion` y puede solicitar una suscripción.
 */
class SubscriptionLockoutTest extends TestCase
{
    use DatabaseTransactions;

    protected function setUp(): void
    {
        parent::setUp();
        Cache::flush(); // hasActiveSubscription() + throttle
        // 'super_admin' es necesario: crear un SubscriptionRequest notifica a los
        // super_admins (SubscriptionRequestNotification), y Spatie lanza si el rol
        // no existe (la BD limpia de CI no lo trae seedeado).
        foreach (['admin', 'super_admin'] as $role) {
            Role::firstOrCreate(['name' => $role, 'guard_name' => 'web']);
        }

        Plan::where('slug', 'professional')->exists() || Plan::factory()->create([
            'slug' => 'professional',
            'name' => 'Profesional',
            'is_active' => true,
            'is_public' => true,
            'is_trial_available' => true,
            'trial_days' => 14,
        ]);
    }

    private function activeAdmin(): User
    {
        return app(TrialRegistrationService::class)->register(
            'Empresa Activa '.uniqid(),
            'Admin Activo',
            'active_'.uniqid().'@credify.test',
            'secret-pass-123',
        );
    }

    private function expiredAdmin(): User
    {
        $user = app(TrialRegistrationService::class)->register(
            'Empresa Vencida '.uniqid(),
            'Admin Vencido',
            'expired_'.uniqid().'@credify.test',
            'secret-pass-123',
        );

        // Simula el trabajo del job nocturno: prueba -> expirada.
        Subscription::where('company_id', $user->company_id)->update([
            'status' => Subscription::STATUS_EXPIRED,
            'ends_at' => now()->subDays(20),
            'trial_ends_at' => now()->subDays(20),
            'grace_period_ends_at' => now()->subDays(13),
        ]);
        Cache::forget(User::subscriptionCacheKey($user->company_id)); // update() no dispara eventos

        return $user->fresh();
    }

    #[Test]
    public function expired_admin_hitting_the_panel_is_redirected_to_the_lockout(): void
    {
        $this->actingAs($this->expiredAdmin())
            ->get('/admin')
            ->assertRedirect(route('subscription.locked'));
    }

    #[Test]
    public function lockout_page_renders_with_the_plan_for_an_expired_admin(): void
    {
        $this->actingAs($this->expiredAdmin())
            ->get('/suscripcion')
            ->assertOk()
            ->assertSee('Tu prueba terminó')
            ->assertSee('Profesional')
            // Solo queda el flujo self-serve; se quitó el contacto por WhatsApp.
            ->assertSee('Solicitar mi suscripción')
            ->assertDontSee('wa.me')
            ->assertDontSee('con GPS');
    }

    #[Test]
    public function active_admin_visiting_the_lockout_is_sent_to_the_panel(): void
    {
        $this->actingAs($this->activeAdmin())
            ->get('/suscripcion')
            ->assertRedirect('/admin');
    }

    #[Test]
    public function guest_visiting_the_lockout_is_sent_to_login(): void
    {
        $this->get('/suscripcion')
            ->assertRedirect(route('filament.admin.auth.login'));
    }

    #[Test]
    public function requesting_a_subscription_creates_a_pending_request(): void
    {
        $user = $this->expiredAdmin();

        $this->actingAs($user)
            ->post(route('subscription.request'))
            ->assertRedirect(route('subscription.locked'))
            ->assertSessionHas('status', 'sent');

        $this->assertDatabaseHas('subscription_requests', [
            'company_id' => $user->company_id,
            'requested_by_user_id' => $user->id,
            'status' => SubscriptionRequest::STATUS_PENDING,
            'request_type' => SubscriptionRequest::TYPE_UPGRADE_PLAN,
        ]);
    }

    #[Test]
    public function a_second_request_does_not_create_a_duplicate(): void
    {
        $user = $this->expiredAdmin();

        $this->actingAs($user)->post(route('subscription.request'));
        $this->actingAs($user)->post(route('subscription.request'))
            ->assertSessionHas('status', 'pending');

        $this->assertSame(1, SubscriptionRequest::where('company_id', $user->company_id)->count());
    }

    #[Test]
    public function expired_admin_login_redirects_to_the_lockout(): void
    {
        $user = $this->expiredAdmin();

        Livewire::test(Login::class)
            ->fillForm([
                'login_identifier' => $user->email,
                'password' => 'secret-pass-123',
            ])
            ->call('authenticate')
            ->assertRedirect(route('subscription.locked'));

        $this->assertAuthenticatedAs($user);
    }
}
