<?php

declare(strict_types=1);

use App\Models\Artwork;
use App\Models\User;
use App\Jobs\DetectArtworkMaturityJob;
use App\Services\Maturity\ArtworkMaturityService;
use App\Models\Collection;
use App\Services\CollectionService;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Queue;
use Inertia\Testing\AssertableInertia;
use Klevze\ControlPanel\Models\Admin\AdminVerification;
use Klevze\ControlPanel\Models\Auth\User as ControlPanelUser;

uses(RefreshDatabase::class);

function createMaturityQueueAdmin(): User
{
    $admin = User::factory()->create(['role' => 'admin']);
    $admin->forceFill([
        'isAdmin' => true,
        'activated' => true,
    ])->save();

    AdminVerification::createForUser($admin->fresh());

    return $admin->fresh();
}

it('persists content preferences from the settings endpoint', function () {
    $user = User::factory()->create();

    $this->actingAs($user)
        ->postJson('/settings/content/update', [
            'mature_content_visibility' => 'hide',
            'mature_content_warning_enabled' => false,
        ])
        ->assertOk()
        ->assertJsonPath('success', true)
        ->assertJsonPath('message', 'Content preferences saved successfully.');

    $profile = DB::table('user_profiles')
        ->where('user_id', $user->id)
        ->first(['mature_content_visibility', 'mature_content_warning_enabled']);

    expect($profile)->not->toBeNull()
        ->and($profile->mature_content_visibility)->toBe('hide')
        ->and((int) $profile->mature_content_warning_enabled)->toBe(0);
});

it('derives mature artwork presentation from viewer preferences', function () {
    $artwork = Artwork::factory()->create([
        'is_mature' => true,
        'maturity_level' => ArtworkMaturityService::LEVEL_MATURE,
        'maturity_status' => ArtworkMaturityService::STATUS_DECLARED,
    ]);

    $hideViewer = User::factory()->create();
    $blurViewer = User::factory()->create();
    $showViewer = User::factory()->create();

    DB::table('user_profiles')->insert([
        [
            'user_id' => $hideViewer->id,
            'mature_content_visibility' => 'hide',
            'mature_content_warning_enabled' => true,
        ],
        [
            'user_id' => $blurViewer->id,
            'mature_content_visibility' => 'blur',
            'mature_content_warning_enabled' => false,
        ],
        [
            'user_id' => $showViewer->id,
            'mature_content_visibility' => 'show',
            'mature_content_warning_enabled' => true,
        ],
    ]);

    $maturity = app(ArtworkMaturityService::class);

    $hidden = $maturity->presentation($artwork, $hideViewer);
    $blurred = $maturity->presentation($artwork, $blurViewer);
    $shown = $maturity->presentation($artwork, $showViewer);

    expect($hidden['should_hide'])->toBeTrue()
        ->and($hidden['should_blur'])->toBeFalse()
        ->and($hidden['requires_interstitial'])->toBeTrue()
        ->and($blurred['should_hide'])->toBeFalse()
        ->and($blurred['should_blur'])->toBeTrue()
        ->and($blurred['requires_interstitial'])->toBeFalse()
        ->and($shown['should_hide'])->toBeFalse()
        ->and($shown['should_blur'])->toBeFalse()
        ->and($shown['requires_interstitial'])->toBeTrue();
});

it('applies uploader mature declarations when publishing an existing artwork', function () {
    Queue::fake();

    $user = User::factory()->create();
    $artwork = Artwork::factory()->create([
        'user_id' => $user->id,
        'is_mature' => false,
        'maturity_level' => ArtworkMaturityService::LEVEL_SAFE,
        'maturity_status' => ArtworkMaturityService::STATUS_CLEAR,
        'maturity_source' => ArtworkMaturityService::SOURCE_LEGACY,
    ]);

    $this->actingAs($user)
        ->postJson("/api/uploads/{$artwork->id}/publish", [
            'title' => 'Updated title',
            'is_mature' => true,
            'visibility' => 'private',
        ])
        ->assertOk()
        ->assertJsonPath('success', true)
        ->assertJsonPath('status', 'published');

    $artwork->refresh();

    expect($artwork->is_mature)->toBeTrue()
        ->and($artwork->maturity_level)->toBe(ArtworkMaturityService::LEVEL_MATURE)
        ->and($artwork->maturity_status)->toBe(ArtworkMaturityService::STATUS_DECLARED)
        ->and($artwork->maturity_source)->toBe(ArtworkMaturityService::SOURCE_USER);
});

