<?php

use App\Enums\RoleSlug;
use App\Models\User;
use Database\Seeders\PermissionSeeder;
use Database\Seeders\RoleSeeder;
use Illuminate\Foundation\Testing\LazilyRefreshDatabase;
use Illuminate\Support\Facades\Hash;

uses(LazilyRefreshDatabase::class);

beforeEach(function () {
    $this->withHeaders([
        'Origin' => 'http://localhost:3000',
        'Referer' => 'http://localhost:3000/',
    ]);

    $this->seed([
        PermissionSeeder::class,
        RoleSeeder::class,
    ]);
});

it('lists platform users for admins', function () {
    $admin = User::factory()->admin()->create();
    $manager = User::factory()->manager()->create();

    $response = $this->actingAs($admin)
        ->getJson('/api/users')
        ->assertSuccessful()
        ->assertJsonCount(2, 'data')
        ->assertJsonFragment(['id' => $admin->id, 'role' => RoleSlug::Admin->code()])
        ->assertJsonFragment(['id' => $manager->id, 'role' => RoleSlug::Manager->code()])
        ->assertJsonMissingPath('data.0.password');

    expect($response->json('data.0.createdAt'))->toBeString()->not->toBeEmpty();
});

it('forbids managers from listing users', function () {
    $manager = User::factory()->manager()->create();

    $this->actingAs($manager)
        ->getJson('/api/users')
        ->assertForbidden();
});

it('creates a manager account', function () {
    $admin = User::factory()->admin()->create();

    $response = $this->actingAs($admin)
        ->postJson('/api/users', [
            'name' => 'Portal Manager',
            'email' => 'manager@royaldevelopers.test',
            'password' => 'password',
            'role' => RoleSlug::Manager->code(),
        ])
        ->assertCreated()
        ->assertJsonPath('data.name', 'Portal Manager')
        ->assertJsonPath('data.email', 'manager@royaldevelopers.test')
        ->assertJsonPath('data.role', RoleSlug::Manager->code())
        ->assertJsonMissingPath('data.password');

    $user = User::query()->findOrFail($response->json('data.id'));

    expect($user->role->slug)->toBe(RoleSlug::Manager)
        ->and(Hash::check('password', $user->password))->toBeTrue();
});

it('allows admins to create another admin', function () {
    $admin = User::factory()->admin()->create();

    $this->actingAs($admin)
        ->postJson('/api/users', [
            'name' => 'Second Admin',
            'email' => 'second-admin@royaldevelopers.test',
            'password' => 'password',
            'role' => RoleSlug::Admin->code(),
        ])
        ->assertCreated()
        ->assertJsonPath('data.role', RoleSlug::Admin->code());
});

it('forbids managers from creating users', function () {
    $manager = User::factory()->manager()->create();

    $this->actingAs($manager)
        ->postJson('/api/users', [
            'name' => 'Someone',
            'email' => 'someone@royaldevelopers.test',
            'password' => 'password',
            'role' => RoleSlug::Manager->code(),
        ])
        ->assertForbidden();
});

it('validates user creation input', function () {
    $admin = User::factory()->admin()->create();

    $this->actingAs($admin)
        ->postJson('/api/users', [
            'name' => '',
            'email' => 'not-an-email',
            'password' => 'short',
            'role' => 'AGENT',
        ])
        ->assertUnprocessable()
        ->assertJsonValidationErrors(['name', 'email', 'password', 'role']);
});

it('shows a platform user', function () {
    $admin = User::factory()->admin()->create();
    $manager = User::factory()->manager()->create();

    $this->actingAs($admin)
        ->getJson("/api/users/{$manager->id}")
        ->assertSuccessful()
        ->assertJsonPath('data.id', $manager->id)
        ->assertJsonPath('data.role', RoleSlug::Manager->code())
        ->assertJsonMissingPath('data.password');
});

it('updates a platform user', function () {
    $admin = User::factory()->admin()->create();
    $manager = User::factory()->manager()->create();

    $this->actingAs($admin)
        ->patchJson("/api/users/{$manager->id}", [
            'name' => 'Updated Manager',
            'role' => RoleSlug::Admin->code(),
        ])
        ->assertSuccessful()
        ->assertJsonPath('data.name', 'Updated Manager')
        ->assertJsonPath('data.role', RoleSlug::Admin->code());

    expect($manager->fresh()->role->slug)->toBe(RoleSlug::Admin);
});

it('deletes a manager account', function () {
    $admin = User::factory()->admin()->create();
    $manager = User::factory()->manager()->create();

    $this->actingAs($admin)
        ->deleteJson("/api/users/{$manager->id}")
        ->assertNoContent();

    $this->assertModelMissing($manager);
});

it('does not allow an admin to delete their own account', function () {
    $admin = User::factory()->admin()->create();

    $this->actingAs($admin)
        ->deleteJson("/api/users/{$admin->id}")
        ->assertForbidden();

    $this->assertModelExists($admin);
});

it('does not allow demoting the last admin', function () {
    $admin = User::factory()->admin()->create();

    $this->actingAs($admin)
        ->patchJson("/api/users/{$admin->id}", [
            'role' => RoleSlug::Manager->code(),
        ])
        ->assertForbidden();

    expect($admin->fresh()->role->slug)->toBe(RoleSlug::Admin);
});
