<?php

namespace Tests\Feature;

use App\Models\User;
use Illuminate\Auth\Notifications\ResetPassword;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Notification;
use Tests\TestCase;

class AuthTest extends TestCase
{
    use RefreshDatabase;

    public function test_user_can_login_with_valid_credentials(): void
    {
        $user = User::factory()->create([
            'email' => 'admin@pm.com',
            'password' => Hash::make('password'),
            'status' => 'active',
        ]);

        $response = $this->postJson('/api/login', [
            'email' => ' admin@pm.com ',
            'password' => 'password',
        ]);

        $response
            ->assertOk()
            ->assertJsonPath('success', true)
            ->assertJsonPath('data.user.id', $user->id)
            ->assertJsonStructure([
                'data' => ['user', 'token', 'permissions'],
            ]);
    }

    public function test_login_rejects_invalid_credentials(): void
    {
        User::factory()->create([
            'email' => 'admin@pm.com',
            'password' => Hash::make('password'),
            'status' => 'active',
        ]);

        $this->postJson('/api/login', [
            'email' => 'admin@pm.com',
            'password' => 'wrong-password',
        ])
            ->assertUnauthorized()
            ->assertJsonPath('success', false);
    }

    public function test_inactive_user_cannot_login(): void
    {
        User::factory()->create([
            'email' => 'inactive@pm.com',
            'password' => Hash::make('password'),
            'status' => 'inactive',
        ]);

        $this->postJson('/api/login', [
            'email' => 'inactive@pm.com',
            'password' => 'password',
        ])
            ->assertForbidden()
            ->assertJsonPath('success', false);
    }

    public function test_authenticated_user_can_be_loaded_and_logged_out(): void
    {
        $user = User::factory()->create([
            'password' => Hash::make('password'),
            'status' => 'active',
        ]);

        $token = $user->createToken('api-token')->plainTextToken;

        $this->withToken($token)
            ->getJson('/api/user')
            ->assertOk()
            ->assertJsonPath('data.id', $user->id);

        $this->withToken($token)
            ->postJson('/api/logout')
            ->assertOk()
            ->assertJsonPath('success', true);

        Auth::forgetGuards();

        $this->withToken($token)
            ->getJson('/api/user')
            ->assertUnauthorized();
    }

    public function test_password_change_revokes_all_access_tokens(): void
    {
        $user = User::factory()->create([
            'password' => Hash::make('old-password'),
            'status' => 'active',
        ]);
        $currentToken = $user->createToken('current')->plainTextToken;
        $user->createToken('other');

        $this->withToken($currentToken)
            ->putJson('/api/user/password', [
                'current_password' => 'old-password',
                'new_password' => 'new-secure-password',
                'new_password_confirmation' => 'new-secure-password',
            ])
            ->assertOk()
            ->assertJsonPath('reauthentication_required', true);

        $this->assertSame(0, $user->tokens()->count());
        $this->assertTrue(Hash::check('new-secure-password', $user->fresh()->password));
    }

    public function test_forgot_password_sends_reset_notification_without_account_disclosure(): void
    {
        Notification::fake();
        $user = User::factory()->create(['email' => 'reset@example.com', 'status' => 'active']);

        $this->postJson('/api/forgot-password', ['email' => $user->email])
            ->assertOk()
            ->assertJsonPath('success', true);
        Notification::assertSentTo($user, ResetPassword::class);

        $this->postJson('/api/forgot-password', ['email' => 'missing@example.com'])
            ->assertOk()
            ->assertJsonPath('success', true);
    }
}