it('flags undeclared mature content from AI assessment', function () {
    Queue::fake();

    $artwork = Artwork::factory()->create([
        'is_mature' => false,
        'maturity_level' => ArtworkMaturityService::LEVEL_SAFE,
        'maturity_status' => ArtworkMaturityService::STATUS_CLEAR,
        'maturity_mismatch_count' => 0,
    ]);

    $assessment = app(ArtworkMaturityService::class)->applyAiAssessment($artwork, [
        'clip_tags' => [
            ['tag' => 'nudity'],
        ],
        'yolo_objects' => [],
        'blip_caption' => 'topless portrait',
    ]);

    $artwork->refresh();

    expect($assessment['flagged'])->toBeTrue()
        ->and($assessment['score'])->toBeGreaterThanOrEqual(0.68)
        ->and($artwork->maturity_status)->toBe(ArtworkMaturityService::STATUS_SUSPECTED)
        ->and($artwork->maturity_flagged_at)->not->toBeNull()
        ->and($artwork->maturity_mismatch_count)->toBe(1)
        ->and($artwork->maturity_ai_labels)->toContain('nudity');
});

it('stores normalized maturity endpoint results and flags review-worthy content', function () {
    Queue::fake();

    $artwork = Artwork::factory()->create([
        'is_mature' => false,
        'maturity_level' => ArtworkMaturityService::LEVEL_SAFE,
        'maturity_status' => ArtworkMaturityService::STATUS_CLEAR,
        'maturity_mismatch_count' => 0,
    ]);

    $assessment = app(ArtworkMaturityService::class)->applyAiAssessment($artwork, [
        'status' => 'succeeded',
        'maturity_label' => 'mature',
        'confidence' => 0.9321,
        'action_hint' => 'flag_high',
        'threshold_used' => 0.7,
        'analysis_time_ms' => 321,
        'model' => 'vision-maturity-v2',
        'advisory' => 'High confidence mature content.',
        'labels' => ['nudity'],
    ]);

    $artwork->refresh();

    expect($assessment['flagged'])->toBeTrue()
        ->and($artwork->maturity_status)->toBe(ArtworkMaturityService::STATUS_SUSPECTED)
        ->and($artwork->maturity_ai_status)->toBe(ArtworkMaturityService::AI_STATUS_SUCCEEDED)
        ->and($artwork->maturity_ai_label)->toBe(ArtworkMaturityService::LEVEL_MATURE)
        ->and($artwork->maturity_ai_confidence)->toBe(0.9321)
        ->and($artwork->maturity_ai_action_hint)->toBe(ArtworkMaturityService::AI_ACTION_FLAG_HIGH)
        ->and($artwork->maturity_ai_threshold_used)->toBe(0.7)
        ->and($artwork->maturity_ai_analysis_time_ms)->toBe(321)
        ->and($artwork->maturity_ai_model)->toBe('vision-maturity-v2')
        ->and($artwork->maturity_ai_advisory)->toBe('High confidence mature content.')
        ->and($artwork->maturity_mismatch_count)->toBe(1);
});

it('normalizes safe action hints from the vision maturity contract', function () {
    Queue::fake();

    $artwork = Artwork::factory()->create([
        'is_mature' => false,
        'maturity_level' => ArtworkMaturityService::LEVEL_SAFE,
        'maturity_status' => ArtworkMaturityService::STATUS_CLEAR,
    ]);

    $assessment = app(ArtworkMaturityService::class)->applyAiAssessment($artwork, [
        'status' => 'succeeded',
        'maturity_label' => 'safe',
        'confidence' => 0.1123,
        'action_hint' => 'safe',
        'threshold_used' => 0.7,
        'model' => 'vision-maturity-v2',
        'labels' => ['safe'],
    ]);

    $artwork->refresh();

    expect($assessment['flagged'])->toBeFalse()
        ->and($assessment['action_hint'])->toBe(ArtworkMaturityService::AI_ACTION_SAFE)
        ->and($artwork->maturity_ai_action_hint)->toBe(ArtworkMaturityService::AI_ACTION_SAFE)
        ->and($artwork->maturity_status)->toBe(ArtworkMaturityService::STATUS_CLEAR);
});

