<?php

declare(strict_types=1);

use App\Models\NovaCard;
use App\Models\NovaCardCategory;
use App\Models\NovaCardChallenge;
use App\Models\NovaCardChallengeEntry;
use App\Models\NovaCardComment;
use App\Models\NovaCardTemplate;
use App\Models\Report;
use App\Models\User;
use Illuminate\Support\Arr;
use Illuminate\Support\Str;

function reportCardCategory(array $attributes = []): NovaCardCategory
{
    return NovaCardCategory::query()->create(array_merge([
        'slug' => 'report-category-' . Str::lower(Str::random(6)),
        'name' => 'Report Category',
        'description' => 'Report category',
        'active' => true,
        'order_num' => 0,
    ], $attributes));
}

function reportCardTemplate(array $attributes = []): NovaCardTemplate
{
    return NovaCardTemplate::query()->create(array_merge([
        'slug' => 'report-template-' . Str::lower(Str::random(6)),
        'name' => 'Report Template',
        'description' => 'Report template',
        'config_json' => [
            'font_preset' => 'modern-sans',
            'gradient_preset' => 'midnight-nova',
            'layout' => 'quote_heavy',
            'text_align' => 'center',
            'text_color' => '#ffffff',
            'overlay_style' => 'dark-soft',
        ],
        'supported_formats' => ['square'],
        'active' => true,
        'official' => true,
        'order_num' => 0,
    ], $attributes));
}

function reportableCard(User $user, array $attributes = []): NovaCard
{
    $category = $attributes['category'] ?? reportCardCategory();
    $template = $attributes['template'] ?? reportCardTemplate();

    return NovaCard::query()->create(array_merge([
        'user_id' => $user->id,
        'category_id' => $category->id,
        'template_id' => $template->id,
        'title' => 'Reportable Card',
        'slug' => 'reportable-card-' . Str::lower(Str::random(6)),
        'quote_text' => 'Card that can be reported.',
        'format' => NovaCard::FORMAT_SQUARE,
        'project_json' => [
            'content' => ['title' => 'Reportable Card', 'quote_text' => 'Card that can be reported.'],
            'layout' => ['layout' => 'quote_heavy', 'position' => 'center', 'alignment' => 'center', 'padding' => 'comfortable', 'max_width' => 'balanced'],
            'typography' => ['font_preset' => 'modern-sans', 'text_color' => '#ffffff', 'accent_color' => '#e0f2fe', 'quote_size' => 72, 'author_size' => 28, 'letter_spacing' => 0, 'line_height' => 1.2, 'shadow_preset' => 'soft'],
            'background' => ['type' => 'gradient', 'gradient_preset' => 'midnight-nova', 'gradient_colors' => ['#0f172a', '#1d4ed8'], 'overlay_style' => 'dark-soft', 'focal_position' => 'center', 'blur_level' => 0, 'opacity' => 50],
            'decorations' => [],
        ],
        'render_version' => 2,
        'schema_version' => 2,
        'background_type' => 'gradient',
        'visibility' => NovaCard::VISIBILITY_PUBLIC,
        'status' => NovaCard::STATUS_PUBLISHED,
        'moderation_status' => NovaCard::MOD_APPROVED,
        'allow_download' => true,
        'allow_remix' => true,
        'published_at' => now()->subMinutes(5),
    ], Arr::except($attributes, ['category', 'template'])));
}

it('accepts nova card, challenge, and challenge entry reports through the shared intake endpoint', function (): void {
    $reporter = User::factory()->create(['username' => 'reporter']);
    $creator = User::factory()->create(['username' => 'creator']);
    $card = reportableCard($creator);
    $challenge = NovaCardChallenge::query()->create([
        'user_id' => $creator->id,
        'slug' => 'reporting-challenge',
        'title' => 'Reporting Challenge',
        'description' => 'Challenge description',
        'prompt' => 'Challenge prompt',
        'status' => NovaCardChallenge::STATUS_ACTIVE,
        'official' => true,
        'featured' => false,
        'starts_at' => now()->subDay(),
        'ends_at' => now()->addWeek(),
    ]);
    $entry = NovaCardChallengeEntry::query()->create([
        'challenge_id' => $challenge->id,
        'card_id' => $card->id,
        'user_id' => $creator->id,
        'status' => NovaCardChallengeEntry::STATUS_SUBMITTED,
        'note' => 'Challenge entry note',
    ]);

    $this->actingAs($reporter)
        ->postJson(route('api.reports.store'), [
            'target_type' => 'nova_card',
            'target_id' => $card->id,
            'reason' => 'Misleading card',
        ])
        ->assertCreated();

    $this->actingAs($reporter)
        ->postJson(route('api.reports.store'), [
            'target_type' => 'nova_card_challenge',
            'target_id' => $challenge->id,
            'reason' => 'Bad challenge brief',
        ])
        ->assertCreated();

    $this->actingAs($reporter)
        ->postJson(route('api.reports.store'), [
            'target_type' => 'nova_card_challenge_entry',
            'target_id' => $entry->id,
            'reason' => 'Spam challenge entry',
            'details' => 'This entry is unrelated to the prompt.',
        ])
        ->assertCreated();

    expect(Report::query()->where('reporter_id', $reporter->id)->count())->toBe(3);
});

