<?php

declare(strict_types=1);

use App\Enums\ModerationContentType;
use App\Enums\ModerationDomainStatus;
use App\Enums\ModerationRuleType;
use App\Enums\ModerationStatus;
use App\Models\ContentModerationFeedback;
use App\Models\Artwork;
use App\Models\ArtworkComment;
use App\Models\ContentModerationActionLog;
use App\Models\ContentModerationCluster;
use App\Models\ContentModerationDomain;
use App\Models\ContentModerationFinding;
use App\Models\ContentModerationRule;
use App\Models\UserProfile;
use App\Models\UserSocialLink;
use App\Models\User;
use App\Services\Moderation\ContentModerationService;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Klevze\ControlPanel\Models\Admin\AdminVerification;

uses(RefreshDatabase::class);

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

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

        return $admin->fresh();
    }
}

it('loads the cpad moderation list and detail screens for admins', function (): void {
    $admin = createControlPanelAdmin();
    $artwork = Artwork::factory()->create();

    ContentModerationFinding::query()->create([
        'content_type' => ModerationContentType::ArtworkDescription->value,
        'content_id' => $artwork->id + 100,
        'artwork_id' => $artwork->id,
        'user_id' => $artwork->user_id,
        'status' => ModerationStatus::ConfirmedSpam->value,
        'severity' => 'critical',
        'score' => 120,
        'content_hash' => hash('sha256', 'spam-description-prior'),
        'scanner_version' => '2.0',
        'content_snapshot' => 'Earlier spam finding',
    ]);

    ContentModerationFinding::query()->create([
        'content_type' => ModerationContentType::ArtworkDescription->value,
        'content_id' => $artwork->id + 101,
        'artwork_id' => $artwork->id,
        'user_id' => $artwork->user_id,
        'status' => ModerationStatus::Pending->value,
        'severity' => 'medium',
        'score' => 45,
        'content_hash' => hash('sha256', 'spam-description-pending'),
        'scanner_version' => '2.0',
        'content_snapshot' => 'Pending review finding',
    ]);

    $finding = ContentModerationFinding::query()->create([
        'content_type' => ModerationContentType::ArtworkDescription->value,
        'content_id' => $artwork->id,
        'artwork_id' => $artwork->id,
        'user_id' => $artwork->user_id,
        'status' => ModerationStatus::Pending->value,
        'severity' => 'high',
        'score' => 95,
        'content_hash' => hash('sha256', 'spam-description'),
        'scanner_version' => '1.0',
        'reasons_json' => ['Contains spam keywords'],
        'matched_links_json' => ['https://promo.pornsite.com'],
        'matched_domains_json' => ['promo.pornsite.com'],
        'matched_keywords_json' => ['buy followers'],
        'content_snapshot' => 'Buy followers now',
    ]);

    $this->actingAs($admin)
        ->actingAs($admin, 'controlpanel')
        ->get(route('admin.site.content-moderation.main'))
        ->assertOk()
        ->assertSee('Content Moderation')
        ->assertSee((string) $finding->id);

    $this->actingAs($admin)
        ->actingAs($admin, 'controlpanel')
        ->get(route('admin.site.content-moderation.show', $finding))
        ->assertOk()
        ->assertSee('Buy followers now')
        ->assertSee('Contains spam keywords')
        ->assertSee('Related Findings')
        ->assertSee('Confirmed Spam')
        ->assertSee('Pending Findings');
});

it('supports sortable moderation list columns in cpad', function (): void {
    $admin = createControlPanelAdmin();
    $artwork = Artwork::factory()->create();

    ContentModerationFinding::query()->create([
        'content_type' => ModerationContentType::ArtworkDescription->value,
        'content_id' => $artwork->id,
        'artwork_id' => $artwork->id,
        'user_id' => $artwork->user_id,
        'status' => ModerationStatus::Pending->value,
        'severity' => 'critical',
        'score' => 120,
        'content_hash' => hash('sha256', 'first'),
        'scanner_version' => '1.0',
        'content_snapshot' => 'critical finding',
    ]);

    ContentModerationFinding::query()->create([
        'content_type' => ModerationContentType::ArtworkDescription->value,
        'content_id' => $artwork->id + 1,
        'artwork_id' => $artwork->id,
        'user_id' => $artwork->user_id,
        'status' => ModerationStatus::Pending->value,
        'severity' => 'medium',
        'score' => 35,
        'content_hash' => hash('sha256', 'second'),
        'scanner_version' => '1.0',
        'content_snapshot' => 'medium finding',
    ]);

    $this->actingAs($admin)
        ->actingAs($admin, 'controlpanel')
        ->get(route('admin.site.content-moderation.main', ['sort' => 'score', 'direction' => 'asc']))
        ->assertOk()
        ->assertSee('Score')
        ->assertSee('ASC');
});