it('records failed maturity AI analysis without implying safe content', function () {
    Queue::fake();

    $artwork = Artwork::factory()->create([
        'is_mature' => false,
        'maturity_level' => ArtworkMaturityService::LEVEL_SAFE,
        'maturity_status' => ArtworkMaturityService::STATUS_CLEAR,
        'maturity_ai_status' => ArtworkMaturityService::AI_STATUS_NOT_REQUESTED,
    ]);

    $assessment = app(ArtworkMaturityService::class)->applyAiAssessment($artwork, [
        'status' => 'failed',
        'advisory' => 'Gateway timeout.',
    ]);

    $artwork->refresh();

    expect($assessment['flagged'])->toBeFalse()
        ->and($artwork->maturity_status)->toBe(ArtworkMaturityService::STATUS_CLEAR)
        ->and($artwork->is_mature)->toBeFalse()
        ->and($artwork->maturity_ai_status)->toBe(ArtworkMaturityService::AI_STATUS_FAILED)
        ->and($artwork->maturity_ai_advisory)->toBe('Gateway timeout.')
        ->and($artwork->maturity_ai_label)->toBeNull();
});

it('lets moderators review suspected artworks', function () {
    Queue::fake();

    $moderator = User::factory()->create(['role' => 'moderator']);
    $artwork = Artwork::factory()->create([
        'is_mature' => false,
        'maturity_level' => ArtworkMaturityService::LEVEL_SAFE,
        'maturity_status' => ArtworkMaturityService::STATUS_SUSPECTED,
        'maturity_flag_reason' => 'AI suspected mature content from: nudity',
    ]);

    $this->actingAs($moderator)
        ->postJson("/cp/maturity/{$artwork->id}/review", [
            'action' => 'mark_mature',
            'note' => 'Confirmed mature by moderation review.',
        ])
        ->assertOk()
        ->assertJsonPath('success', true)
        ->assertJsonPath('artwork.id', $artwork->id);

    $artwork->refresh();

    expect($artwork->is_mature)->toBeTrue()
        ->and($artwork->maturity_level)->toBe(ArtworkMaturityService::LEVEL_MATURE)
        ->and($artwork->maturity_status)->toBe(ArtworkMaturityService::STATUS_REVIEWED)
        ->and($artwork->maturity_source)->toBe(ArtworkMaturityService::SOURCE_MODERATOR)
        ->and($artwork->maturity_reviewed_by)->toBe($moderator->id)
        ->and($artwork->maturity_reviewer_note)->toBe('Confirmed mature by moderation review.');
});

it('renders the moderation queue page and filters queue items by status', function () {
    Queue::fake();

    $moderator = User::factory()->create(['role' => 'moderator']);

    $suspected = Artwork::factory()->create([
        'title' => 'Suspected Queue Artwork',
        'is_mature' => false,
        'maturity_level' => ArtworkMaturityService::LEVEL_SAFE,
        'maturity_status' => ArtworkMaturityService::STATUS_SUSPECTED,
        'maturity_flag_reason' => 'AI suspected mature content from: nudity',
        'maturity_ai_status' => ArtworkMaturityService::AI_STATUS_SUCCEEDED,
        'maturity_ai_label' => ArtworkMaturityService::LEVEL_MATURE,
        'maturity_ai_score' => 0.8812,
        'maturity_ai_confidence' => 0.8812,
        'maturity_ai_action_hint' => ArtworkMaturityService::AI_ACTION_REVIEW,
        'maturity_ai_labels' => ['nudity'],
        'published_at' => now(),
    ]);

    $reviewed = Artwork::factory()->create([
        'title' => 'Reviewed Queue Artwork',
        'is_mature' => true,
        'maturity_level' => ArtworkMaturityService::LEVEL_MATURE,
        'maturity_status' => ArtworkMaturityService::STATUS_REVIEWED,
        'maturity_source' => ArtworkMaturityService::SOURCE_MODERATOR,
        'maturity_reviewed_by' => $moderator->id,
        'maturity_reviewed_at' => now(),
        'maturity_reviewer_note' => 'Already reviewed.',
        'published_at' => now(),
    ]);

    $this->actingAs($moderator)
        ->get('/cp/maturity')
        ->assertOk()
        ->assertInertia(fn (AssertableInertia $page) => $page
            ->component('Moderation/ArtworkMaturityQueue')
            ->where('title', 'Artwork Maturity Queue')
            ->where('stats.suspected', 1)
            ->where('stats.reviewed', 1)
            ->where('initialItems.0.id', $suspected->id)
            ->where('initialItems.0.title', 'Suspected Queue Artwork')
            ->where('initialItems.0.maturity.ai_action_hint', ArtworkMaturityService::AI_ACTION_REVIEW)
        );

    $this->actingAs($moderator)
        ->getJson('/cp/maturity/queue?status=reviewed')
        ->assertOk()
        ->assertJsonPath('meta.status', 'reviewed')
        ->assertJsonPath('meta.stats.suspected', 1)
        ->assertJsonPath('meta.stats.reviewed', 1)
        ->assertJsonCount(1, 'data')
        ->assertJsonPath('data.0.id', $reviewed->id)
        ->assertJsonPath('data.0.review.reviewer_note', 'Already reviewed.');
});

