<?php

use App\Models\Artwork;
use App\Models\ArtworkComment;
use App\Models\Category;
use App\Models\ContentType;
use App\Models\User;
use App\Models\World;
use App\Models\WorldRewardGrant;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\DB;
use Inertia\Testing\AssertableInertia;

uses(RefreshDatabase::class);

beforeEach(function (): void {
    File::ensureDirectoryExists(public_path('build'));
    File::put(public_path('build/manifest.json'), json_encode([
        'resources/css/app.css' => ['file' => 'assets/app.css', 'src' => 'resources/css/app.css', 'isEntry' => true],
        'resources/css/nova-grid.css' => ['file' => 'assets/nova-grid.css', 'src' => 'resources/css/nova-grid.css', 'isEntry' => true],
        'resources/scss/nova.scss' => ['file' => 'assets/nova.css', 'src' => 'resources/scss/nova.scss', 'isEntry' => true],
        'resources/js/nova.js' => ['file' => 'assets/nova.js', 'src' => 'resources/js/nova.js', 'isEntry' => true],
        'resources/js/entry-search.jsx' => ['file' => 'assets/entry-search.js', 'src' => 'resources/js/entry-search.jsx', 'isEntry' => true],
        'resources/js/app.js' => ['file' => 'assets/app.js', 'src' => 'resources/js/app.js', 'isEntry' => true],
        'resources/js/artwork.jsx' => ['file' => 'assets/artwork.js', 'src' => 'resources/js/artwork.jsx', 'isEntry' => true],
    ], JSON_THROW_ON_ERROR));
});

it('renders nested artwork comments without lazy-loading reply branches during page render', function () {
    $author = User::factory()->create([
        'username' => 'commentauthor',
    ]);

    $commenterA = User::factory()->create([
        'username' => 'commentera',
    ]);

    $commenterB = User::factory()->create([
        'username' => 'commenterb',
    ]);

    $commenterC = User::factory()->create([
        'username' => 'commenterc',
    ]);

    $contentType = ContentType::create([
        'name' => 'Skins',
        'slug' => 'skins',
        'description' => 'Skins content type',
    ]);

    $category = Category::create([
        'content_type_id' => $contentType->id,
        'name' => 'Internet',
        'slug' => 'internet',
        'description' => 'Internet skins',
        'is_active' => true,
        'sort_order' => 1,
    ]);

    $artwork = Artwork::factory()->for($author)->create([
        'title' => 'ICQ Skin',
        'slug' => 'icq',
        'published_at' => now()->subHour(),
        'is_public' => true,
        'is_approved' => true,
    ]);

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

    $rootComment = ArtworkComment::query()->create([
        'artwork_id' => $artwork->id,
        'user_id' => $commenterA->id,
        'content' => 'Root comment',
        'raw_content' => 'Root comment',
        'is_approved' => true,
    ]);

    $reply = ArtworkComment::query()->create([
        'artwork_id' => $artwork->id,
        'user_id' => $commenterB->id,
        'parent_id' => $rootComment->id,
        'content' => 'First reply',
        'raw_content' => 'First reply',
        'is_approved' => true,
    ]);

    ArtworkComment::query()->create([
        'artwork_id' => $artwork->id,
        'user_id' => $commenterC->id,
        'parent_id' => $reply->id,
        'content' => 'Nested reply',
        'raw_content' => 'Nested reply',
        'is_approved' => true,
    ]);

    $this->get('/skins/internet/icq')
        ->assertOk()
        ->assertInertia(fn (AssertableInertia $page) => $page
            ->component('ArtworkPage')
            ->has('comments', 1)
            ->where('comments.0.content', 'Root comment')
            ->has('comments.0.replies', 1)
            ->where('comments.0.replies.0.content', 'First reply')
            ->has('comments.0.replies.0.replies', 1)
            ->where('comments.0.replies.0.replies.0.content', 'Nested reply'));
});

it('keeps artwork page query count bounded with deep nested comments', function () {
    $author = User::factory()->create([
        'username' => 'querycountauthor',
    ]);

    $contentType = ContentType::create([
        'name' => 'Skins',
        'slug' => 'skins',
        'description' => 'Skins content type',
    ]);

    $category = Category::create([
        'content_type_id' => $contentType->id,
        'name' => 'Internet',
        'slug' => 'internet',
        'description' => 'Internet skins',
        'is_active' => true,
        'sort_order' => 1,
    ]);

    $artwork = Artwork::factory()->for($author)->create([
        'title' => 'ICQ Query Budget',
        'slug' => 'icq-query-budget',
        'published_at' => now()->subHour(),
        'is_public' => true,
        'is_approved' => true,
    ]);

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

    $parentId = null;

    for ($i = 0; $i < 20; $i++) {
        $commenter = User::factory()->create([
            'username' => 'querycommenter' . $i,
        ]);

        $comment = ArtworkComment::query()->create([
            'artwork_id' => $artwork->id,
            'user_id' => $commenter->id,
            'parent_id' => $parentId,
            'content' => 'Nested comment ' . $i,
            'raw_content' => 'Nested comment ' . $i,
            'is_approved' => true,
        ]);

        $parentId = $comment->id;
    }

    $queryCount = 0;
    DB::listen(function () use (&$queryCount) {
        $queryCount++;
    });

    $this->get('/skins/internet/icq-query-budget')->assertOk();

    expect($queryCount)->toBeLessThanOrEqual(50);
});