it('updates finding review status from the cpad moderation actions', function (): void {
    $admin = createControlPanelAdmin();
    $artwork = Artwork::factory()->create();

    $finding = ContentModerationFinding::query()->create([
        'content_type' => ModerationContentType::ArtworkDescription->value,
        'content_id' => $artwork->id,
        'artwork_id' => $artwork->id,
        'user_id' => $artwork->user_id,
        'status' => ModerationStatus::Pending->value,
        'severity' => 'high',
        'score' => 95,
        'content_hash' => hash('sha256', 'spam-description'),
        'scanner_version' => '1.0',
        'content_snapshot' => 'Buy followers now',
    ]);

    $this->actingAs($admin)
        ->actingAs($admin, 'controlpanel')
        ->post(route('admin.site.content-moderation.safe', $finding), ['admin_notes' => 'false positive'])
        ->assertRedirect();

    $finding->refresh();

    expect($finding->status)->toBe(ModerationStatus::ReviewedSafe)
        ->and($finding->admin_notes)->toBe('false positive')
        ->and($finding->reviewed_by)->toBe($admin->id);
});

it('can hide flagged artwork comments from the cpad moderation screen', function (): void {
    $admin = createControlPanelAdmin();
    $artwork = Artwork::factory()->create();
    $comment = ArtworkComment::factory()->create([
        'artwork_id' => $artwork->id,
        'user_id' => $artwork->user_id,
    ]);

    $finding = ContentModerationFinding::query()->create([
        'content_type' => ModerationContentType::ArtworkComment->value,
        'content_id' => $comment->id,
        'artwork_id' => $artwork->id,
        'user_id' => $comment->user_id,
        'status' => ModerationStatus::Pending->value,
        'severity' => 'critical',
        'score' => 120,
        'content_hash' => hash('sha256', 'spam-comment'),
        'scanner_version' => '1.0',
        'content_snapshot' => $comment->raw_content,
    ]);

    $this->actingAs($admin)
        ->actingAs($admin, 'controlpanel')
        ->post(route('admin.site.content-moderation.hide', $finding), ['admin_notes' => 'hidden by moderation'])
        ->assertRedirect();

    expect($comment->fresh()->is_approved)->toBeFalse()
        ->and($finding->fresh()->status)->toBe(ModerationStatus::ConfirmedSpam)
        ->and($finding->fresh()->action_taken)->toBe('hide_comment');
});

it('loads the v2 moderation dashboard, domains, rules, and actions pages', function (): void {
    $admin = createControlPanelAdmin();

    $domain = ContentModerationDomain::query()->create([
        'domain' => 'promo.pornsite.com',
        'status' => ModerationDomainStatus::Blocked,
        'times_seen' => 3,
        'times_flagged' => 2,
        'times_confirmed_spam' => 1,
    ]);

    $rule = ContentModerationRule::query()->create([
        'type' => ModerationRuleType::SuspiciousKeyword,
        'value' => 'rare promo blast',
        'enabled' => true,
        'weight' => 20,
        'created_by' => $admin->id,
    ]);

    $finding = ContentModerationFinding::query()->create([
        'content_type' => ModerationContentType::ArtworkComment->value,
        'content_id' => 99,
        'status' => ModerationStatus::Pending->value,
        'severity' => 'high',
        'score' => 95,
        'content_hash' => hash('sha256', 'finding'),
        'scanner_version' => '2.0',
        'content_snapshot' => 'spam snapshot',
    ]);

    ContentModerationActionLog::query()->create([
        'finding_id' => $finding->id,
        'target_type' => 'finding',
        'target_id' => $finding->id,
        'action_type' => 'rescan',
        'actor_type' => 'admin',
        'actor_id' => $admin->id,
        'created_at' => now(),
    ]);

    $this->actingAs($admin)->actingAs($admin, 'controlpanel')
        ->get(route('admin.site.content-moderation.dashboard'))
        ->assertOk()
        ->assertSee('Content Moderation Dashboard')
        ->assertSee('Top Flagged Domains');

    $this->actingAs($admin)->actingAs($admin, 'controlpanel')
        ->get(route('admin.site.content-moderation.domains'))
        ->assertOk()
        ->assertSee($domain->domain);

    $this->actingAs($admin)->actingAs($admin, 'controlpanel')
        ->get(route('admin.site.content-moderation.rules'))
        ->assertOk()
        ->assertSee($rule->value);

    $this->actingAs($admin)->actingAs($admin, 'controlpanel')
        ->get(route('admin.site.content-moderation.actions'))
        ->assertOk()
        ->assertSee('rescan');
});

