<?php

declare(strict_types=1);

use Builder\Core\Foundation\Contracts\Modules\FieldHandler;
use Builder\Core\Foundation\Resources\FieldHandlerRegistry;
use Illuminate\Database\Eloquent\Model;

final class FakeFieldHandlerForRegistry implements FieldHandler
{
    public function loadFields(Model $record, array $fields, ?string $locale = null): void {}

    public function syncFields(Model $record, array $fields, array $requestData, ?string $locale = null): void {}
}

it('register stores the handler interface and returns self for fluent chaining', function (): void {
    $registry = new FieldHandlerRegistry;

    $result = $registry->register('TestComponent', FakeFieldHandlerForRegistry::class);

    expect($result)->toBe($registry)
        ->and($registry->all())->toBe(['TestComponent' => FakeFieldHandlerForRegistry::class]);
});

it('all returns empty array when nothing is registered', function (): void {
    $registry = new FieldHandlerRegistry;

    expect($registry->all())->toBe([]);
});

it('all returns all registered handlers', function (): void {
    $registry = new FieldHandlerRegistry;
    $registry->register('ComponentA', FakeFieldHandlerForRegistry::class);
    $registry->register('ComponentB', FakeFieldHandlerForRegistry::class);

    expect($registry->all())->toHaveCount(2)
        ->and($registry->all())->toHaveKey('ComponentA')
        ->and($registry->all())->toHaveKey('ComponentB');
});

it('has returns false when component is not registered', function (): void {
    $registry = new FieldHandlerRegistry;

    expect($registry->has('Unknown'))->toBeFalse();
});

it('has returns false when component is registered but handler not bound in container', function (): void {
    $registry = new FieldHandlerRegistry;
    $registry->register('TestComponent', FakeFieldHandlerForRegistry::class);

    expect($registry->has('TestComponent'))->toBeFalse();
});

it('has returns true when component is registered and handler is bound in container', function (): void {
    $registry = new FieldHandlerRegistry;
    $registry->register('TestComponent', FakeFieldHandlerForRegistry::class);
    app()->bind(FakeFieldHandlerForRegistry::class, fn () => new FakeFieldHandlerForRegistry);

    expect($registry->has('TestComponent'))->toBeTrue();
});

it('resolve returns null when component is not registered', function (): void {
    $registry = new FieldHandlerRegistry;

    expect($registry->resolve('Unknown'))->toBeNull();
});

it('resolve returns null when handler is registered but not bound in container', function (): void {
    $registry = new FieldHandlerRegistry;
    $registry->register('TestComponent', FakeFieldHandlerForRegistry::class);

    expect($registry->resolve('TestComponent'))->toBeNull();
});

it('resolve returns handler instance when bound in container', function (): void {
    $registry = new FieldHandlerRegistry;
    $registry->register('TestComponent', FakeFieldHandlerForRegistry::class);
    app()->bind(FakeFieldHandlerForRegistry::class, fn () => new FakeFieldHandlerForRegistry);

    $handler = $registry->resolve('TestComponent');

    expect($handler)->toBeInstanceOf(FakeFieldHandlerForRegistry::class);
});

it('register overwrites existing handler for same component', function (): void {
    $registry = new FieldHandlerRegistry;
    $registry->register('TestComponent', FakeFieldHandlerForRegistry::class);

    $otherClass = get_class(new class implements FieldHandler
    {
        public function loadFields(Model $record, array $fields, ?string $locale = null): void {}

        public function syncFields(Model $record, array $fields, array $requestData, ?string $locale = null): void {}
    });

    $registry->register('TestComponent', $otherClass);

    expect($registry->all()['TestComponent'])->toBe($otherClass);
});