it('keeps artwork page category queries bounded with nested attached categories', function () {
    $author = User::factory()->create([
        'username' => 'categoryqueryauthor',
    ]);

    $contentType = ContentType::create([
        'name' => 'Skins',
        'slug' => 'skins',
        'description' => 'Skins content type',
    ]);

    $rootCategory = Category::create([
        'content_type_id' => $contentType->id,
        'name' => 'Misc',
        'slug' => 'misc',
        'description' => 'Misc skins',
        'is_active' => true,
        'sort_order' => 1,
    ]);

    $artwork = Artwork::factory()->for($author)->create([
        'title' => 'Parasite Runboxurl Launcher',
        'slug' => 'parasite-runboxurl-launcher',
        'published_at' => now()->subHour(),
        'is_public' => true,
        'is_approved' => true,
    ]);

    $attachedCategoryIds = [$rootCategory->id];

    for ($i = 1; $i <= 8; $i++) {
        $section = Category::create([
            'content_type_id' => $contentType->id,
            'parent_id' => $rootCategory->id,
            'name' => 'Section ' . $i,
            'slug' => 'section-' . $i,
            'description' => 'Section ' . $i,
            'is_active' => true,
            'sort_order' => $i,
        ]);

        $leaf = Category::create([
            'content_type_id' => $contentType->id,
            'parent_id' => $section->id,
            'name' => 'Leaf ' . $i,
            'slug' => 'leaf-' . $i,
            'description' => 'Leaf ' . $i,
            'is_active' => true,
            'sort_order' => $i,
        ]);

        $attachedCategoryIds[] = $leaf->id;
    }

    $artwork->categories()->attach($attachedCategoryIds);

    $categoryQueryCount = 0;
    DB::listen(function ($query) use (&$categoryQueryCount) {
        if (preg_match('/\b(from|join)\s+["`\[]?(categories|content_types)\b/i', $query->sql) === 1) {
            $categoryQueryCount++;
        }
    });

    $this->get('/skins/misc/parasite-runboxurl-launcher')
        ->assertOk()
        ->assertInertia(fn (AssertableInertia $page) => $page
            ->component('ArtworkPage')
            ->has('artwork.categories', 9)
            ->where('artwork.categories.0.slug', 'misc'));

    expect($categoryQueryCount)->toBeLessThanOrEqual(12);
});

it('keeps artwork page world participation queries bounded with many recurring reward badges', function () {
    $author = User::factory()->create([
        'username' => 'jetaudioauthor',
    ]);

    $contentType = ContentType::create([
        'name' => 'Skins',
        'slug' => 'skins',
        'description' => 'Skins content type',
    ]);

    $category = Category::create([
        'content_type_id' => $contentType->id,
        'name' => 'Audio',
        'slug' => 'audio',
        'description' => 'Audio skins',
        'is_active' => true,
        'sort_order' => 1,
    ]);

    $artwork = Artwork::factory()->for($author)->create([
        'title' => 'Jet Audio',
        'slug' => 'jet-audio',
        'published_at' => now()->subHour(),
        'is_public' => true,
        'is_approved' => true,
    ]);

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

    for ($i = 1; $i <= 8; $i++) {
        $world = World::query()->create([
            'title' => 'Audio World ' . $i,
            'slug' => 'audio-world-' . $i,
            'status' => World::STATUS_PUBLISHED,
            'type' => World::TYPE_SEASONAL,
            'is_recurring' => true,
            'recurrence_key' => 'audio-world-series-' . $i,
            'edition_year' => 2020 + $i,
            'is_active_campaign' => false,
            'is_featured' => false,
            'is_homepage_featured' => false,
            'accepts_submissions' => false,
            'participation_mode' => World::PARTICIPATION_MODE_CLOSED,
            'published_at' => now()->subDays(30 + $i),
            'starts_at' => now()->subDays(20 + $i),
            'ends_at' => now()->subDays(10 + $i),
            'created_by_user_id' => $author->id,
        ]);

        WorldRewardGrant::query()->create([
            'user_id' => $author->id,
            'world_id' => $world->id,
            'artwork_id' => $artwork->id,
            'reward_type' => 'featured',
            'grant_source' => 'manual',
            'granted_at' => now()->subDays($i),
        ]);
    }

    $worldQueryCount = 0;
    DB::listen(function ($query) use (&$worldQueryCount) {
        if (preg_match('/\bfrom\s+["`\[]?worlds\b/i', $query->sql) === 1) {
            $worldQueryCount++;
        }
    });

    $this->get('/skins/audio/jet-audio')
        ->assertOk()
        ->assertInertia(fn (AssertableInertia $page) => $page
            ->component('ArtworkPage')
            ->has('artwork.world_participation', 8));

    expect($worldQueryCount)->toBeLessThanOrEqual(6);
});