it('supports proactive domain creation and domain detail inspection from cpad', function (): void {
    $admin = createControlPanelAdmin();
    $artwork = Artwork::factory()->create();

    $response = $this->actingAs($admin)
        ->actingAs($admin, 'controlpanel')
        ->post(route('admin.site.content-moderation.domains.store'), [
            'domain' => 'promo.example.com',
            'status' => ModerationDomainStatus::Blocked->value,
            'notes' => 'Manual blocklist entry',
        ]);

    $domain = ContentModerationDomain::query()->where('domain', 'promo.example.com')->firstOrFail();

    ContentModerationFinding::query()->create([
        'content_type' => ModerationContentType::ArtworkDescription->value,
        'content_id' => $artwork->id,
        'artwork_id' => $artwork->id,
        'user_id' => $artwork->user_id,
        'status' => ModerationStatus::Pending->value,
        'severity' => 'high',
        'score' => 95,
        'content_hash' => hash('sha256', 'domain-linked-finding'),
        'scanner_version' => '2.0',
        'matched_domains_json' => ['promo.example.com'],
        'content_snapshot' => 'Linked to promo domain',
    ]);

    $response->assertRedirect(route('admin.site.content-moderation.domains.show', $domain));

    $this->actingAs($admin)
        ->actingAs($admin, 'controlpanel')
        ->get(route('admin.site.content-moderation.domains.show', $domain))
        ->assertOk()
        ->assertSee('promo.example.com')
        ->assertSee('Linked Findings')
        ->assertSee('Manual blocklist entry');
});

it('applies admin managed domains to moderation analysis', function (): void {
    $admin = createControlPanelAdmin();

    $this->actingAs($admin)
        ->actingAs($admin, 'controlpanel')
        ->post(route('admin.site.content-moderation.domains.store'), [
            'domain' => 'promo.example.com',
            'status' => ModerationDomainStatus::Blocked->value,
        ])
        ->assertRedirect();

    $result = app(ContentModerationService::class)->analyze('Visit https://promo.example.com/deal right now.', [
        'user_id' => $admin->id,
    ]);

    expect($result->matchedDomains)->toContain('promo.example.com')
        ->and($result->ruleHits)->toHaveKey('blocked_domain')
        ->and($result->status)->toBe(ModerationStatus::Pending);
});

it('applies admin managed rules to moderation analysis', function (): void {
    $admin = createControlPanelAdmin();

    $this->actingAs($admin)
        ->actingAs($admin, 'controlpanel')
        ->post(route('admin.site.content-moderation.rules.store'), [
            'type' => ModerationRuleType::SuspiciousKeyword->value,
            'value' => 'rare promo blast',
            'enabled' => '1',
            'weight' => 20,
        ])
        ->assertRedirect();

    $result = app(ContentModerationService::class)->analyze('This rare promo blast just dropped.');

    expect($result->matchedKeywords)->toContain('rare promo blast')
        ->and($result->ruleHits)->toHaveKey('suspicious_keyword')
        ->and($result->score)->toBeGreaterThan(0)
        ->and($result->reasons)->toContain('Contains suspicious keyword(s): rare promo blast');
});