it('renders the artwork admin maturity queue for cpad admins', function () {
    Queue::fake();

    $admin = createMaturityQueueAdmin();
    $suspected = Artwork::factory()->create([
        'title' => 'Admin Surface Suspected Artwork',
        'is_mature' => false,
        'maturity_level' => ArtworkMaturityService::LEVEL_SAFE,
        'maturity_status' => ArtworkMaturityService::STATUS_SUSPECTED,
        'maturity_ai_status' => ArtworkMaturityService::AI_STATUS_SUCCEEDED,
        'maturity_ai_action_hint' => ArtworkMaturityService::AI_ACTION_REVIEW,
        'published_at' => now(),
    ]);

    $this->actingAs($admin)->actingAs($admin, 'controlpanel')
        ->get(route('admin.cp.artworks.maturity.main'))
        ->assertOk()
        ->assertInertia(fn (AssertableInertia $page) => $page
            ->component('Moderation/ArtworkMaturityQueue')
            ->where('initialItems.0.id', $suspected->id)
            ->where('endpoints.list', route('admin.cp.artworks.maturity.queue'))
            ->where('endpoints.reviewPattern', route('admin.cp.artworks.maturity.review', ['artwork' => '__ARTWORK__']))
        );
});

it('allows cpad admins to open the legacy maturity queue url', function () {
    Queue::fake();

    $admin = createMaturityQueueAdmin();
    $suspected = Artwork::factory()->create([
        'title' => 'Legacy Url Suspected Artwork',
        'is_mature' => false,
        'maturity_level' => ArtworkMaturityService::LEVEL_SAFE,
        'maturity_status' => ArtworkMaturityService::STATUS_SUSPECTED,
        'maturity_ai_status' => ArtworkMaturityService::AI_STATUS_SUCCEEDED,
        'maturity_ai_action_hint' => ArtworkMaturityService::AI_ACTION_REVIEW,
        'published_at' => now(),
    ]);

    $this->actingAs($admin)->actingAs($admin, 'controlpanel')
        ->get('/cp/maturity')
        ->assertOk()
        ->assertInertia(fn (AssertableInertia $page) => $page
            ->component('Moderation/ArtworkMaturityQueue')
            ->where('initialItems.0.id', $suspected->id)
            ->where('endpoints.list', route('cp.maturity.list'))
            ->where('endpoints.reviewPattern', route('cp.maturity.review', ['artwork' => '__ARTWORK__']))
        );
});