it('accepts nova card comment reports through the shared intake endpoint', function (): void {
    $reporter = User::factory()->create(['username' => 'commentreporter']);
    $creator = User::factory()->create(['username' => 'commentreportcreator']);
    $card = reportableCard($creator, ['title' => 'Comment Report Card']);
    $comment = NovaCardComment::query()->create([
        'card_id' => $card->id,
        'user_id' => $creator->id,
        'body' => 'Questionable comment body.',
        'rendered_body' => 'Questionable comment body.',
        'status' => 'visible',
    ]);

    $this->actingAs($reporter)
        ->postJson(route('api.reports.store'), [
            'target_type' => 'nova_card_comment',
            'target_id' => $comment->id,
            'reason' => 'Abusive comment',
        ])
        ->assertCreated();

    expect(Report::query()->where('target_type', 'nova_card_comment')->where('target_id', $comment->id)->exists())->toBeTrue();
});

it('filters nova card reports in the moderation queue and allows status transitions', function (): void {
    $admin = User::factory()->create(['role' => 'admin']);
    $reporter = User::factory()->create(['username' => 'queuereporter']);
    $creator = User::factory()->create(['username' => 'queuecreator']);
    $card = reportableCard($creator, ['title' => 'Queue Card']);
    $challenge = NovaCardChallenge::query()->create([
        'user_id' => $creator->id,
        'slug' => 'queue-challenge',
        'title' => 'Queue Challenge',
        'prompt' => 'Queue prompt',
        'status' => NovaCardChallenge::STATUS_ACTIVE,
        'official' => true,
        'featured' => false,
        'starts_at' => now()->subDay(),
        'ends_at' => now()->addWeek(),
    ]);

    $cardReport = Report::query()->create([
        'reporter_id' => $reporter->id,
        'target_type' => 'nova_card',
        'target_id' => $card->id,
        'reason' => 'Card spam',
        'status' => 'open',
    ]);

    Report::query()->create([
        'reporter_id' => $reporter->id,
        'target_type' => 'nova_card_challenge',
        'target_id' => $challenge->id,
        'reason' => 'Challenge abuse',
        'status' => 'open',
    ]);

    Report::query()->create([
        'reporter_id' => $reporter->id,
        'target_type' => 'user',
        'target_id' => $creator->id,
        'reason' => 'Unrelated user report',
        'status' => 'open',
    ]);

    $queue = $this->actingAs($admin)
        ->getJson(route('api.admin.reports.queue', ['group' => 'nova_cards', 'status' => 'open']))
        ->assertOk();

    expect($queue->json('meta.total'))->toBe(2)
        ->and(collect($queue->json('data'))->pluck('target.label')->all())->toContain('Queue Card', 'Queue Challenge');

    $this->actingAs($admin)
        ->patchJson(route('api.admin.reports.update', ['report' => $cardReport->id]), [
            'status' => 'reviewing',
        ])
        ->assertOk()
        ->assertJsonPath('report.status', 'reviewing')
        ->assertJsonPath('report.target.label', 'Queue Card');

    $reviewing = $this->actingAs($admin)
        ->getJson(route('api.admin.reports.queue', ['group' => 'nova_cards', 'status' => 'reviewing']))
        ->assertOk();

    expect($reviewing->json('meta.total'))->toBe(1)
        ->and($cardReport->fresh()->status)->toBe('reviewing');
});

it('records moderator notes and report history entries from the moderation queue', function (): void {
    $admin = User::factory()->create(['role' => 'admin', 'username' => 'auditadmin']);
    $reporter = User::factory()->create(['username' => 'auditreporter']);
    $creator = User::factory()->create(['username' => 'auditcreator']);
    $card = reportableCard($creator, ['title' => 'Audit Queue Card']);

    $report = Report::query()->create([
        'reporter_id' => $reporter->id,
        'target_type' => 'nova_card',
        'target_id' => $card->id,
        'reason' => 'Needs closer review',
        'status' => 'open',
    ]);

    $response = $this->actingAs($admin)
        ->patchJson(route('api.admin.reports.update', ['report' => $report->id]), [
            'status' => 'reviewing',
            'moderator_note' => 'Escalated to card moderation while we verify the prompt source.',
        ])
        ->assertOk();

    $report->refresh();

    expect($report->status)->toBe('reviewing')
        ->and($report->moderator_note)->toBe('Escalated to card moderation while we verify the prompt source.')
        ->and($report->last_moderated_by_id)->toBe($admin->id)
        ->and($report->historyEntries()->count())->toBe(1)
        ->and($response->json('report.history.0.summary'))->toContain('Status open -> reviewing')
        ->and($response->json('report.history.0.actor.username'))->toBe('auditadmin');
});

