<?php

namespace Tests\Feature;

use App\Livewire\Auth\ForgotPassword;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Hash;
use Livewire\Livewire;
use PragmaRX\Google2FAQRCode\Google2FA;
use Tests\TestCase;

class ForgotPasswordTest extends TestCase
{
    use RefreshDatabase;

    private function user(): User
    {
        return User::factory()->create([
            'email' => 'admin@clusev.local',
            'two_factor_secret' => (new Google2FA)->generateSecretKey(),
            'two_factor_confirmed_at' => now(),
        ]);
    }

    public function test_totp_resets_password_and_rotates_remember_token(): void
    {
        $user = $this->user();
        $user->forceFill(['remember_token' => 'stale-cookie-token'])->save();
        $otp = (new Google2FA)->getCurrentOtp($user->two_factor_secret);

        Livewire::test(ForgotPassword::class)
            ->set('email', $user->email)->set('code', $otp)
            ->set('password', 'NewPassw0rd123')->set('password_confirmation', 'NewPassw0rd123')
            ->call('resetPassword')->assertHasNoErrors();

        $this->assertTrue(Hash::check('NewPassw0rd123', $user->fresh()->password));
        // a stolen remember-me cookie must not survive the reset
        $this->assertNotSame('stale-cookie-token', $user->fresh()->remember_token);
    }

    public function test_backup_code_resets_and_is_consumed(): void
    {
        $user = $this->user();
        $code = $user->replaceRecoveryCodes()[0];

        Livewire::test(ForgotPassword::class)
            ->set('email', $user->email)->set('code', $code)
            ->set('password', 'NewPassw0rd123')->set('password_confirmation', 'NewPassw0rd123')
            ->call('resetPassword')->assertHasNoErrors();

        $this->assertTrue(Hash::check('NewPassw0rd123', $user->fresh()->password));
        $this->assertFalse($user->fresh()->useRecoveryCode($code));
    }

    public function test_wrong_code_does_not_reset(): void
    {
        $user = $this->user();
        $old = $user->password;

        Livewire::test(ForgotPassword::class)
            ->set('email', $user->email)->set('code', '000000')
            ->set('password', 'NewPassw0rd123')->set('password_confirmation', 'NewPassw0rd123')
            ->call('resetPassword')->assertHasErrors('code');

        $this->assertSame($old, $user->fresh()->password);
    }

    public function test_weak_password_rejected(): void
    {
        $user = $this->user();
        $otp = (new Google2FA)->getCurrentOtp($user->two_factor_secret);

        Livewire::test(ForgotPassword::class)
            ->set('email', $user->email)->set('code', $otp)
            ->set('password', 'short')->set('password_confirmation', 'short')
            ->call('resetPassword')->assertHasErrors('password');
    }
}
