<?php

declare(strict_types=1);

use Builder\Core\Foundation\Definition\Field;

// --- Static type helpers ---

it('text() creates TextInput component', function (): void {
    $field = Field::text('title');

    expect($field)->toBeInstanceOf(Field::class)
        ->and($field->getComponent())->toBe('TextInput')
        ->and($field->getName())->toBe('title');
});

it('email() creates EmailInput component', function (): void {
    expect(Field::email('email')->getComponent())->toBe('EmailInput');
});

it('tel() creates TelInput component', function (): void {
    expect(Field::tel('phone')->getComponent())->toBe('TelInput');
});

it('url() creates UrlInput component', function (): void {
    expect(Field::url('website')->getComponent())->toBe('UrlInput');
});

it('number() creates NumberInput component', function (): void {
    expect(Field::number('price')->getComponent())->toBe('NumberInput');
});

it('password() creates PasswordInput component', function (): void {
    expect(Field::password('password')->getComponent())->toBe('PasswordInput');
});

it('textarea() creates TextareaInput component', function (): void {
    expect(Field::textarea('bio')->getComponent())->toBe('TextareaInput');
});

it('select() creates SelectInput component', function (): void {
    expect(Field::select('status')->getComponent())->toBe('SelectInput');
});

it('radio() creates RadioInput component', function (): void {
    expect(Field::radio('gender')->getComponent())->toBe('RadioInput');
});

it('checkbox() creates CheckboxInput component', function (): void {
    expect(Field::checkbox('agree')->getComponent())->toBe('CheckboxInput');
});

it('toggle() creates ToggleInput component', function (): void {
    expect(Field::toggle('active')->getComponent())->toBe('ToggleInput');
});

it('toggle() defaults to false', function (): void {
    expect(Field::toggle('active')->getDefault())->toBeFalse();
});

it('hidden() creates HiddenInput component', function (): void {
    expect(Field::hidden('_token')->getComponent())->toBe('HiddenInput');
});

it('datepicker() creates DatepickerInput component', function (): void {
    expect(Field::datepicker('published_at')->getComponent())->toBe('DatepickerInput');
});

it('wysiwyg() creates WysiwygInput component', function (): void {
    expect(Field::wysiwyg('content')->getComponent())->toBe('WysiwygInput');
});

// --- HasOptions fluent methods ---

it('options() sets array options and is returned via getOptions()', function (): void {
    $field = Field::select('status')->options(['active' => 'Active', 'inactive' => 'Inactive']);

    expect($field->getOptions())->toBe(['active' => 'Active', 'inactive' => 'Inactive']);
});

it('options() accepts a Closure and resolves it lazily', function (): void {
    $field = Field::select('status')->options(fn () => ['a' => 'A', 'b' => 'B']);

    expect($field->getOptions())->toBe(['a' => 'A', 'b' => 'B']);
});

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

it('multiple() sets multiple to true', function (): void {
    $field = Field::select('tags')->multiple();

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

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

it('multiple() accepts explicit false', function (): void {
    expect(Field::select('tags')->multiple(false)->isMultiple())->toBeFalse();
});

// --- toArray() ---

it('toArray() includes options resolved from Closure', function (): void {
    $field = Field::select('status')->options(fn () => ['a' => 'A']);

    expect($field->toArray()['options'])->toBe(['a' => 'A']);
});

it('toArray() includes options as null when not set', function (): void {
    expect(Field::make('title')->toArray()['options'])->toBeNull();
});

it('toArray() includes multiple', function (): void {
    expect(Field::select('tags')->multiple()->toArray()['multiple'])->toBeTrue();
});

it('make() still works and defaults to TextInput', function (): void {
    $field = Field::make('title');

    expect($field->getComponent())->toBe('TextInput')
        ->and($field->getName())->toBe('title');
});

// --- Field::related() ---

it('related() creates RelatedInput component', function (): void {
    $field = Field::related('category_id');

    expect($field)->toBeInstanceOf(Field::class)
        ->and($field->getComponent())->toBe('RelatedInput')
        ->and($field->getName())->toBe('category_id');
});

it('relatedTo() sets relatedResource meta', function (): void {
    $field = Field::related('category_id')->relatedTo('categories');

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

it('labelFrom() sets relatedLabelKey meta', function (): void {
    $field = Field::related('category_id')->relatedTo('categories')->labelFrom('title');

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

it('related() toArray() includes relatedResource and relatedLabelKey', function (): void {
    $array = Field::related('category_id')
        ->relatedTo('categories')
        ->labelFrom('title')
        ->toArray();

    expect($array['relatedResource'])->toBe('categories')
        ->and($array['relatedLabelKey'])->toBe('title');
});

it('related() relatedResource is null by default', function (): void {
    expect(Field::related('category_id')->toArray()['relatedResource'])->toBeNull();
});

it('related() relatedLabelKey is null by default', function (): void {
    expect(Field::related('category_id')->toArray()['relatedLabelKey'])->toBeNull();
});

it('publishingStatus() creates SelectInput with draft/published/scheduled options', function (): void {
    $field = Field::publishingStatus();

    expect($field->getComponent())->toBe('SelectInput')
        ->and($field->getName())->toBe('status');
});

it('publishingStatus() accepts custom field name', function (): void {
    $field = Field::publishingStatus('pub_status');

    expect($field->getName())->toBe('pub_status');
});

it('publishAt() creates a DatetimeInput field', function (): void {
    $field = Field::publishAt();

    expect($field->getComponent())->toBe('DatetimeInput')
        ->and($field->getName())->toBe('publish_at');
});

it('visibleWhen() stores field and value in meta', function (): void {
    $field = Field::text('bio')->visibleWhen('role', 'author');

    expect($field->getMeta('visibleWhen'))->toBe(['field' => 'role', 'value' => 'author']);
});