it('reports partial bulk action failures explicitly', function (): void {
    $admin = createControlPanelAdmin();
    $artwork = Artwork::factory()->create();

    $domainFinding = ContentModerationFinding::query()->create([
        'content_type' => ModerationContentType::ArtworkDescription->value,
        'content_id' => $artwork->id,
        'artwork_id' => $artwork->id,
        'user_id' => $artwork->user_id,
        'status' => ModerationStatus::Pending->value,
        'severity' => 'high',
        'score' => 80,
        'content_hash' => hash('sha256', 'bulk-domain-finding'),
        'scanner_version' => '2.0',
        'matched_domains_json' => ['promo.bulk-test.com'],
        'content_snapshot' => 'Has a domain',
    ]);

    $noDomainFinding = ContentModerationFinding::query()->create([
        'content_type' => ModerationContentType::ArtworkDescription->value,
        'content_id' => $artwork->id + 1,
        'artwork_id' => $artwork->id,
        'user_id' => $artwork->user_id,
        'status' => ModerationStatus::Pending->value,
        'severity' => 'medium',
        'score' => 40,
        'content_hash' => hash('sha256', 'bulk-no-domain-finding'),
        'scanner_version' => '2.0',
        'matched_domains_json' => [],
        'content_snapshot' => 'No domain here',
    ]);

    $this->actingAs($admin)
        ->actingAs($admin, 'controlpanel')
        ->post(route('admin.site.content-moderation.bulk'), [
            'action' => 'block_domains',
            'finding_ids' => [$domainFinding->id, $noDomainFinding->id],
        ])
        ->assertRedirect(route('admin.site.content-moderation.main'))
        ->assertSessionHas('msg_success', 'Processed 1 moderation item(s).')
        ->assertSessionHas('msg_warning');

    expect(ContentModerationDomain::query()->where('domain', 'promo.bulk-test.com')->where('status', ModerationDomainStatus::Blocked->value)->exists())->toBeTrue()
        ->and(ContentModerationActionLog::query()->where('target_type', 'domain')->where('target_id', ContentModerationDomain::query()->where('domain', 'promo.bulk-test.com')->value('id'))->exists())->toBeTrue();
});

it('restores auto hidden comments from the cpad moderation screen', function (): void {
    $admin = createControlPanelAdmin();
    $artwork = Artwork::factory()->create();
    $comment = ArtworkComment::factory()->create([
        'artwork_id' => $artwork->id,
        'user_id' => $artwork->user_id,
        'is_approved' => false,
    ]);

    $finding = ContentModerationFinding::query()->create([
        'content_type' => ModerationContentType::ArtworkComment->value,
        'content_id' => $comment->id,
        'artwork_id' => $artwork->id,
        'user_id' => $comment->user_id,
        'status' => ModerationStatus::Pending->value,
        'severity' => 'critical',
        'score' => 120,
        'content_hash' => hash('sha256', 'spam-comment-restored'),
        'scanner_version' => '2.0',
        'content_snapshot' => $comment->raw_content,
        'is_auto_hidden' => true,
        'auto_action_taken' => 'auto_hide_comment',
        'auto_hidden_at' => now(),
    ]);

    $this->actingAs($admin)
        ->actingAs($admin, 'controlpanel')
        ->post(route('admin.site.content-moderation.restore', $finding), ['admin_notes' => 'restored after review'])
        ->assertRedirect();

    expect($comment->fresh()->is_approved)->toBeTrue()
        ->and($finding->fresh()->is_auto_hidden)->toBeFalse()
        ->and($finding->fresh()->restored_by)->toBe($admin->id);
});

