<?php

namespace Tests\Feature;

use App\Livewire\Auth\ForgotPassword;
use App\Livewire\Settings\Security;
use App\Models\User;
use App\Notifications\QueuedResetPassword as ResetPasswordNotification;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Notification;
use Livewire\Livewire;
use PragmaRX\Google2FAQRCode\Google2FA;
use Tests\TestCase;

/**
 * The forgot-password screen is mail-aware: with SMTP configured the e-mail reset link
 * is the default path (with a secondary 2FA-fallback toggle); without SMTP only the
 * inline 2FA-proof reset is shown. The public screen never advertises clusev:reset-admin
 * — that last-resort recovery note lives in Settings → Security.
 */
class ForgotPasswordSmtpAwareTest extends TestCase
{
    use RefreshDatabase;

    // ── Token expiry ─────────────────────────────────────────────────────
    public function test_reset_token_expires_in_15_minutes(): void
    {
        $this->assertSame(15, config('auth.passwords.users.expire'));
    }

    // ── SMTP configured: e-mail link is the default ──────────────────────
    public function test_smtp_on_shows_send_link_button_and_hides_code_form_by_default(): void
    {
        config(['mail.default' => 'smtp']);

        Livewire::test(ForgotPassword::class)
            ->assertSee(__('auth.forgot_send_email'))
            ->assertSee(__('auth.forgot_use_code_toggle'))
            // the inline 2FA-proof form (new-password field) is hidden by default
            ->assertDontSee(__('auth.new_password'));
    }

    public function test_smtp_on_subtitle_advertises_the_email_link(): void
    {
        config(['mail.default' => 'smtp']);

        Livewire::test(ForgotPassword::class)
            ->assertSee(__('auth.forgot_subtitle_mail'));
    }

    public function test_smtp_on_send_link_dispatches_reset_notification(): void
    {
        config(['mail.default' => 'smtp']);
        Notification::fake();
        $user = User::factory()->create(['email' => 'admin@clusev.local']);

        Livewire::test(ForgotPassword::class)
            ->set('email', 'admin@clusev.local')
            ->call('sendResetLink')
            ->assertHasNoErrors();

        Notification::assertSentTo($user, ResetPasswordNotification::class);
    }

    public function test_toggle_reveals_the_2fa_code_form(): void
    {
        config(['mail.default' => 'smtp']);

        Livewire::test(ForgotPassword::class)
            ->assertDontSee(__('auth.new_password'))
            ->set('showCodeReset', true)
            ->assertSee(__('auth.new_password'))
            ->assertSee(__('auth.forgot_code'));
    }

    public function test_2fa_reset_still_works_with_smtp_on_via_toggle(): void
    {
        config(['mail.default' => 'smtp']);
        $user = User::factory()->create([
            'email' => 'admin@clusev.local',
            'two_factor_secret' => (new Google2FA)->generateSecretKey(),
            'two_factor_confirmed_at' => now(),
        ]);
        $otp = (new Google2FA)->getCurrentOtp($user->two_factor_secret);

        Livewire::test(ForgotPassword::class)
            ->set('showCodeReset', true)
            ->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));
    }

    // ── No SMTP: inline 2FA-proof reset only ─────────────────────────────
    public function test_smtp_off_shows_inline_2fa_form_and_no_send_link(): void
    {
        config(['mail.default' => 'log']);

        Livewire::test(ForgotPassword::class)
            ->assertSee(__('auth.new_password'))
            ->assertSee(__('auth.forgot_code'))
            ->assertDontSee(__('auth.forgot_send_email'));
    }

    public function test_smtp_off_subtitle_keeps_the_2fa_copy(): void
    {
        config(['mail.default' => 'log']);

        Livewire::test(ForgotPassword::class)
            ->assertSee(__('auth.forgot_subtitle'));
    }

    public function test_smtp_off_resets_with_a_valid_totp(): void
    {
        config(['mail.default' => 'log']);
        $user = User::factory()->create([
            'email' => 'admin@clusev.local',
            'two_factor_secret' => (new Google2FA)->generateSecretKey(),
            'two_factor_confirmed_at' => now(),
        ]);
        $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));
    }

    // ── clusev:reset-admin recovery note placement ───────────────────────
    public function test_public_forgot_view_does_not_advertise_reset_admin_command(): void
    {
        config(['mail.default' => 'log']);

        Livewire::test(ForgotPassword::class)
            ->assertDontSee('clusev reset-admin');

        config(['mail.default' => 'smtp']);

        Livewire::test(ForgotPassword::class)
            ->assertDontSee('clusev reset-admin');
    }

    public function test_settings_security_shows_the_recovery_note_with_the_command(): void
    {
        $user = User::factory()->create();

        Livewire::actingAs($user)->test(Security::class)
            ->assertSee(__('settings.recovery_note'))
            ->assertSee('clusev reset-admin');
    }
}
