<?php

declare(strict_types=1);

use Builder\Core\Foundation\Definition\Field;
use Builder\Core\Foundation\Definition\FieldBuilder;
use Builder\Core\Foundation\Resources\NestedResource;
use Illuminate\Database\Eloquent\Model;

it('make creates a Field instance', function (): void {
    expect(Field::make('title'))->toBeInstanceOf(Field::class);
});

it('name defaults as label', function (): void {
    $field = Field::make('title');

    expect($field->getLabel())->toBe('title');
});

it('label sets and returns self', function (): void {
    $field = Field::make('title');
    $result = $field->label('Page Title');

    expect($result)->toBe($field)
        ->and($field->getLabel())->toBe('Page Title');
});

it('component defaults to TextInput', function (): void {
    expect(Field::make('title')->getComponent())->toBe('TextInput');
});

it('component sets and returns self', function (): void {
    $field = Field::make('image');
    $result = $field->component('MediaSelector');

    expect($result)->toBe($field)
        ->and($field->getComponent())->toBe('MediaSelector');
});

it('rules accepts string and converts to array', function (): void {
    $field = Field::make('title')->rules('required|string');

    expect($field->getRules())->toBe(['required|string']);
});

it('rules accepts array', function (): void {
    $field = Field::make('title')->rules(['required', 'string']);

    expect($field->getRules())->toBe(['required', 'string']);
});

it('default sets value', function (): void {
    $field = Field::make('active')->default(true);

    expect($field->getDefault())->toBeTrue();
});

it('default is null by default', function (): void {
    expect(Field::make('title')->getDefault())->toBeNull();
});

it('hint sets hint', function (): void {
    $field = Field::make('title')->hint('Max 100 characters');

    expect($field->getHint())->toBe('Max 100 characters');
});

it('hint is null by default', function (): void {
    expect(Field::make('title')->getHint())->toBeNull();
});

it('readonly defaults to false', function (): void {
    expect(Field::make('title')->isReadonly())->toBeFalse();
});

it('readonly sets to true', function (): void {
    expect(Field::make('title')->readonly()->isReadonly())->toBeTrue();
});

it('readonly sets to explicit false', function (): void {
    expect(Field::make('title')->readonly(false)->isReadonly())->toBeFalse();
});

it('condition is null by default', function (): void {
    expect(Field::make('title')->getCondition())->toBeNull();
});

it('condition sets closure', function (): void {
    $closure = fn (mixed $v, mixed $m): bool => true;
    $field = Field::make('title')->condition($closure);

    expect($field->getCondition())->toBe($closure);
});

it('getName returns field name', function (): void {
    expect(Field::make('slug')->getName())->toBe('slug');
});

// --- quickCreate ---

it('minRows sets minRows meta on the field', function (): void {
    $field = Field::make('items')->minRows(2);

    expect($field->getMeta('minRows'))->toBe(2);
});

it('quickCreate defaults to null in toArray', function (): void {
    expect(Field::make('category_id')->toArray()['quickCreate'])->toBeNull();
});

it('quickCreate() sets resource slug and default labelKey', function (): void {
    $field = Field::select('category_id')->quickCreate('categories');

    expect($field->getQuickCreateResource())->toBe('categories')
        ->and($field->toArray()['quickCreate'])->toBe([
            'resource' => 'categories',
            'labelKey' => 'name',
        ]);
});

it('quickCreate() accepts a custom labelKey', function (): void {
    $field = Field::select('tag_id')->quickCreate('tags', 'title');

    expect($field->toArray()['quickCreate'])->toBe([
        'resource' => 'tags',
        'labelKey' => 'title',
    ]);
});

it('quickCreate() returns self for chaining', function (): void {
    $field = Field::select('category_id');

    expect($field->quickCreate('categories'))->toBe($field);
});

it('toArray excludes condition closure', function (): void {
    $field = Field::make('title')
        ->label('Title')
        ->component('TextInput')
        ->rules(['required'])
        ->default('Hello')
        ->hint('A hint')
        ->readonly(true)
        ->condition(fn (mixed $v, mixed $m): bool => true);

    $array = $field->toArray();

    expect($array)->toMatchArray([
        'name' => 'title',
        'label' => 'Title',
        'component' => 'TextInput',
        'rules' => ['required'],
        'default' => 'Hello',
        'hint' => 'A hint',
        'readonly' => true,
    ])->and($array)->not->toHaveKey('condition');
});

// ── nestedResource() ──────────────────────────────────────────────────────────

final class FieldNestedChild extends Model
{
    protected $table = 'field_nested_children';

    protected $guarded = [];
}

final class FieldTestNestedResource extends NestedResource
{
    public static function getModel(): string
    {
        return FieldNestedChild::class;
    }

    public static function parentField(): string
    {
        return 'parent_id';
    }

    public function fields(): FieldBuilder
    {
        return FieldBuilder::make()->add(Field::text('title'));
    }
}

it('nestedResource() creates a NestedResourceEditor field with schema meta', function (): void {
    $field = Field::nestedResource('items', FieldTestNestedResource::class);

    expect($field->getComponent())->toBe('NestedResourceEditor')
        ->and($field->getMeta('virtual'))->toBeTrue()
        ->and($field->getMeta('schema'))->toBeArray();
});

// ── whenModuleActive() ────────────────────────────────────────────────────────

it('whenModuleActive returns the field when the module is active', function (): void {
    app()->bind('builder.my-module', fn (): string => 'active');

    $field = Field::text('body')->whenModuleActive('my-module');

    expect($field)->toBeInstanceOf(Field::class);
});

it('whenModuleActive returns null when the module is not active', function (): void {
    $field = Field::text('body')->whenModuleActive('inactive-module-xyz');

    expect($field)->toBeNull();
});
