<?php

namespace Tests\Feature\Auth;

use App\Domains\Auth\Models\ResetPasswordAttempt;
use App\Domains\Auth\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Hash;
use Tests\TestCase;

class ResetPasswordControllerTest extends TestCase
{
    use RefreshDatabase;

    public function test_it_resets_the_password_consumes_the_attempt_and_revokes_tokens(): void
    {
        $user = User::factory()->create([
            'email' => 'ada@example.com',
            'password' => 'OldSecret!123',
        ]);
        $user->forceFill([
            'failed_login_attempts' => 5,
            'last_failed_login_at' => now(),
            'locked_until' => now()->addMinutes(15),
        ])->save();
        $user->createToken('existing-session');
        $attempt = $user->resetPasswordAttempts()->create([
            'codigo' => '0123',
            'status' => ResetPasswordAttempt::STATUS_VALIDATED,
        ]);

        $this->postJson('/api/password/reset', [
            'email' => ' ADA@EXAMPLE.COM ',
            'codigo' => '0123',
            'password' => 'NewSecret!456',
            'password_confirmation' => 'NewSecret!456',
        ])->assertOk()
            ->assertJsonPath('status', ResetPasswordAttempt::STATUS_USED);

        $user->refresh();

        $this->assertTrue(Hash::check('NewSecret!456', $user->password));
        $this->assertFalse(Hash::check('OldSecret!123', $user->password));
        $this->assertSame(ResetPasswordAttempt::STATUS_USED, $attempt->fresh()->status);
        $this->assertDatabaseCount('personal_access_tokens', 0);
        $this->assertSame(0, $user->failed_login_attempts);
        $this->assertNull($user->last_failed_login_at);
        $this->assertNull($user->locked_until);
    }

    public function test_it_rejects_a_pending_expired_or_used_attempt(): void
    {
        $user = User::factory()->create([
            'email' => 'ada@example.com',
            'password' => 'OldSecret!123',
        ]);

        foreach ([
            ResetPasswordAttempt::STATUS_PENDING,
            ResetPasswordAttempt::STATUS_EXPIRED,
            ResetPasswordAttempt::STATUS_USED,
        ] as $status) {
            $user->resetPasswordAttempts()->create([
                'codigo' => '1234',
                'status' => $status,
            ]);
        }

        $this->postJson('/api/password/reset', [
            'email' => 'ada@example.com',
            'codigo' => '1234',
            'password' => 'NewSecret!456',
            'password_confirmation' => 'NewSecret!456',
        ])->assertUnprocessable()
            ->assertJsonValidationErrors('codigo');

        $this->assertTrue(Hash::check('OldSecret!123', $user->fresh()->password));
    }

    public function test_a_used_attempt_cannot_be_reused(): void
    {
        $user = User::factory()->create(['email' => 'ada@example.com']);
        $attempt = $user->resetPasswordAttempts()->create([
            'codigo' => '1234',
            'status' => ResetPasswordAttempt::STATUS_VALIDATED,
        ]);
        $payload = [
            'email' => 'ada@example.com',
            'codigo' => '1234',
            'password' => 'NewSecret!456',
            'password_confirmation' => 'NewSecret!456',
        ];

        $this->postJson('/api/password/reset', $payload)->assertOk();
        $this->postJson('/api/password/reset', $payload)
            ->assertUnprocessable()
            ->assertJsonValidationErrors('codigo');

        $this->assertSame(ResetPasswordAttempt::STATUS_USED, $attempt->fresh()->status);
    }

    public function test_it_validates_password_confirmation_and_strength(): void
    {
        $this->postJson('/api/password/reset', [
            'email' => 'ada@example.com',
            'codigo' => '1234',
            'password' => 'weak',
            'password_confirmation' => 'different',
        ])->assertUnprocessable()
            ->assertJsonValidationErrors('password');
    }
}
