<?php

declare(strict_types=1);

namespace Tests\Feature\Ranking;

use App\Jobs\RankBuildListsJob;
use App\Jobs\RankBuildScopeListsJob;
use App\Models\ContentType;
use App\Models\RankList;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Queue;
use Tests\TestCase;

class RankBuildListsDispatchTest extends TestCase
{
    use RefreshDatabase;

    public function test_dispatcher_fans_out_only_active_category_scopes(): void
    {
        Queue::fake();

        $contentType = ContentType::create([
            'name' => 'Wallpapers',
            'slug' => 'wallpapers',
        ]);

        $activeCategoryIds = [
            (int) $contentType->categories()->create([
                'name' => 'Abstract',
                'slug' => 'abstract',
                'is_active' => true,
            ])->id,
            (int) $contentType->categories()->create([
                'name' => 'Nature',
                'slug' => 'nature',
                'is_active' => true,
            ])->id,
        ];

        $contentType->categories()->create([
            'name' => 'Hidden',
            'slug' => 'hidden',
            'is_active' => false,
        ]);

        (new RankBuildListsJob)->handle();

        Queue::assertPushed(RankBuildScopeListsJob::class, 4);
        Queue::assertPushed(RankBuildScopeListsJob::class, fn (RankBuildScopeListsJob $job) => $job->scopeType === 'global' && $job->scopeId === 0);
        Queue::assertPushed(RankBuildScopeListsJob::class, fn (RankBuildScopeListsJob $job) => $job->scopeType === 'content_type' && $job->scopeId === (int) $contentType->id);

        foreach ($activeCategoryIds as $categoryId) {
            Queue::assertPushed(RankBuildScopeListsJob::class, fn (RankBuildScopeListsJob $job) => $job->scopeType === 'category' && $job->scopeId === $categoryId);
        }

        Queue::assertNotPushed(RankBuildScopeListsJob::class, fn (RankBuildScopeListsJob $job) => $job->scopeType === 'category' && ! in_array($job->scopeId, $activeCategoryIds, true));
    }

    public function test_scope_job_upserts_rows_even_when_scope_has_no_candidates(): void
    {
        $contentType = ContentType::create([
            'name' => 'Photography',
            'slug' => 'photography',
        ]);

        $category = $contentType->categories()->create([
            'name' => 'Macro',
            'slug' => 'macro',
            'is_active' => true,
        ]);

        app()->call([new RankBuildScopeListsJob('category', (int) $category->id), 'handle']);

        $rows = RankList::query()
            ->where('scope_type', 'category')
            ->where('scope_id', $category->id)
            ->where('model_version', config('ranking.model_version'))
            ->orderBy('list_type')
            ->get();

        $this->assertCount(3, $rows);
        $this->assertSame(['best', 'new_hot', 'trending'], $rows->pluck('list_type')->all());
        $this->assertTrue($rows->every(fn (RankList $row) => $row->artwork_ids === []));
    }
}