<?php

/**
 * 文件功能：前台邮箱找回密码控制器功能测试
 *
 * 覆盖发送重置邮件、重复邮箱兜底、重置密码成功与无效令牌失败等关键场景。
 */

namespace Tests\Feature;

use App\Models\Sysparam;
use App\Models\User;
use App\Notifications\ResetUserPasswordNotification;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Notification;
use Illuminate\Support\Facades\Password;
use Tests\TestCase;

/**
 * 类功能：验证首页邮箱找回密码链路的核心行为。
 */
class PasswordResetControllerTest extends TestCase
{
    use RefreshDatabase;

    /**
     * 初始化系统参数，开启邮箱发信能力。
     */
    protected function setUp(): void
    {
        parent::setUp();

        Sysparam::updateOrCreate(
            ['alias' => 'smtp_enabled'],
            ['body' => '1']
        );
    }

    /**
     * 验证独立找回密码页可以正常访问。
     */
    public function test_can_view_password_recovery_page(): void
    {
        $this->get(route('password.request'))
            ->assertOk()
            ->assertSee('邮箱找回密码');
    }

    /**
     * 验证唯一邮箱账号可以收到重置密码通知。
     */
    public function test_can_send_password_reset_link_by_email(): void
    {
        Notification::fake();

        $user = User::factory()->create([
            'email' => 'recover@example.com',
        ]);

        $this->postJson(route('password.email'), [
            'email' => 'recover@example.com',
        ])->assertOk()
            ->assertJsonPath('status', 'success');

        Notification::assertSentTo($user, ResetUserPasswordNotification::class);
        $this->assertDatabaseHas('password_reset_tokens', [
            'email' => 'recover@example.com',
        ]);
    }

    /**
     * 验证同一个邮箱绑定多个账号时会拒绝自助找回。
     */
    public function test_cannot_send_reset_link_when_email_is_bound_to_multiple_users(): void
    {
        User::factory()->create([
            'username' => 'recover-a',
            'email' => 'shared@example.com',
        ]);

        User::factory()->create([
            'username' => 'recover-b',
            'email' => 'shared@example.com',
        ]);

        $this->postJson(route('password.email'), [
            'email' => 'shared@example.com',
        ])->assertStatus(422)
            ->assertJsonPath('status', 'error');
    }

    /**
     * 验证用户可以使用有效令牌成功重置密码。
     */
    public function test_can_reset_password_with_valid_token(): void
    {
        $user = User::factory()->create([
            'email' => 'reset@example.com',
            'password' => Hash::make('old-password'),
        ]);

        $token = Password::broker()->createToken($user);

        $this->post(route('password.update'), [
            'token' => $token,
            'email' => 'reset@example.com',
            'password' => 'new-password',
            'password_confirmation' => 'new-password',
        ])->assertRedirect(route('home'));

        $user->refresh();

        $this->assertTrue(Hash::check('new-password', $user->password));
    }

    /**
     * 验证无效令牌不会修改用户密码。
     */
    public function test_cannot_reset_password_with_invalid_token(): void
    {
        $user = User::factory()->create([
            'email' => 'broken@example.com',
            'password' => Hash::make('old-password'),
        ]);

        $response = $this->from(route('password.reset', ['token' => 'bad-token', 'email' => 'broken@example.com']))
            ->post(route('password.update'), [
                'token' => 'bad-token',
                'email' => 'broken@example.com',
                'password' => 'new-password',
                'password_confirmation' => 'new-password',
            ]);

        $response->assertRedirect(route('password.reset', ['token' => 'bad-token', 'email' => 'broken@example.com']));
        $response->assertSessionHasErrors('email');

        $user->refresh();

        $this->assertTrue(Hash::check('old-password', $user->password));
    }
}
