<?php

declare(strict_types=1);

use App\Models\User;
use App\Models\Artwork;
use App\Models\Category;
use App\Models\ContentType;
use App\Models\Group;
use App\Models\World;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\DB;
use Inertia\Testing\AssertableInertia;

function studioWorld(array $attributes = []): World
{
    $creator = $attributes['creator'] ?? User::factory()->create([
        'username' => 'worldbuilder',
        'name' => 'World Builder',
    ]);

    unset($attributes['creator']);

    return World::query()->create(array_merge([
        'title' => 'Halloween World 2026',
        'slug' => 'halloween-world-2026',
        'tagline' => 'Night drives, haunted pixels, and autumn launches.',
        'summary' => 'A curated seasonal destination for Halloween programming.',
        'description' => 'World description',
        'theme_key' => 'halloween',
        'status' => World::STATUS_DRAFT,
        'type' => World::TYPE_SEASONAL,
        'is_featured' => true,
        'created_by_user_id' => $creator->id,
    ], $attributes));
}

it('forbids world studio pages for non moderators', function (): void {
    $user = User::factory()->create();

    $this->actingAs($user)
        ->get(route('studio.worlds.index'))
        ->assertForbidden();

    $this->actingAs($user)
        ->get(route('studio.worlds.create'))
        ->assertRedirect(route('worlds.index'));

    $this->actingAs($user)
        ->get('/worlds/create')
        ->assertRedirect(route('worlds.index'));
});

it('sends guests from the public worlds create shortcut to login', function (): void {
    $this->get('/worlds/create')
        ->assertRedirect(route('login'));
});

it('renders world studio pages for moderators', function (): void {
    $moderator = User::factory()->create([
        'role' => 'moderator',
        'username' => 'modworlds',
        'name' => 'Moderator Worlds',
    ]);
    $world = studioWorld([
        'creator' => $moderator,
        'status' => World::STATUS_PUBLISHED,
        'published_at' => Carbon::parse('2026-10-01 10:00:00'),
        'starts_at' => Carbon::parse('2026-10-15 00:00:00'),
    ]);

    $this->actingAs($moderator)
        ->get(route('studio.worlds.index'))
        ->assertOk()
        ->assertInertia(fn (AssertableInertia $page) => $page
            ->component('Studio/StudioWorldsIndex')
            ->where('title', 'Worlds')
            ->where('listing.items.0.title', 'Halloween World 2026')
            ->where('createUrl', route('studio.worlds.create')));

    $this->actingAs($moderator)
        ->get('/worlds/create')
        ->assertRedirect(route('studio.worlds.create'));

    $this->actingAs($moderator)
        ->get(route('studio.worlds.create'))
        ->assertOk()
        ->assertInertia(fn (AssertableInertia $page) => $page
            ->component('Studio/StudioWorldEditor')
            ->where('title', 'Create world')
            ->has('themeOptions')
            ->has('sectionOptions')
            ->has('relationTypeOptions')
            ->where('mediaSupport.picker_available', false));

    $this->actingAs($moderator)
        ->get(route('studio.worlds.edit', ['world' => $world->id]))
        ->assertOk()
        ->assertInertia(fn (AssertableInertia $page) => $page
            ->component('Studio/StudioWorldEditor')
            ->where('world.title', 'Halloween World 2026')
            ->where('world.slug', 'halloween-world-2026')
            ->where('world.section_visibility_json.featured_artworks', true)
            ->where('duplicateActions.canCreateEdition', false));

    $this->actingAs($moderator)
        ->get(route('studio.worlds.preview', ['world' => $world->id]))
        ->assertOk()
        ->assertInertia(fn (AssertableInertia $page) => $page
            ->component('World/WorldShow')
            ->where('previewMode', true)
            ->where('world.title', 'Halloween World 2026'));
});

it('renders world studio pages for legacy admin accounts', function (): void {
    $admin = User::factory()->create([
        'role' => 'user',
        'username' => 'legacyadminworlds',
        'name' => 'Legacy Admin Worlds',
    ]);

    DB::table('users')
        ->where('id', $admin->id)
        ->update(['isAdmin' => 1]);

    $admin->refresh();

    $this->actingAs($admin)
        ->get(route('studio.worlds.index'))
        ->assertOk()
        ->assertInertia(fn (AssertableInertia $page) => $page
            ->component('Studio/StudioWorldsIndex')
            ->where('title', 'Worlds')
            ->where('createUrl', route('studio.worlds.create')));

    $this->actingAs($admin)
        ->get(route('studio.worlds.create'))
        ->assertOk()
        ->assertInertia(fn (AssertableInertia $page) => $page
            ->component('Studio/StudioWorldEditor')
            ->where('title', 'Create world'));
});

