<?php

declare(strict_types=1);

use Builder\Core\Foundation\Tables\Column;

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

it('key defaults as label', function (): void {
    $col = Column::make('created_at');

    expect($col->getLabel())->toBe('created_at');
});

it('label sets the label', function (): void {
    $col = Column::make('name')->label('Full Name');

    expect($col->getLabel())->toBe('Full Name');
});

it('sortable defaults to false', function (): void {
    expect(Column::make('name')->isSortable())->toBeFalse();
});

it('sortable() sets to true', function (): void {
    expect(Column::make('name')->sortable()->isSortable())->toBeTrue();
});

it('sortable() accepts explicit false', function (): void {
    expect(Column::make('name')->sortable(false)->isSortable())->toBeFalse();
});

it('searchable defaults to false', function (): void {
    expect(Column::make('name')->isSearchable())->toBeFalse();
});

it('searchable() sets to true', function (): void {
    expect(Column::make('name')->searchable()->isSearchable())->toBeTrue();
});

it('component defaults to null', function (): void {
    expect(Column::make('name')->getComponent())->toBeNull();
});

it('component() sets component', function (): void {
    expect(Column::make('name')->component('ColumnLink')->getComponent())->toBe('ColumnLink');
});

it('hidden defaults to false', function (): void {
    expect(Column::make('name')->isHidden())->toBeFalse();
});

it('hidden() sets to true', function (): void {
    expect(Column::make('name')->hidden()->isHidden())->toBeTrue();
});

it('format() sets a closure', function (): void {
    $fn = fn (mixed $v): string => strtoupper($v);
    $col = Column::make('name')->format($fn);

    expect($col->getFormat())->toBe($fn);
});

it('getKey() returns key', function (): void {
    expect(Column::make('email')->getKey())->toBe('email');
});

it('toArray() excludes format closure', function (): void {
    $col = Column::make('name')
        ->label('Name')
        ->sortable()
        ->searchable()
        ->component('ColumnLink')
        ->hidden(false)
        ->format(fn (mixed $v): string => $v);

    $array = $col->toArray();

    expect($array)->toBe([
        'key' => 'name',
        'label' => 'Name',
        'sortable' => true,
        'searchable' => true,
        'component' => 'ColumnLink',
        'hidden' => false,
        'badges' => null,
    ])->and($array)->not->toHaveKey('format');
});

it('toArray() includes badges key as null by default', function (): void {
    $array = Column::make('name')->toArray();

    expect($array)->toHaveKey('badges')
        ->and($array['badges'])->toBeNull();
});

// --- Formatter convenience methods ---

it('formatDate() sets a format Closure that formats a date string', function (): void {
    $col = Column::make('created_at')->formatDate('d-m-Y');

    expect($col->getFormat())->toBeInstanceOf(Closure::class)
        ->and(($col->getFormat())('2026-02-26'))->toBe('26-02-2026');
});

it('formatDate() returns null for null value', function (): void {
    $col = Column::make('created_at')->formatDate();

    expect(($col->getFormat())(null))->toBeNull();
});

it('formatDate() returns null for empty string', function (): void {
    $col = Column::make('created_at')->formatDate();

    expect(($col->getFormat())(''))->toBeNull();
});

it('formatCurrency() sets a format Closure that returns a non-empty string', function (): void {
    $col = Column::make('price')->formatCurrency('EUR');

    expect($col->getFormat())->toBeInstanceOf(Closure::class)
        ->and(($col->getFormat())(1234.56))->toBeString()->not->toBeEmpty();
});

it('formatCurrency() returns null for null value', function (): void {
    $col = Column::make('price')->formatCurrency('EUR');

    expect(($col->getFormat())(null))->toBeNull();
});

it('formatNumber() sets a format Closure that returns a non-empty string', function (): void {
    $col = Column::make('views')->formatNumber(0);

    expect($col->getFormat())->toBeInstanceOf(Closure::class)
        ->and(($col->getFormat())(1234))->toBeString()->not->toBeEmpty();
});

it('formatNumber() returns null for null value', function (): void {
    $col = Column::make('views')->formatNumber();

    expect(($col->getFormat())(null))->toBeNull();
});

it('formatDate() toArray() still excludes format closure', function (): void {
    $array = Column::make('created_at')->formatDate()->toArray();

    expect($array)->not->toHaveKey('format');
});

it('badge() sets component to BadgeCell and stores badge config', function (): void {
    $badges = [
        'draft' => ['label' => 'Draft', 'color' => 'gray'],
        'published' => ['label' => 'Published', 'color' => 'green'],
    ];

    $col = Column::make('status')->badge($badges);

    expect($col->getComponent())->toBe('BadgeCell');

    $array = $col->toArray();

    expect($array['badges'])->toBe($badges)
        ->and($array['component'])->toBe('BadgeCell');
});

// --- eagerLoad ---

it('eagerLoad defaults to empty array', function (): void {
    expect(Column::make('name')->getEagerLoad())->toBe([]);
});

it('eagerLoad() stores relation names', function (): void {
    $col = Column::make('category_name')->eagerLoad('category');

    expect($col->getEagerLoad())->toBe(['category']);
});

it('eagerLoad() accepts multiple relations', function (): void {
    $col = Column::make('name')->eagerLoad('author', 'tags');

    expect($col->getEagerLoad())->toBe(['author', 'tags']);
});

// --- join ---

it('getJoinConfig() defaults to null', function (): void {
    expect(Column::make('name')->getJoinConfig())->toBeNull();
});

it('join() stores join configuration', function (): void {
    $col = Column::make('country_name')->join('countries', 'country_id', 'id', 'name');

    expect($col->getJoinConfig())->toBe([
        'table' => 'countries',
        'foreignKey' => 'country_id',
        'ownerKey' => 'id',
        'column' => 'name',
        'type' => 'left',
    ]);
});

it('join() uses column key when no explicit column given', function (): void {
    $col = Column::make('country_name')->join('countries', 'country_id', 'id');

    expect($col->getJoinConfig()['column'])->toBe('country_name');
});

it('join() accepts inner join type', function (): void {
    $col = Column::make('country_name')->join('countries', 'country_id', 'id', 'name', 'inner');

    expect($col->getJoinConfig()['type'])->toBe('inner');
});

it('join() returns self for chaining', function (): void {
    $col = Column::make('name');

    expect($col->join('t', 'fk'))->toBe($col);
});

it('publishingStatus() creates a badge column for publication statuses', function (): void {
    $column = Column::publishingStatus();

    expect($column->getKey())->toBe('status');
});

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

    expect($column->getKey())->toBe('pub_status');
});