it('defaults to the audit queue when suspected items are empty but audit candidates exist', function () {
    Queue::fake();

    $admin = createMaturityQueueAdmin();
    $artwork = Artwork::factory()->create([
        'title' => 'Audit First Queue Candidate',
        'hash' => 'audit-first-queue-candidate',
        'thumb_ext' => 'webp',
        'is_mature' => false,
        'maturity_level' => ArtworkMaturityService::LEVEL_SAFE,
        'maturity_source' => ArtworkMaturityService::SOURCE_LEGACY,
        'maturity_status' => ArtworkMaturityService::STATUS_CLEAR,
        'maturity_declared_at' => null,
        'maturity_reviewed_at' => null,
        'published_at' => now(),
    ]);

    DB::table('artwork_maturity_audit_findings')->insert([
        'artwork_id' => $artwork->id,
        'status' => 'open',
        'thumbnail_variant' => 'md',
        'ai_label' => 'mature',
        'ai_confidence' => 0.8442,
        'ai_score' => 0.8442,
        'ai_labels' => json_encode(['nudity'], JSON_UNESCAPED_SLASHES),
        'ai_model' => 'vision-maturity-v2',
        'ai_action_hint' => ArtworkMaturityService::AI_ACTION_REVIEW,
        'ai_status' => ArtworkMaturityService::AI_STATUS_SUCCEEDED,
        'ai_advisory' => 'Needs manual review.',
        'detected_at' => now(),
        'last_scanned_at' => now(),
        'created_at' => now(),
        'updated_at' => now(),
    ]);

    $this->actingAs($admin)->actingAs($admin, 'controlpanel')
        ->get('/cp/maturity')
        ->assertOk()
        ->assertInertia(fn (AssertableInertia $page) => $page
            ->component('Moderation/ArtworkMaturityQueue')
            ->where('initialFilters.status', 'audit')
            ->where('initialItems.0.id', $artwork->id)
            ->where('stats.audit', 1)
            ->where('stats.suspected', 0)
        );
});

it('filters the moderation queue by AI action hint', function () {
    Queue::fake();

    $moderator = User::factory()->create(['role' => 'moderator']);

    $flagHigh = Artwork::factory()->create([
        'title' => 'Flag High Artwork',
        'maturity_status' => ArtworkMaturityService::STATUS_SUSPECTED,
        'maturity_ai_status' => ArtworkMaturityService::AI_STATUS_SUCCEEDED,
        'maturity_ai_action_hint' => ArtworkMaturityService::AI_ACTION_FLAG_HIGH,
        'published_at' => now(),
    ]);

    Artwork::factory()->create([
        'title' => 'Review Artwork',
        'maturity_status' => ArtworkMaturityService::STATUS_SUSPECTED,
        'maturity_ai_status' => ArtworkMaturityService::AI_STATUS_SUCCEEDED,
        'maturity_ai_action_hint' => ArtworkMaturityService::AI_ACTION_REVIEW,
        'published_at' => now(),
    ]);

    $this->actingAs($moderator)
        ->getJson('/cp/maturity/queue?status=suspected&ai_action=flag_high')
        ->assertOk()
        ->assertJsonPath('meta.filters.ai_action', ArtworkMaturityService::AI_ACTION_FLAG_HIGH)
        ->assertJsonCount(1, 'data')
        ->assertJsonPath('data.0.id', $flagHigh->id);
});

it('records audit findings for legacy artworks without mutating artwork maturity fields', function () {
    Queue::fake();

    $artwork = Artwork::factory()->create([
        'title' => 'Legacy Audit Candidate',
        'hash' => 'abc123def456',
        'thumb_ext' => 'webp',
        'is_mature' => false,
        'maturity_level' => ArtworkMaturityService::LEVEL_SAFE,
        'maturity_source' => ArtworkMaturityService::SOURCE_LEGACY,
        'maturity_status' => ArtworkMaturityService::STATUS_CLEAR,
        'maturity_declared_at' => null,
        'maturity_reviewed_at' => null,
    ]);

    config()->set('vision.enabled', true);
    config()->set('vision.maturity.base_url', 'https://vision.test');
    config()->set('vision.maturity.endpoint', '/analyze/maturity');

    Http::fake([
        'https://vision.test/*' => Http::response([
            'status' => 'succeeded',
            'maturity_label' => 'mature',
            'confidence' => 0.9123,
            'score' => 0.9123,
            'action_hint' => 'review',
            'labels' => ['nudity'],
            'model' => 'vision-maturity-v2',
            'advisory' => 'Needs moderator confirmation.',
        ], 200),
    ]);

    $this->artisan('artworks:audit-thumbnail-maturity', ['--limit' => 1])
        ->assertSuccessful();

    $artwork->refresh();

    expect($artwork->maturity_status)->toBe(ArtworkMaturityService::STATUS_CLEAR)
        ->and($artwork->maturity_source)->toBe(ArtworkMaturityService::SOURCE_LEGACY)
        ->and($artwork->is_mature)->toBeFalse();

    $this->assertDatabaseHas('artwork_maturity_audit_findings', [
        'artwork_id' => $artwork->id,
        'status' => 'open',
        'ai_action_hint' => ArtworkMaturityService::AI_ACTION_REVIEW,
        'ai_status' => ArtworkMaturityService::AI_STATUS_SUCCEEDED,
    ]);
});