it('searches artwork relations by creator and project context in the worlds picker', function (): void {
    $moderator = User::factory()->create([
        'role' => 'moderator',
        'username' => 'searchworldsmod',
        'name' => 'Search Worlds Moderator',
    ]);

    $creator = User::factory()->create([
        'username' => 'springartist',
        'name' => 'Spring Artist',
    ]);

    $group = Group::factory()->create([
        'name' => 'Spring Project',
        'slug' => 'spring-project',
    ]);

    $contentType = ContentType::query()->create([
        'name' => 'Pixel Art',
        'slug' => 'pixel-art',
        'description' => 'Pixel art content type',
    ]);

    $category = Category::query()->create([
        'content_type_id' => $contentType->id,
        'name' => 'Seasonal Spring',
        'slug' => 'seasonal-spring',
        'description' => 'Spring showcase',
        'is_active' => true,
        'sort_order' => 1,
    ]);

    $artwork = Artwork::factory()->for($creator)->create([
        'group_id' => $group->id,
        'title' => 'Morning Dew',
        'slug' => 'morning-dew',
        'description' => 'A calm scene with no direct spring keyword in the artwork copy.',
        'artwork_status' => 'published',
        'visibility' => Artwork::VISIBILITY_PUBLIC,
        'is_public' => true,
    ]);

    $artwork->categories()->attach($category->id);

    $this->actingAs($moderator)
        ->getJson(route('studio.worlds.entity-search', ['type' => 'artwork', 'q' => 'spring']))
        ->assertOk()
        ->assertJsonPath('items.0.id', $artwork->id)
        ->assertJsonPath('items.0.title', 'Morning Dew')
        ->assertJsonPath('items.0.subtitle', 'Spring Artist');
});

it('stores a world draft through the studio flow', function (): void {
    $moderator = User::factory()->create([
        'role' => 'moderator',
        'username' => 'editorworlds',
        'name' => 'Editor Worlds',
    ]);

    $response = $this->actingAs($moderator)->post(route('studio.worlds.store'), [
        'title' => 'Retro Month 2026',
        'slug' => 'retro-month-2026',
        'tagline' => 'Scanlines, diskmag culture, and old-school launches.',
        'summary' => 'A recurring world for retro platform activity.',
        'description' => 'World body copy',
        'theme_key' => 'retro-month',
        'status' => World::STATUS_DRAFT,
        'type' => World::TYPE_CAMPAIGN,
        'is_featured' => true,
        'is_recurring' => true,
        'recurrence_key' => 'retro-month',
        'recurrence_rule' => 'annual:04',
        'edition_year' => 2026,
        'cta_label' => 'Explore Retro Month',
        'cta_url' => 'https://skinbase.test/worlds/retro-month-2026',
        'badge_label' => 'Editorial pick',
        'badge_description' => 'Featured by the Nova editorial team.',
        'badge_url' => 'https://skinbase.test/badges/retro',
        'seo_title' => 'Retro Month 2026 - Skinbase Nova',
        'seo_description' => 'Retro Month seasonal campaign',
        'published_at' => '2026-03-20T10:00',
        'related_tags_json' => ['retro', 'demoscene'],
        'section_order_json' => ['featured_artworks', 'featured_collections', 'news'],
        'section_visibility_json' => [
            'featured_artworks' => true,
            'featured_collections' => true,
            'featured_creators' => false,
            'featured_groups' => false,
            'news' => true,
            'challenge' => false,
            'events' => false,
            'releases' => false,
            'cards' => false,
        ],
        'relations' => [],
    ]);

    $world = World::query()->where('slug', 'retro-month-2026')->firstOrFail();

    $response->assertRedirect(route('studio.worlds.edit', ['world' => $world->id]));

    $this->assertDatabaseHas('worlds', [
        'id' => $world->id,
        'title' => 'Retro Month 2026',
        'slug' => 'retro-month-2026',
        'status' => World::STATUS_DRAFT,
        'type' => World::TYPE_CAMPAIGN,
        'is_featured' => true,
        'is_recurring' => true,
        'recurrence_key' => 'retro-month',
        'edition_year' => 2026,
        'published_at' => '2026-03-20 10:00:00',
        'created_by_user_id' => $moderator->id,
    ]);

    expect($world->fresh()->section_visibility_json)->toMatchArray([
        'featured_artworks' => true,
        'featured_collections' => true,
        'featured_creators' => false,
        'news' => true,
    ]);
});

it('rejects reserved world slugs in the studio flow', function (): void {
    $moderator = User::factory()->create([
        'role' => 'moderator',
        'username' => 'reservedslugmod',
        'name' => 'Reserved Slug Moderator',
    ]);

    $this->actingAs($moderator)
        ->from(route('studio.worlds.create'))
        ->post(route('studio.worlds.store'), [
            'title' => 'Create',
            'slug' => 'create',
            'summary' => 'Reserved slug attempt',
            'description' => 'Should fail validation',
            'theme_key' => 'retro-month',
            'status' => World::STATUS_DRAFT,
            'type' => World::TYPE_CAMPAIGN,
            'relations' => [],
        ])
        ->assertRedirect(route('studio.worlds.create'))
        ->assertSessionHasErrors(['slug']);
});

