<?php

declare(strict_types=1);

use App\Models\NovaCard;
use App\Models\NovaCardAssetPack;
use App\Models\NovaCardCategory;
use App\Models\NovaCardChallenge;
use App\Models\NovaCardCollection;
use App\Models\NovaCardCollectionItem;
use App\Models\NovaCardTemplate;
use App\Models\Report;
use App\Models\User;
use Illuminate\Support\Arr;
use Illuminate\Support\Str;
use Inertia\Testing\AssertableInertia;

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

function adminCardTemplate(array $attributes = []): NovaCardTemplate
{
    return NovaCardTemplate::query()->create(array_merge([
        'slug' => 'admin-template-' . Str::lower(Str::random(6)),
        'name' => 'Admin Template',
        'description' => 'Admin 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 moderatedCard(User $user, array $attributes = []): NovaCard
{
    $category = $attributes['category'] ?? adminCardCategory();
    $template = $attributes['template'] ?? adminCardTemplate();

    return NovaCard::query()->create(array_merge([
        'user_id' => $user->id,
        'category_id' => $category->id,
        'template_id' => $template->id,
        'title' => 'Moderation Card',
        'slug' => 'moderation-card-' . Str::lower(Str::random(6)),
        'quote_text' => 'A card waiting for moderation.',
        'format' => NovaCard::FORMAT_SQUARE,
        'project_json' => [
            'content' => ['title' => 'Moderation Card', 'quote_text' => 'A card waiting for moderation.'],
            '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' => 1,
        'background_type' => 'gradient',
        'visibility' => NovaCard::VISIBILITY_PUBLIC,
        'status' => NovaCard::STATUS_PUBLISHED,
        'moderation_status' => NovaCard::MOD_PENDING,
        'featured' => false,
        'allow_download' => true,
        'published_at' => now()->subMinutes(10),
    ], Arr::except($attributes, ['category', 'template'])));
}

it('blocks non staff users from the cards admin area', function (): void {
    $user = User::factory()->create(['role' => 'user']);

    $this->actingAs($user)
        ->get(route('cp.cards.index'))
        ->assertForbidden();
});

it('renders the cards admin index for admins', function (): void {
    $admin = User::factory()->create(['role' => 'admin']);
    $creator = User::factory()->create(['username' => 'spotlightmaker', 'nova_featured_creator' => true]);
    $card = moderatedCard($creator, [
        'title' => 'Needs Review',
        'project_json' => [
            'content' => ['title' => 'Needs Review', 'quote_text' => 'A card waiting for moderation.'],
            'moderation' => [
                'source' => 'publish_heuristics',
                'flagged' => true,
                'reasons' => ['duplicate_content'],
                'override' => [
                    'moderation_status' => 'flagged',
                    'disposition' => 'escalated_for_review',
                    'disposition_label' => 'Escalated for review',
                    'source' => 'report_queue',
                    'actor_username' => 'modone',
                    'updated_at' => now()->subMinutes(5)->toISOString(),
                ],
                'override_history' => [
                    [
                        'moderation_status' => 'flagged',
                        'disposition' => 'escalated_for_review',
                        'disposition_label' => 'Escalated for review',
                        'source' => 'report_queue',
                        'actor_username' => 'modone',
                        'updated_at' => now()->subMinutes(5)->toISOString(),
                    ],
                    [
                        'moderation_status' => 'pending',
                        'disposition' => 'returned_to_pending',
                        'disposition_label' => 'Returned to pending',
                        'source' => 'admin_card_update',
                        'actor_username' => 'modtwo',
                        'updated_at' => now()->subMinutes(12)->toISOString(),
                    ],
                ],
            ],
        ],
    ]);

    Report::query()->create([
        'reporter_id' => $creator->id,
        'target_type' => 'nova_card',
        'target_id' => $card->id,
        'reason' => 'Spam remix bait',
        'status' => 'open',
    ]);

    $this->actingAs($admin)
        ->get(route('cp.cards.index'))
        ->assertOk()
        ->assertInertia(fn (AssertableInertia $page) => $page
            ->component('Collection/NovaCardsAdminIndex')
            ->where('cards.data.0.title', 'Needs Review')
            ->where('cards.data.0.moderation_reasons.0', 'duplicate_content')
            ->where('cards.data.0.moderation_reason_labels.0', 'Duplicate content')
            ->where('cards.data.0.moderation_override_history.1.disposition_label', 'Returned to pending')
            ->where('moderationDispositionOptions.approved.1.value', 'approved_with_watch')
            ->where('featuredCreators.0.username', 'spotlightmaker')
            ->where('featuredCreators.0.nova_featured_creator', true)
            ->where('reportingQueue.label', 'Nova Cards report queue')
            ->where('reportingQueue.pending', 1)
            ->where('endpoints.updateCreatorPattern', route('cp.cards.creators.update', ['user' => '__CREATOR__']))
            ->where('endpoints.moderateReportTargetPattern', route('api.admin.reports.moderate-target', ['report' => '__REPORT__']))
            ->where('endpoints.templates', route('cp.cards.templates.index')));
});

it('allows admins to update card moderation fields', function (): void {
    $admin = User::factory()->create(['role' => 'admin']);
    $creator = User::factory()->create();
    $card = moderatedCard($creator);

    $this->actingAs($admin)
        ->patchJson(route('cp.cards.update', ['card' => $card->id]), [
            'status' => NovaCard::STATUS_PUBLISHED,
            'moderation_status' => NovaCard::MOD_APPROVED,
            'disposition' => 'approved_with_watch',
            'featured' => true,
            'allow_remix' => false,
        ])
        ->assertOk()
        ->assertJsonPath('card.featured', true)
        ->assertJsonPath('card.moderation_status', NovaCard::MOD_APPROVED)
        ->assertJsonPath('card.moderation_override.source', 'admin_card_update')
        ->assertJsonPath('card.moderation_override.disposition', 'approved_with_watch')
        ->assertJsonPath('card.moderation_override.disposition_label', 'Approved with watch')
        ->assertJsonPath('card.moderation_override_history.0.disposition_label', 'Approved with watch')
        ->assertJsonPath('card.moderation_override.actor_user_id', $admin->id)
        ->assertJsonPath('card.allow_remix', false);

    $fresh = $card->fresh();
    expect($fresh->featured)->toBeTrue();
    expect($fresh->moderation_status)->toBe(NovaCard::MOD_APPROVED);
    expect($fresh->allow_remix)->toBeFalse();
    expect($fresh->project_json['moderation']['override']['source'] ?? null)->toBe('admin_card_update')
        ->and($fresh->project_json['moderation']['override']['disposition'] ?? null)->toBe('approved_with_watch');
});

it('allows admins to feature creators for editorial surfacing', function (): void {
    $admin = User::factory()->create(['role' => 'admin']);
    $creator = User::factory()->create(['username' => 'creatorflag']);
    moderatedCard($creator, [
        'title' => 'Eligible Creator Card',
        'status' => NovaCard::STATUS_PUBLISHED,
        'moderation_status' => NovaCard::MOD_APPROVED,
        'visibility' => NovaCard::VISIBILITY_PUBLIC,
    ]);

    $this->actingAs($admin)
        ->patchJson(route('cp.cards.creators.update', ['user' => $creator->id]), [
            'nova_featured_creator' => true,
        ])
        ->assertOk()
        ->assertJsonPath('creator.username', 'creatorflag')
        ->assertJsonPath('creator.nova_featured_creator', true)
        ->assertJsonPath('creator.public_cards_count', 1);

    expect($creator->fresh()->nova_featured_creator)->toBeTrue();
});

it('allows admins to create categories and templates', function (): void {
    $admin = User::factory()->create(['role' => 'admin']);

    $this->actingAs($admin)
        ->postJson(route('cp.cards.categories.store'), [
            'slug' => 'serenity',
            'name' => 'Serenity',
            'description' => 'Peaceful cards',
            'active' => true,
            'order_num' => 3,
        ])
        ->assertOk()
        ->assertJsonPath('category.slug', 'serenity');

    $this->actingAs($admin)
        ->postJson(route('cp.cards.templates.store'), [
            'slug' => 'calm-quote',
            'name' => 'Calm Quote',
            'description' => 'Soft centered quote card',
            'supported_formats' => ['square', 'story'],
            'active' => true,
            'official' => true,
            'order_num' => 1,
            'config_json' => [
                'font_preset' => 'modern-sans',
                'gradient_preset' => 'midnight-nova',
                'layout' => 'quote_heavy',
                'text_align' => 'center',
                'text_color' => '#ffffff',
                'overlay_style' => 'dark-soft',
            ],
        ])
        ->assertOk()
        ->assertJsonPath('template.slug', 'calm-quote')
        ->assertJsonPath('template.supported_formats.1', 'story');

    expect(NovaCardCategory::query()->where('slug', 'serenity')->exists())->toBeTrue();
    expect(NovaCardTemplate::query()->where('slug', 'calm-quote')->exists())->toBeTrue();
});

it('renders the template admin page for admins', function (): void {
    $admin = User::factory()->create(['role' => 'admin']);
    adminCardTemplate(['slug' => 'editorial', 'name' => 'Editorial']);

    $this->actingAs($admin)
        ->get(route('cp.cards.templates.index'))
        ->assertOk()
        ->assertInertia(fn (AssertableInertia $page) => $page
            ->component('Collection/NovaCardsTemplateAdmin')
            ->where('templates.0.slug', 'editorial')
            ->where('endpoints.cards', route('cp.cards.index')));
});

it('renders and manages asset packs and challenges for admins', function (): void {
    $admin = User::factory()->create(['role' => 'admin']);
    $creator = User::factory()->create();
    $winner = moderatedCard($creator, [
        'slug' => 'winner-card',
        'title' => 'Winner Card',
        'moderation_status' => NovaCard::MOD_APPROVED,
    ]);

    NovaCardAssetPack::query()->create([
        'slug' => 'official-pack',
        'name' => 'Official Pack',
        'description' => 'Admin managed pack',
        'type' => 'asset',
        'manifest_json' => ['items' => [['key' => 'spark', 'label' => 'Spark', 'glyph' => '✦']]],
        'official' => true,
        'active' => true,
        'order_num' => 0,
    ]);

    NovaCardChallenge::query()->create([
        'user_id' => $admin->id,
        'slug' => 'editorial-week',
        'title' => 'Editorial Week',
        'description' => 'Admin challenge',
        'prompt' => 'Create a sharp editorial quote card.',
        'status' => NovaCardChallenge::STATUS_ACTIVE,
        'official' => true,
        'featured' => true,
        'winner_card_id' => $winner->id,
        'starts_at' => now()->subDay(),
        'ends_at' => now()->addWeek(),
    ]);

    $this->actingAs($admin)
        ->get(route('cp.cards.asset-packs.index'))
        ->assertOk()
        ->assertInertia(fn (AssertableInertia $page) => $page
            ->component('Collection/NovaCardsAssetPackAdmin')
            ->where('packs.0.slug', 'official-pack'));

    $this->actingAs($admin)
        ->get(route('cp.cards.challenges.index'))
        ->assertOk()
        ->assertInertia(fn (AssertableInertia $page) => $page
            ->component('Collection/NovaCardsChallengeAdmin')
            ->where('challenges.0.slug', 'editorial-week'));

    $this->actingAs($admin)
        ->postJson(route('cp.cards.asset-packs.store'), [
            'slug' => 'story-pack',
            'name' => 'Story Pack',
            'description' => 'Pack for stories',
            'type' => 'template',
            'manifest_json' => ['templates' => ['story-vertical']],
            'official' => true,
            'active' => true,
            'order_num' => 1,
        ])
        ->assertOk()
        ->assertJsonPath('pack.slug', 'story-pack');

    $this->actingAs($admin)
        ->postJson(route('cp.cards.challenges.store'), [
            'slug' => 'clarity-run',
            'title' => 'Clarity Run',
            'description' => 'A clean clarity challenge.',
            'prompt' => 'Use space and contrast.',
            'rules_json' => ['max_entries_per_user' => 1],
            'status' => 'active',
            'official' => true,
            'featured' => false,
            'winner_card_id' => $winner->id,
            'starts_at' => now()->toISOString(),
            'ends_at' => now()->addWeek()->toISOString(),
        ])
        ->assertOk()
        ->assertJsonPath('challenge.slug', 'clarity-run');

    expect(NovaCardAssetPack::query()->where('slug', 'story-pack')->exists())->toBeTrue();
    expect(NovaCardChallenge::query()->where('slug', 'clarity-run')->exists())->toBeTrue();
});

it('renders and manages official collections for admins', function (): void {
    $admin = User::factory()->create(['role' => 'admin']);
    $cardOwner = User::factory()->create();
    $card = moderatedCard($cardOwner, ['slug' => 'collection-managed-card', 'title' => 'Collection Managed Card', 'moderation_status' => NovaCard::MOD_APPROVED]);

    $collection = NovaCardCollection::query()->create([
        'user_id' => $admin->id,
        'slug' => 'official-launch',
        'name' => 'Official Launch',
        'description' => 'Initial official collection.',
        'visibility' => NovaCardCollection::VISIBILITY_PUBLIC,
        'official' => true,
        'featured' => false,
        'cards_count' => 0,
    ]);

    $this->actingAs($admin)
        ->get(route('cp.cards.collections.index'))
        ->assertOk()
        ->assertInertia(fn (AssertableInertia $page) => $page
            ->component('Collection/NovaCardsCollectionAdmin')
            ->where('collections.0.slug', 'official-launch'));

    $this->actingAs($admin)
        ->postJson(route('cp.cards.collections.store'), [
            'user_id' => $admin->id,
            'slug' => 'staff-picks',
            'name' => 'Staff Picks',
            'description' => 'Editorial picks.',
            'visibility' => 'public',
            'official' => true,
            'featured' => true,
        ])
        ->assertOk()
        ->assertJsonPath('collection.slug', 'staff-picks')
        ->assertJsonPath('collection.featured', true);

    $this->actingAs($admin)
        ->postJson(route('cp.cards.collections.cards.store', ['collection' => $collection->id]), [
            'card_id' => $card->id,
            'note' => 'Lead card',
        ])
        ->assertOk()
        ->assertJsonPath('collection.items.0.card.id', $card->id);

    expect(NovaCardCollectionItem::query()->where('collection_id', $collection->id)->where('card_id', $card->id)->exists())->toBeTrue();
    expect(NovaCardCollection::query()->where('slug', 'staff-picks')->value('featured'))->toBeTrue();
});