it('shows audit candidates in cpad and resolves them after moderator review', function () {
    Queue::fake();

    $moderator = User::factory()->create(['role' => 'moderator']);
    $artwork = Artwork::factory()->create([
        'title' => 'Legacy Queue Candidate',
        'hash' => 'queuecandidate123',
        'thumb_ext' => 'webp',
        'is_mature' => false,
        'maturity_level' => ArtworkMaturityService::LEVEL_SAFE,
        'maturity_source' => ArtworkMaturityService::SOURCE_LEGACY,
        'maturity_status' => ArtworkMaturityService::STATUS_CLEAR,
        'maturity_declared_at' => null,
        'maturity_reviewed_at' => null,
        'published_at' => now(),
    ]);

    DB::table('artwork_maturity_audit_findings')->insert([
        'artwork_id' => $artwork->id,
        'status' => 'open',
        'thumbnail_variant' => 'md',
        'ai_label' => 'mature',
        'ai_confidence' => 0.8442,
        'ai_score' => 0.8442,
        'ai_labels' => json_encode(['nudity'], JSON_UNESCAPED_SLASHES),
        'ai_model' => 'vision-maturity-v2',
        'ai_action_hint' => ArtworkMaturityService::AI_ACTION_REVIEW,
        'ai_status' => ArtworkMaturityService::AI_STATUS_SUCCEEDED,
        'ai_advisory' => 'Needs manual review.',
        'detected_at' => now(),
        'last_scanned_at' => now(),
        'created_at' => now(),
        'updated_at' => now(),
    ]);

    $this->actingAs($moderator)
        ->getJson('/cp/maturity/queue?status=audit')
        ->assertOk()
        ->assertJsonPath('meta.status', 'audit')
        ->assertJsonPath('meta.stats.audit', 1)
        ->assertJsonCount(1, 'data')
        ->assertJsonPath('data.0.id', $artwork->id)
        ->assertJsonPath('data.0.audit.ai_action_hint', ArtworkMaturityService::AI_ACTION_REVIEW)
        ->assertJsonPath('data.0.audit.legacy_unset', true);

    $this->actingAs($moderator)
        ->postJson("/cp/maturity/{$artwork->id}/review", [
            'action' => 'mark_mature',
            'note' => 'Confirmed from audit queue.',
        ])
        ->assertOk();

    $artwork->refresh();

    expect($artwork->maturity_status)->toBe(ArtworkMaturityService::STATUS_REVIEWED)
        ->and($artwork->maturity_source)->toBe(ArtworkMaturityService::SOURCE_MODERATOR)
        ->and($artwork->is_mature)->toBeTrue();

    $this->assertDatabaseHas('artwork_maturity_audit_findings', [
        'artwork_id' => $artwork->id,
        'status' => 'reviewed',
        'resolved_by' => $moderator->id,
        'resolution_action' => 'mark_mature',
    ]);
});

it('allows cpad admins to review artwork maturity from the artwork admin surface', function () {
    Queue::fake();

    $admin = createMaturityQueueAdmin();
    $artwork = Artwork::factory()->create([
        'title' => 'Artwork Admin Review Candidate',
        'is_mature' => false,
        'maturity_level' => ArtworkMaturityService::LEVEL_SAFE,
        'maturity_status' => ArtworkMaturityService::STATUS_SUSPECTED,
        'maturity_flag_reason' => 'AI suspected mature content from: nudity',
    ]);

    $this->actingAs($admin)->actingAs($admin, 'controlpanel')
        ->postJson(route('admin.cp.artworks.maturity.review', ['artwork' => $artwork->id]), [
            'action' => 'mark_mature',
            'note' => 'Reviewed from artwork admin surface.',
        ])
        ->assertOk()
        ->assertJsonPath('success', true)
        ->assertJsonPath('artwork.id', $artwork->id);

    $artwork->refresh();

    expect($artwork->is_mature)->toBeTrue()
        ->and($artwork->maturity_level)->toBe(ArtworkMaturityService::LEVEL_MATURE)
        ->and($artwork->maturity_status)->toBe(ArtworkMaturityService::STATUS_REVIEWED)
        ->and($artwork->maturity_source)->toBe(ArtworkMaturityService::SOURCE_MODERATOR)
        ->and($artwork->maturity_reviewer_note)->toBe('Reviewed from artwork admin surface.');
});

