<?php

declare(strict_types=1);

use App\Jobs\IngestUserDiscoveryEventJob;
use App\Models\Artwork;
use App\Models\Category;
use App\Models\ContentType;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Queue;

uses(RefreshDatabase::class);

it('queues discovery event ingestion asynchronously', function () {
    Queue::fake();

    $user = User::factory()->create();
    $artwork = Artwork::factory()->create();

    $response = $this->actingAs($user)->postJson('/api/discovery/events', [
        'event_type' => 'view',
        'artwork_id' => $artwork->id,
        'meta' => ['source' => 'artwork_show'],
    ]);

    $response
        ->assertStatus(202)
        ->assertJsonPath('queued', true)
        ->assertJsonPath('algo_version', (string) config('discovery.algo_version'));

    Queue::assertPushed(IngestUserDiscoveryEventJob::class, function (IngestUserDiscoveryEventJob $job) use ($user, $artwork): bool {
        return $job->userId === $user->id
            && $job->artworkId === $artwork->id
            && $job->eventType === 'view';
    });
});

it('validates discovery event payload', function () {
    $user = User::factory()->create();
    $artwork = Artwork::factory()->create();

    $response = $this->actingAs($user)->postJson('/api/discovery/events', [
        'event_type' => 'impression',
        'artwork_id' => $artwork->id,
    ]);

    $response->assertStatus(422);
    $response->assertJsonValidationErrors(['event_type']);
});

it('accepts session-oriented discovery events', function () {
    Queue::fake();

    $user = User::factory()->create();
    $artwork = Artwork::factory()->create();

    $response = $this->actingAs($user)->postJson('/api/discovery/events', [
        'event_type' => 'dwell',
        'artwork_id' => $artwork->id,
        'meta' => ['duration_ms' => 4500],
    ]);

    $response->assertStatus(202);

    Queue::assertPushed(IngestUserDiscoveryEventJob::class, function (IngestUserDiscoveryEventJob $job): bool {
        return $job->eventType === 'dwell';
    });
});

it('stores discovery event meta as json when ingesting queued events', function (): void {
    $user = User::factory()->create();

    $contentType = ContentType::query()->create([
        'name' => 'Skins',
        'slug' => 'skins',
    ]);

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

    $artwork = Artwork::factory()->create([
        'user_id' => $user->id,
    ]);

    DB::table('artwork_category')->insert([
        'artwork_id' => $artwork->id,
        'category_id' => $category->id,
    ]);

    $meta = [
        'source' => 'feed',
        'context' => [
            'slot' => 'for-you',
            'score' => 0.88,
        ],
    ];

    $job = new IngestUserDiscoveryEventJob(
        eventId: (string) \Illuminate\Support\Str::uuid(),
        userId: $user->id,
        artworkId: $artwork->id,
        eventType: 'view',
        algoVersion: 'clip-cosine-v2-adaptive',
        occurredAt: now()->toIso8601String(),
        meta: $meta,
    );

    $job->handle(
        app(\App\Services\Recommendations\UserInterestProfileService::class),
        app(\App\Services\Recommendations\SessionRecoService::class),
    );

    $storedMeta = DB::table('user_discovery_events')->value('meta');

    expect($storedMeta)->not->toBeNull();
    expect(json_decode((string) $storedMeta, true))->toBe($meta);
});
