<?php

declare(strict_types=1);

use Builder\Core\Extensions\Resources\Roles\RoleResource;
use Builder\Core\Foundation\Definition\Field;
use Builder\Core\Foundation\Definition\Hook;
use Builder\Core\Foundation\Definition\Section;
use Builder\Core\Foundation\Tables\Column;
use Spatie\Permission\Models\Role;

it('RoleResource slug is roles', function (): void {
    expect(RoleResource::getSlug())->toBe('roles');
});

it('RoleResource label is Roles', function (): void {
    expect(RoleResource::getLabel())->toBe('Roles');
});

it('RoleResource model is Spatie Role', function (): void {
    expect(RoleResource::getModel())->toBe(Role::class);
});

it('RoleResource has permission read:roles', function (): void {
    expect((new RoleResource)->getPermission())->toBe('read:roles');
});

it('RoleResource has General and Permissions sections', function (): void {
    $sections = (new RoleResource)->fields()->toSections();
    $keys = array_map(fn (Section $s) => $s->getKey(), $sections);

    expect($sections)->toHaveCount(2)
        ->and($keys)->toContain('general')
        ->and($keys)->toContain('permissions');
});

it('RoleResource General section contains name field only (no guard_name)', function (): void {
    $sections = (new RoleResource)->fields()->toSections();
    $general = array_values(array_filter($sections, fn (Section $s) => $s->getKey() === 'general'))[0];
    $fieldNames = array_map(fn (Field $f) => $f->getName(), $general->getFields());

    expect($fieldNames)->toContain('name')
        ->not->toContain('guard_name');
});

it('RoleResource Permissions section contains PermissionsInput field', function (): void {
    $sections = (new RoleResource)->fields()->toSections();
    $permsSection = array_values(array_filter($sections, fn (Section $s) => $s->getKey() === 'permissions'))[0];
    $fields = $permsSection->getFields();

    expect($fields)->toHaveCount(1)
        ->and($fields[0]->getName())->toBe('permissions')
        ->and($fields[0]->getComponent())->toBe('PermissionsInput')
        ->and($fields[0]->isMultiple())->toBeTrue();
});

it('RoleResource General has priority 10, Permissions has priority 20', function (): void {
    $sections = (new RoleResource)->fields()->toSections();
    $byKey = array_column(array_map(fn (Section $s) => ['key' => $s->getKey(), 'p' => $s->getPriority()], $sections), 'p', 'key');

    expect($byKey['general'])->toBe(10)
        ->and($byKey['permissions'])->toBe(20);
});

it('RoleResource eagerLoads permissions', function (): void {
    expect((new RoleResource)->eagerLoad())->toContain('permissions');
});

it('RoleResource columns include name only (no guard_name)', function (): void {
    $columns = (new RoleResource)->columns();
    $keys = array_map(fn (Column $c) => $c->getKey(), $columns);

    expect($keys)->toContain('name')
        ->not->toContain('guard_name');
});

it('RoleResource name column is sortable and searchable', function (): void {
    $columns = (new RoleResource)->columns();
    $name = array_values(array_filter($columns, fn (Column $c) => $c->getKey() === 'name'))[0];

    expect($name->isSortable())->toBeTrue()
        ->and($name->isSearchable())->toBeTrue();
});

it('RoleResource create rules require name (no guard_name)', function (): void {
    $rules = (new RoleResource)->rules('create');

    expect($rules)->toHaveKey('name')
        ->not->toHaveKey('guard_name')
        ->toHaveKey('permissions');
});

it('RoleResource creating hook sets guard_name to web', function (): void {
    $hooks = (new RoleResource)->hooks();
    $creating = array_values(array_filter($hooks, fn (Hook $h) => $h->getEvent() === 'creating'))[0];

    $record = new class
    {
        public string $guard_name = '';

        private array $unset = [];

        public function offsetUnset(string $key): void
        {
            $this->unset[] = $key;
        }
    };

    $creating->execute($record, []);

    expect($record->guard_name)->toBe('web');
});

it('RoleResource has creating, updating, and saved hooks', function (): void {
    $hooks = (new RoleResource)->hooks();
    $events = array_map(fn (Hook $h) => $h->getEvent(), $hooks);

    expect($events)->toContain('creating')
        ->toContain('updating')
        ->toContain('saved');
});