it('accepts controlpanel auth users when recording maturity reviews', function () {
    Queue::fake();

    $admin = ControlPanelUser::query()->create([
        'name' => 'Legacy CP Admin',
        'email' => 'legacy-cp-admin@example.test',
        'password' => Hash::make('password'),
        'isAdmin' => true,
        'activated' => true,
    ]);
    $artwork = Artwork::factory()->create([
        'title' => 'Legacy CP Review Candidate',
        'is_mature' => false,
        'maturity_level' => ArtworkMaturityService::LEVEL_SAFE,
        'maturity_status' => ArtworkMaturityService::STATUS_SUSPECTED,
        'maturity_flag_reason' => 'AI suspected mature content from: nudity',
    ]);

    DB::table('artwork_maturity_audit_findings')->insert([
        'artwork_id' => $artwork->id,
        'status' => 'open',
        'thumbnail_variant' => 'md',
        'ai_label' => 'mature',
        'ai_confidence' => 0.8123,
        'ai_score' => 0.8123,
        'ai_labels' => json_encode(['nudity'], JSON_UNESCAPED_SLASHES),
        'ai_model' => 'vision-maturity-v2',
        'ai_action_hint' => ArtworkMaturityService::AI_ACTION_REVIEW,
        'ai_status' => ArtworkMaturityService::AI_STATUS_SUCCEEDED,
        'ai_advisory' => 'Needs manual review.',
        'detected_at' => now(),
        'last_scanned_at' => now(),
        'created_at' => now(),
        'updated_at' => now(),
    ]);

    app(ArtworkMaturityService::class)->review($artwork, 'mark_mature', $admin, 'Reviewed from legacy cp route.');
    app(\App\Services\Maturity\ArtworkMaturityAuditService::class)->resolveFindingForReview(
        $artwork,
        $admin,
        'mark_mature',
        'Reviewed from legacy cp route.',
    );

    $artwork->refresh();

    expect($artwork->is_mature)->toBeTrue()
        ->and($artwork->maturity_status)->toBe(ArtworkMaturityService::STATUS_REVIEWED)
        ->and($artwork->maturity_source)->toBe(ArtworkMaturityService::SOURCE_MODERATOR)
        ->and($artwork->maturity_reviewed_by)->toBe($admin->id)
        ->and($artwork->maturity_reviewer_note)->toBe('Reviewed from legacy cp route.');

    $this->assertDatabaseHas('artwork_maturity_audit_findings', [
        'artwork_id' => $artwork->id,
        'status' => 'reviewed',
        'resolved_by' => $admin->id,
        'resolution_action' => 'mark_mature',
    ]);
});

it('records a failed maturity detection job without marking the artwork safe by implication', function () {
    Queue::fake();

    $artwork = Artwork::factory()->create([
        'is_mature' => false,
        'maturity_level' => ArtworkMaturityService::LEVEL_SAFE,
        'maturity_status' => ArtworkMaturityService::STATUS_CLEAR,
        'maturity_ai_status' => ArtworkMaturityService::AI_STATUS_PENDING,
        'maturity_ai_label' => null,
    ]);

    $job = new DetectArtworkMaturityJob($artwork->id, 'fake-hash');
    $job->failed(new RuntimeException('Vision gateway timeout.'));

    $artwork->refresh();

    expect($artwork->is_mature)->toBeFalse()
        ->and($artwork->maturity_level)->toBe(ArtworkMaturityService::LEVEL_SAFE)
        ->and($artwork->maturity_status)->toBe(ArtworkMaturityService::STATUS_CLEAR)
        ->and($artwork->maturity_ai_status)->toBe(ArtworkMaturityService::AI_STATUS_FAILED)
        ->and($artwork->maturity_ai_advisory)->toBe('Vision gateway timeout.')
        ->and($artwork->maturity_ai_label)->toBeNull();
});