it('allows moderators to update the underlying nova card from a report row', function (): void {
    $admin = User::factory()->create(['role' => 'admin']);
    $reporter = User::factory()->create(['username' => 'targetreporter']);
    $creator = User::factory()->create(['username' => 'targetcreator']);
    $card = reportableCard($creator, [
        'title' => 'Flaggable Queue Card',
        'moderation_status' => NovaCard::MOD_PENDING,
        'project_json' => [
            'content' => ['title' => 'Flaggable Queue Card', 'quote_text' => 'Report queue card'],
            'moderation' => [
                'source' => 'publish_heuristics',
                'flagged' => true,
                'reasons' => ['self_remix_loop'],
            ],
        ],
    ]);

    $report = Report::query()->create([
        'reporter_id' => $reporter->id,
        'target_type' => 'nova_card',
        'target_id' => $card->id,
        'reason' => 'Suspicious engagement bait',
        'status' => 'reviewing',
    ]);

    $this->actingAs($admin)
        ->postJson(route('api.admin.reports.moderate-target', ['report' => $report->id]), [
            'action' => 'flag_card',
            'disposition' => 'rights_review_required',
        ])
        ->assertOk()
        ->assertJsonPath('report.target.moderation_target.card_id', $card->id)
        ->assertJsonPath('report.target.moderation_target.moderation_status', NovaCard::MOD_FLAGGED)
        ->assertJsonPath('report.target.moderation_target.moderation_reasons.0', 'self_remix_loop')
        ->assertJsonPath('report.target.moderation_target.moderation_reason_labels.0', 'Self-remix loop')
        ->assertJsonPath('report.target.moderation_target.moderation_override.source', 'report_queue')
        ->assertJsonPath('report.target.moderation_target.moderation_override.disposition', 'rights_review_required')
        ->assertJsonPath('report.target.moderation_target.moderation_override.disposition_label', 'Rights review required')
        ->assertJsonPath('report.target.moderation_target.moderation_override_history.0.disposition_label', 'Rights review required')
        ->assertJsonPath('report.target.moderation_target.moderation_override.report_id', $report->id)
        ->assertJsonPath('report.history.0.action_type', 'target_moderated');

    expect($card->fresh()->moderation_status)->toBe(NovaCard::MOD_FLAGGED)
        ->and($card->fresh()->project_json['moderation']['override']['source'] ?? null)->toBe('report_queue')
        ->and($card->fresh()->project_json['moderation']['override']['disposition'] ?? null)->toBe('rights_review_required')
        ->and($report->fresh()->historyEntries()->count())->toBe(1)
        ->and($report->fresh()->last_moderated_by_id)->toBe($admin->id);
});

it('includes nova card comment reports in the nova cards moderation queue', function (): void {
    $admin = User::factory()->create(['role' => 'admin']);
    $reporter = User::factory()->create(['username' => 'commentqueuereporter']);
    $creator = User::factory()->create(['username' => 'commentqueuecreator']);
    $card = reportableCard($creator, ['title' => 'Queue Comment Card']);
    $comment = NovaCardComment::query()->create([
        'card_id' => $card->id,
        'user_id' => $creator->id,
        'body' => 'Queue this comment too.',
        'rendered_body' => 'Queue this comment too.',
        'status' => 'visible',
    ]);

    Report::query()->create([
        'reporter_id' => $reporter->id,
        'target_type' => 'nova_card_comment',
        'target_id' => $comment->id,
        'reason' => 'Comment harassment',
        'status' => 'open',
    ]);

    $queue = $this->actingAs($admin)
        ->getJson(route('api.admin.reports.queue', ['group' => 'nova_cards', 'status' => 'open']))
        ->assertOk();

    expect(collect($queue->json('data'))->pluck('target.type')->all())->toContain('nova_card_comment');
});

it('renders challenge reporting controls for authenticated viewers', function (): void {
    $viewer = User::factory()->create(['username' => 'challengeviewer']);
    $creator = User::factory()->create(['username' => 'challengecreator']);
    $card = reportableCard($creator, ['title' => 'Challenge Card']);
    $challenge = NovaCardChallenge::query()->create([
        'user_id' => $creator->id,
        'slug' => 'challenge-report-page',
        'title' => 'Challenge Report Page',
        'description' => 'Challenge description',
        'prompt' => 'Challenge prompt',
        'status' => NovaCardChallenge::STATUS_ACTIVE,
        'official' => true,
        'featured' => true,
        'starts_at' => now()->subDay(),
        'ends_at' => now()->addWeek(),
    ]);

    NovaCardChallengeEntry::query()->create([
        'challenge_id' => $challenge->id,
        'card_id' => $card->id,
        'user_id' => $creator->id,
        'status' => NovaCardChallengeEntry::STATUS_SUBMITTED,
    ]);

    $response = $this->actingAs($viewer)
        ->get(route('cards.challenges.show', ['slug' => $challenge->slug]))
        ->assertOk();

    expect($response->getContent())
        ->toContain('data-report-target-type="nova_card_challenge"')
        ->toContain('data-report-target-type="nova_card_challenge_entry"');
});