<?php

declare(strict_types=1);

use Builder\Core\Extensions\Resources\Languages\LanguageResource;
use Builder\Core\Foundation\Registry;
use Builder\Core\Models\Language;
use Builder\Core\Tests\BuilderTestUser;
use Illuminate\Support\Facades\Schema;
use Inertia\Testing\AssertableInertia;

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::dropIfExists('languages');
    Schema::create('languages', function ($table): void {
        $table->id();
        $table->string('code')->unique();
        $table->string('name');
        $table->boolean('is_active')->default(true);
        $table->boolean('is_default')->default(false);
        $table->unsignedInteger('order')->default(0);
        $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(LanguageResource::class);
});

it('renders language index page', function (): void {
    $admin = BuilderTestUser::create(['name' => 'Admin', 'email' => 'admin@test.com', 'password' => 'x']);

    $this->actingAs($admin)
        ->get(route('builder.resource.index', 'languages'))
        ->assertOk()
        ->assertInertia(fn (AssertableInertia $page): AssertableInertia => $page->component('Resource/Index'));
});

it('renders language create page', function (): void {
    $admin = BuilderTestUser::create(['name' => 'Admin', 'email' => 'admin@test.com', 'password' => 'x']);

    $this->actingAs($admin)
        ->get(route('builder.resource.create', 'languages'))
        ->assertOk()
        ->assertInertia(fn (AssertableInertia $page): AssertableInertia => $page->component('Resource/Form'));
});

it('stores a new language', function (): void {
    $admin = BuilderTestUser::create(['name' => 'Admin', 'email' => 'admin@test.com', 'password' => 'x']);

    $this->actingAs($admin)
        ->post(route('builder.resource.store', 'languages'), [
            'code' => 'fr',
            'name' => 'Français',
            'is_active' => true,
            'is_default' => false,
            'order' => 0,
        ])
        ->assertRedirect(route('builder.resource.index', 'languages'));

    expect(Language::where('code', 'fr')->exists())->toBeTrue();
});

it('validates required fields when storing', function (): void {
    $admin = BuilderTestUser::create(['name' => 'Admin', 'email' => 'admin@test.com', 'password' => 'x']);

    $this->actingAs($admin)
        ->post(route('builder.resource.store', 'languages'), [])
        ->assertSessionHasErrors(['code', 'name']);
});

it('updates a language', function (): void {
    $language = Language::create(['code' => 'en', 'name' => 'English', 'is_active' => true, 'is_default' => false, 'order' => 0]);
    $admin = BuilderTestUser::create(['name' => 'Admin', 'email' => 'admin@test.com', 'password' => 'x']);

    $this->actingAs($admin)
        ->put(route('builder.resource.update', ['resource' => 'languages', 'id' => $language->id]), [
            'code' => 'en',
            'name' => 'English (UK)',
            'is_active' => true,
            'is_default' => false,
            'order' => 0,
        ])
        ->assertRedirect(route('builder.resource.edit', ['resource' => 'languages', 'id' => $language->id]));

    expect($language->fresh()->name)->toBe('English (UK)');
});

it('setting is_default clears other languages default flag', function (): void {
    $en = Language::create(['code' => 'en', 'name' => 'English', 'is_active' => true, 'is_default' => true, 'order' => 0]);
    $nl = Language::create(['code' => 'nl', 'name' => 'Nederlands', 'is_active' => true, 'is_default' => false, 'order' => 1]);
    $admin = BuilderTestUser::create(['name' => 'Admin', 'email' => 'admin@test.com', 'password' => 'x']);

    $this->actingAs($admin)
        ->put(route('builder.resource.update', ['resource' => 'languages', 'id' => $nl->id]), [
            'code' => 'nl',
            'name' => 'Nederlands',
            'is_active' => true,
            'is_default' => true,
            'order' => 1,
        ])
        ->assertRedirect(route('builder.resource.edit', ['resource' => 'languages', 'id' => $nl->id]));

    expect($nl->fresh()->is_default)->toBeTrue()
        ->and($en->fresh()->is_default)->toBeFalse();
});

it('deletes a language when more than one exists', function (): void {
    Language::create(['code' => 'nl', 'name' => 'Nederlands', 'is_active' => true, 'is_default' => true, 'order' => 0]);
    $language = Language::create(['code' => 'en', 'name' => 'English', 'is_active' => true, 'is_default' => false, 'order' => 1]);
    $admin = BuilderTestUser::create(['name' => 'Admin', 'email' => 'admin@test.com', 'password' => 'x']);

    $this->actingAs($admin)
        ->delete(route('builder.resource.destroy', ['resource' => 'languages', 'id' => $language->id]))
        ->assertRedirect(route('builder.resource.index', 'languages'));

    expect(Language::find($language->id))->toBeNull();
});

it('cannot delete the last language', function (): void {
    $language = Language::create(['code' => 'en', 'name' => 'English', 'is_active' => true, 'is_default' => true, 'order' => 0]);
    $admin = BuilderTestUser::create(['name' => 'Admin', 'email' => 'admin@test.com', 'password' => 'x']);

    $this->actingAs($admin)
        ->delete(route('builder.resource.destroy', ['resource' => 'languages', 'id' => $language->id]))
        ->assertRedirect();

    expect(Language::find($language->id))->not->toBeNull();
});
