<?php

use App\Models\Category;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;

use function Pest\Laravel\actingAs;
use function Pest\Laravel\deleteJson;
use function Pest\Laravel\getJson;
use function Pest\Laravel\postJson;
use function Pest\Laravel\putJson;

uses(RefreshDatabase::class);

test('index returns all categories', function () {
    $user = User::factory()->create();

    Category::factory()->count(3)->create();

    actingAs($user)
        ->getJson('/api/categories')
        ->assertSuccessful()
        ->assertJsonCount(3, 'data');
});

test('index requires authentication', function () {
    getJson('/api/categories')->assertUnauthorized();
});

test('store creates a new category when user is admin', function () {
    $adminEmail = config('app.admin_email');
    $admin = User::factory()->create(['email' => $adminEmail]);

    actingAs($admin)
        ->postJson('/api/categories', ['name' => 'Technology'])
        ->assertSuccessful()
        ->assertJsonPath('data.name', 'Technology');

    expect(Category::where('name', 'Technology')->exists())->toBeTrue();
});

test('store fails when name is missing', function () {
    $adminEmail = config('app.admin_email');
    $admin = User::factory()->create(['email' => $adminEmail]);

    actingAs($admin)
        ->postJson('/api/categories', [])
        ->assertUnprocessable()
        ->assertJsonValidationErrors(['name']);
});

test('store fails when name is not unique', function () {
    $adminEmail = config('app.admin_email');
    $admin = User::factory()->create(['email' => $adminEmail]);

    Category::factory()->create(['name' => 'Existing']);

    actingAs($admin)
        ->postJson('/api/categories', ['name' => 'Existing'])
        ->assertUnprocessable()
        ->assertJsonValidationErrors(['name']);
});

test('store fails when user is not admin', function () {
    $user = User::factory()->create();

    actingAs($user)
        ->postJson('/api/categories', ['name' => 'Technology'])
        ->assertForbidden();
});

test('store requires authentication', function () {
    postJson('/api/categories', ['name' => 'Technology'])->assertUnauthorized();
});

test('show returns a single category', function () {
    $user = User::factory()->create();
    $category = Category::factory()->create(['name' => 'Science']);

    actingAs($user)
        ->getJson("/api/categories/{$category->id}")
        ->assertSuccessful()
        ->assertJsonPath('data.name', 'Science')
        ->assertJsonPath('data.id', $category->id);
});

test('show requires authentication', function () {
    $category = Category::factory()->create();

    getJson("/api/categories/{$category->id}")->assertUnauthorized();
});

test('update modifies an existing category when user is admin', function () {
    $adminEmail = config('app.admin_email');
    $admin = User::factory()->create(['email' => $adminEmail]);
    $category = Category::factory()->create(['name' => 'Old Name']);

    actingAs($admin)
        ->putJson("/api/categories/{$category->id}", ['name' => 'New Name'])
        ->assertSuccessful()
        ->assertJsonPath('data.name', 'New Name');

    expect($category->refresh()->name)->toBe('New Name');
});

test('update allows partial updates', function () {
    $adminEmail = config('app.admin_email');
    $admin = User::factory()->create(['email' => $adminEmail]);
    $category = Category::factory()->create(['name' => 'Original']);

    actingAs($admin)
        ->putJson("/api/categories/{$category->id}", [])
        ->assertSuccessful();

    expect($category->refresh()->name)->toBe('Original');
});

test('update fails when name is not unique', function () {
    $adminEmail = config('app.admin_email');
    $admin = User::factory()->create(['email' => $adminEmail]);

    Category::factory()->create(['name' => 'Existing']);
    $category = Category::factory()->create(['name' => 'Original']);

    actingAs($admin)
        ->putJson("/api/categories/{$category->id}", ['name' => 'Existing'])
        ->assertUnprocessable()
        ->assertJsonValidationErrors(['name']);
});

test('update fails when user is not admin', function () {
    $user = User::factory()->create();
    $category = Category::factory()->create();

    actingAs($user)
        ->putJson("/api/categories/{$category->id}", ['name' => 'New Name'])
        ->assertForbidden();
});

test('update requires authentication', function () {
    $category = Category::factory()->create();

    putJson("/api/categories/{$category->id}", ['name' => 'New Name'])->assertUnauthorized();
});

test('destroy deletes a category when user is admin', function () {
    $adminEmail = config('app.admin_email');
    $admin = User::factory()->create(['email' => $adminEmail]);
    $category = Category::factory()->create();

    actingAs($admin)
        ->deleteJson("/api/categories/{$category->id}")
        ->assertNoContent();

    expect(Category::find($category->id))->toBeNull();
});

test('destroy fails when user is not admin', function () {
    $user = User::factory()->create();
    $category = Category::factory()->create();

    actingAs($user)
        ->deleteJson("/api/categories/{$category->id}")
        ->assertForbidden();
});

test('destroy requires authentication', function () {
    $category = Category::factory()->create();

    deleteJson("/api/categories/{$category->id}")->assertUnauthorized();
});