it('requires recurrence metadata and blocks duplicate recurrence editions', function (): void {
    $moderator = User::factory()->create([
        'role' => 'moderator',
        'username' => 'recurrencemod',
        'name' => 'Recurrence Moderator',
    ]);

    studioWorld([
        'creator' => $moderator,
        'title' => 'Halloween World 2026',
        'slug' => 'halloween-world-2026-existing',
        'is_recurring' => true,
        'recurrence_key' => 'halloween',
        'edition_year' => 2026,
    ]);

    $this->actingAs($moderator)
        ->from(route('studio.worlds.create'))
        ->post(route('studio.worlds.store'), [
            'title' => 'Recurring World Without Metadata',
            'status' => World::STATUS_DRAFT,
            'type' => World::TYPE_CAMPAIGN,
            'is_recurring' => true,
            'relations' => [],
        ])
        ->assertRedirect(route('studio.worlds.create'))
        ->assertSessionHasErrors(['recurrence_key', 'edition_year']);

    $this->actingAs($moderator)
        ->from(route('studio.worlds.create'))
        ->post(route('studio.worlds.store'), [
            'title' => 'Halloween World Clone',
            'slug' => 'halloween-world-clone',
            'status' => World::STATUS_DRAFT,
            'type' => World::TYPE_SEASONAL,
            'is_recurring' => true,
            'recurrence_key' => 'halloween',
            'edition_year' => 2026,
            'relations' => [],
        ])
        ->assertRedirect(route('studio.worlds.create'))
        ->assertSessionHasErrors(['edition_year']);
});

it('duplicates worlds and preserves editorial structure in a new draft', function (): void {
    $moderator = User::factory()->create([
        'role' => 'moderator',
        'username' => 'duplicateworldmod',
        'name' => 'Duplicate World Moderator',
    ]);

    $world = studioWorld([
        'creator' => $moderator,
        'title' => 'Pixel Week 2026',
        'slug' => 'pixel-week-2026',
        'theme_key' => 'pixel-week',
        'section_visibility_json' => [
            'featured_artworks' => true,
            'featured_collections' => false,
            'events' => true,
        ],
        'starts_at' => Carbon::parse('2026-07-01 09:00:00'),
        'published_at' => Carbon::parse('2026-06-28 18:00:00'),
    ]);

    $world->worldRelations()->create([
        'section_key' => 'featured_creators',
        'related_type' => 'user',
        'related_id' => $moderator->id,
        'context_label' => 'Lead pixel artist',
        'sort_order' => 0,
        'is_featured' => true,
    ]);

    $response = $this->actingAs($moderator)->post(route('studio.worlds.duplicate', ['world' => $world->id]));

    $duplicate = World::query()->where('slug', 'like', 'pixel-week-2026-copy%')->latest('id')->firstOrFail();

    $response->assertRedirect(route('studio.worlds.edit', ['world' => $duplicate->id]));

    expect($duplicate->status)->toBe(World::STATUS_DRAFT);
    expect($duplicate->is_featured)->toBeFalse();
    expect($duplicate->starts_at)->toBeNull();
    expect($duplicate->published_at)->toBeNull();
    expect($duplicate->section_visibility_json)->toMatchArray([
        'featured_artworks' => true,
        'featured_collections' => false,
        'events' => true,
    ]);
    expect($duplicate->worldRelations()->count())->toBe(1);
});

it('creates the next edition draft for recurring worlds', function (): void {
    $moderator = User::factory()->create([
        'role' => 'moderator',
        'username' => 'editionworldmod',
        'name' => 'Edition World Moderator',
    ]);

    $world = studioWorld([
        'creator' => $moderator,
        'title' => 'Halloween 2026',
        'slug' => 'halloween-2026',
        'is_recurring' => true,
        'recurrence_key' => 'halloween',
        'edition_year' => 2026,
    ]);

    $response = $this->actingAs($moderator)->post(route('studio.worlds.new-edition', ['world' => $world->id]));

    $edition = World::query()->where('recurrence_key', 'halloween')->where('edition_year', 2027)->latest('id')->firstOrFail();

    $response->assertRedirect(route('studio.worlds.edit', ['world' => $edition->id]));
    expect($edition->parent_world_id)->toBe($world->id);
    expect($edition->status)->toBe(World::STATUS_DRAFT);
    expect($edition->is_recurring)->toBeTrue();
    expect($edition->slug)->toContain('2027');
});