it('hides mature items from the daily uploads page for hide-mode viewers', function () {
    $viewer = User::factory()->create();

    DB::table('user_profiles')->insert([
        'user_id' => $viewer->id,
        'mature_content_visibility' => 'hide',
        'mature_content_warning_enabled' => true,
    ]);

    $safeArtwork = Artwork::factory()->create([
        'title' => 'Daily Safe Artwork',
        'is_public' => true,
        'is_approved' => true,
        'visibility' => Artwork::VISIBILITY_PUBLIC,
        'published_at' => now(),
        'is_mature' => false,
        'maturity_level' => ArtworkMaturityService::LEVEL_SAFE,
        'maturity_status' => ArtworkMaturityService::STATUS_CLEAR,
    ]);

    $matureArtwork = Artwork::factory()->create([
        'title' => 'Daily Hidden Mature Artwork',
        'is_public' => true,
        'is_approved' => true,
        'visibility' => Artwork::VISIBILITY_PUBLIC,
        'published_at' => now(),
        'is_mature' => true,
        'maturity_level' => ArtworkMaturityService::LEVEL_MATURE,
        'maturity_status' => ArtworkMaturityService::STATUS_DECLARED,
    ]);

    $this->actingAs($viewer)
        ->get(route('uploads.daily'))
        ->assertOk()
        ->assertSee('Daily Safe Artwork')
        ->assertDontSee('Daily Hidden Mature Artwork');

    expect($safeArtwork->exists)->toBeTrue()
        ->and($matureArtwork->exists)->toBeTrue();
});

it('filters collection artworks and cover fallbacks for hide-mode viewers', function () {
    $viewer = User::factory()->create();
    $owner = User::factory()->create();

    DB::table('user_profiles')->insert([
        'user_id' => $viewer->id,
        'mature_content_visibility' => 'hide',
        'mature_content_warning_enabled' => true,
    ]);

    $collection = Collection::factory()->create([
        'user_id' => $owner->id,
        'visibility' => Collection::VISIBILITY_PUBLIC,
    ]);

    $matureArtwork = Artwork::factory()->create([
        'user_id' => $owner->id,
        'title' => 'Hidden Cover Artwork',
        'hash' => 'mature-cover-hash',
        'thumb_ext' => 'jpg',
        'is_mature' => true,
        'maturity_level' => ArtworkMaturityService::LEVEL_MATURE,
        'maturity_status' => ArtworkMaturityService::STATUS_DECLARED,
        'published_at' => now(),
    ]);

    $safeArtwork = Artwork::factory()->create([
        'user_id' => $owner->id,
        'title' => 'Visible Safe Artwork',
        'hash' => 'safe-cover-hash',
        'thumb_ext' => 'jpg',
        'is_mature' => false,
        'maturity_level' => ArtworkMaturityService::LEVEL_SAFE,
        'maturity_status' => ArtworkMaturityService::STATUS_CLEAR,
        'published_at' => now(),
    ]);

    $collection->forceFill([
        'cover_artwork_id' => $matureArtwork->id,
    ])->save();

    DB::table('collection_artwork')->insert([
        [
            'collection_id' => $collection->id,
            'artwork_id' => $matureArtwork->id,
            'order_num' => 1,
            'created_at' => now(),
            'updated_at' => now(),
        ],
        [
            'collection_id' => $collection->id,
            'artwork_id' => $safeArtwork->id,
            'order_num' => 2,
            'created_at' => now(),
            'updated_at' => now(),
        ],
    ]);

    $service = app(CollectionService::class);
    $cardPayload = $service->mapCollectionCardPayloads(
        collect([$collection->fresh()->loadMissing(['user.profile', 'coverArtwork'])]),
        false,
        $viewer,
    )[0];
    $artworks = $service->getCollectionDetailArtworks($collection->fresh(), false, 24, $viewer);

    expect($cardPayload['cover_artwork_id'])->toBe($safeArtwork->id)
        ->and($artworks->getCollection()->pluck('id')->all())->toBe([$safeArtwork->id]);
});