<?php

declare(strict_types=1);

use Builder\Core\Foundation\Concerns\HasHierarchy;
use Builder\Core\Foundation\Definition\Field;
use Builder\Core\Foundation\Definition\FieldBuilder;
use Builder\Core\Foundation\Definition\Section;
use Builder\Core\Foundation\Registry;
use Builder\Core\Foundation\Resources\Resource;
use Builder\Core\Tests\BuilderTestUser;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Schema;

// ---------------------------------------------------------------------------
// Test doubles
// ---------------------------------------------------------------------------

final class HierarchyTestPage extends Model
{
    use HasHierarchy;

    protected $table = 'hierarchy_test_pages';

    protected $guarded = [];
}

final class HierarchyTestPageResource extends Resource
{
    public static function getSlug(): string
    {
        return 'hierarchy-test-pages';
    }

    public static function getLabel(): string
    {
        return 'Pages';
    }

    public static function getModel(): string
    {
        return HierarchyTestPage::class;
    }

    public function isHierarchical(): bool
    {
        return true;
    }

    public function rules(string $action): array
    {
        return [
            'name' => 'required|string',
            'parent_id' => 'nullable|integer',
        ];
    }

    public function fields(): FieldBuilder
    {
        return FieldBuilder::make()->add(
            Section::make('content')
                ->fields([
                    Field::text('name'),
                    Field::related('parent_id')->relatedTo('hierarchy-test-pages'),
                ])
        );
    }
}

// ---------------------------------------------------------------------------
// Setup
// ---------------------------------------------------------------------------

beforeEach(function (): void {
    Schema::create('users', function ($table): void {
        $table->id();
        $table->string('name')->nullable();
        $table->string('email')->nullable()->unique();
        $table->string('password')->nullable();
        $table->json('user_widget_preferences')->nullable();
        $table->rememberToken();
        $table->timestamps();
    });

    Schema::create('hierarchy_test_pages', function ($table): void {
        $table->id();
        $table->foreignId('parent_id')->nullable()->constrained('hierarchy_test_pages')->nullOnDelete();
        $table->string('name');
        $table->timestamps();
    });

    Schema::create('revisions', function ($table): void {
        $table->id();
        $table->string('revisable_type');
        $table->unsignedBigInteger('revisable_id');
        $table->unsignedBigInteger('user_id')->nullable();
        $table->json('revision_data');
        $table->timestamps();
    });

    app(Registry::class)->resource(HierarchyTestPageResource::class);
});

afterEach(function (): void {
    Schema::dropIfExists('hierarchy_test_pages');
    Schema::dropIfExists('revisions');
    Schema::dropIfExists('users');
});

// ---------------------------------------------------------------------------
// Tests
// ---------------------------------------------------------------------------

it('prevents setting a record as its own parent', function (): void {
    $page = HierarchyTestPage::create(['name' => 'Root', 'parent_id' => null]);
    $admin = BuilderTestUser::create(['name' => 'Admin', 'email' => 'admin@example.com', 'password' => 'x']);

    $this->actingAs($admin)
        ->put(route('builder.resource.update', ['hierarchy-test-pages', $page->id]), [
            'name' => 'Root',
            'parent_id' => $page->id,
        ])
        ->assertSessionHasErrors('parent_id');

    expect($page->fresh()->parent_id)->toBeNull();
});

it('prevents setting a descendant as parent', function (): void {
    $root = HierarchyTestPage::create(['name' => 'Root', 'parent_id' => null]);
    $child = HierarchyTestPage::create(['name' => 'Child', 'parent_id' => $root->id]);
    $grandchild = HierarchyTestPage::create(['name' => 'Grandchild', 'parent_id' => $child->id]);

    $admin = BuilderTestUser::create(['name' => 'Admin', 'email' => 'admin@example.com', 'password' => 'x']);

    $this->actingAs($admin)
        ->put(route('builder.resource.update', ['hierarchy-test-pages', $root->id]), [
            'name' => 'Root',
            'parent_id' => $grandchild->id,
        ])
        ->assertSessionHasErrors('parent_id');

    expect($root->fresh()->parent_id)->toBeNull();
});

it('allows setting a valid parent', function (): void {
    $a = HierarchyTestPage::create(['name' => 'A', 'parent_id' => null]);
    $b = HierarchyTestPage::create(['name' => 'B', 'parent_id' => null]);

    $admin = BuilderTestUser::create(['name' => 'Admin', 'email' => 'admin@example.com', 'password' => 'x']);

    $this->actingAs($admin)
        ->put(route('builder.resource.update', ['hierarchy-test-pages', $b->id]), [
            'name' => 'B',
            'parent_id' => $a->id,
        ])
        ->assertRedirect();

    expect((int) $b->fresh()->parent_id)->toBe((int) $a->id);
});