it('loads the v3 moderation queue, cluster, user, policy, and feedback screens', function (): void {
    $admin = createControlPanelAdmin();
    $flaggedUser = User::factory()->create();
    $artwork = Artwork::factory()->create(['user_id' => $flaggedUser->id]);

    UserProfile::query()->create([
        'user_id' => $flaggedUser->id,
        'about' => 'Profile with promotional links',
    ]);

    UserSocialLink::query()->create([
        'user_id' => $flaggedUser->id,
        'platform' => 'website',
        'url' => 'https://promo.cluster-test.com',
    ]);

    $finding = ContentModerationFinding::query()->create([
        'content_type' => ModerationContentType::UserProfileLink->value,
        'content_id' => UserSocialLink::query()->where('user_id', $flaggedUser->id)->value('id'),
        'content_target_type' => UserSocialLink::class,
        'content_target_id' => UserSocialLink::query()->where('user_id', $flaggedUser->id)->value('id'),
        'artwork_id' => $artwork->id,
        'user_id' => $flaggedUser->id,
        'status' => ModerationStatus::Pending->value,
        'severity' => 'critical',
        'score' => 140,
        'priority_score' => 99,
        'review_bucket' => 'urgent',
        'policy_name' => 'strict_seo_protection',
        'campaign_key' => 'campaign:test-cluster',
        'cluster_reason' => 'Shared promotional domain and keywords',
        'cluster_score' => 88,
        'content_hash' => hash('sha256', 'cluster-finding'),
        'scanner_version' => '3.0',
        'matched_domains_json' => ['promo.cluster-test.com'],
        'matched_keywords_json' => ['promo blast'],
        'content_snapshot' => 'Visit https://promo.cluster-test.com for promo blast offers',
        'ai_label' => 'spam',
        'ai_suggested_action' => 'review',
        'ai_confidence' => 91,
        'ai_provider' => 'heuristic',
    ]);

    ContentModerationCluster::query()->create([
        'campaign_key' => 'campaign:test-cluster',
        'cluster_reason' => 'Shared promotional domain and keywords',
        'cluster_score' => 88,
    ]);

    ContentModerationFeedback::query()->create([
        'finding_id' => $finding->id,
        'actor_id' => $admin->id,
        'feedback_type' => 'reviewed_safe',
        'notes' => 'Operator reviewed queue behaviour',
    ]);

    $this->actingAs($admin)->actingAs($admin, 'controlpanel')
        ->get(route('admin.site.content-moderation.priority'))
        ->assertOk()
        ->assertSee('Priority Findings')
        ->assertSee((string) $finding->id);

    $this->actingAs($admin)->actingAs($admin, 'controlpanel')
        ->get(route('admin.site.content-moderation.clusters'))
        ->assertOk()
        ->assertSee('Campaign Clusters')
        ->assertSee('campaign:test-cluster');

    $this->actingAs($admin)->actingAs($admin, 'controlpanel')
        ->get(route('admin.site.content-moderation.clusters.show', ['campaignKey' => 'campaign:test-cluster']))
        ->assertOk()
        ->assertSee('Cluster Findings')
        ->assertSee('Shared promotional domain and keywords');

    $this->actingAs($admin)->actingAs($admin, 'controlpanel')
        ->get(route('admin.site.content-moderation.users'))
        ->assertOk()
        ->assertSee('User Moderation Profiles')
        ->assertSee($flaggedUser->username ?? $flaggedUser->name);

    $this->actingAs($admin)->actingAs($admin, 'controlpanel')
        ->get(route('admin.site.content-moderation.users.show', ['user' => $flaggedUser->id]))
        ->assertOk()
        ->assertSee('Profile Summary')
        ->assertSee($flaggedUser->username ?? $flaggedUser->name);

    $this->actingAs($admin)->actingAs($admin, 'controlpanel')
        ->get(route('admin.site.content-moderation.policies'))
        ->assertOk()
        ->assertSee('Moderation Policies')
        ->assertSee('strict_seo_protection');

    $this->actingAs($admin)->actingAs($admin, 'controlpanel')
        ->get(route('admin.site.content-moderation.feedback'))
        ->assertOk()
        ->assertSee('Reviewer Feedback')
        ->assertSee('Operator reviewed queue behaviour');
});

it('marks findings as false positives from the cpad moderation screen', function (): void {
    $admin = createControlPanelAdmin();
    $artwork = Artwork::factory()->create();

    $finding = ContentModerationFinding::query()->create([
        'content_type' => ModerationContentType::ArtworkTitle->value,
        'content_id' => $artwork->id,
        'content_target_type' => Artwork::class,
        'content_target_id' => $artwork->id,
        'artwork_id' => $artwork->id,
        'user_id' => $artwork->user_id,
        'status' => ModerationStatus::Pending->value,
        'severity' => 'high',
        'score' => 85,
        'priority_score' => 80,
        'content_hash' => hash('sha256', 'artwork-title-false-positive'),
        'scanner_version' => '3.0',
        'content_snapshot' => 'Totally legitimate artwork title',
    ]);

    $this->actingAs($admin)
        ->actingAs($admin, 'controlpanel')
        ->post(route('admin.site.content-moderation.false-positive', $finding), ['admin_notes' => 'Safe brand reference'])
        ->assertRedirect(route('admin.site.content-moderation.show', $finding));

    $finding->refresh();

    expect($finding->is_false_positive)->toBeTrue()
        ->and($finding->false_positive_count)->toBeGreaterThanOrEqual(1)
        ->and($finding->admin_notes)->toBe('Safe brand reference')
        ->and(ContentModerationFeedback::query()->where('finding_id', $finding->id)->where('feedback_type', 'false_positive')->exists())->toBeTrue();
});