<?php

declare(strict_types=1);

use App\Enums\ModerationDomainStatus;
use App\Enums\ModerationRuleType;
use App\Enums\ModerationContentType;
use App\Enums\ModerationSeverity;
use App\Enums\ModerationStatus;
use App\Models\ContentModerationDomain;
use App\Models\ContentModerationFinding;
use App\Models\ContentModerationRule;
use App\Models\User;
use App\Services\Moderation\ContentModerationService;
use App\Services\Moderation\ContentModerationSourceService;
use App\Services\Moderation\Rules\LinkPresenceRule;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;

uses(TestCase::class, RefreshDatabase::class);

it('extracts explicit and www urls from content', function (): void {
    $rule = app(LinkPresenceRule::class);

    $urls = $rule->extractUrls('Visit https://spam.example.com and www.short.test/offer now.');

    expect($urls)->toContain('https://spam.example.com')
        ->and($urls)->toContain('www.short.test/offer');
});

it('detects suspicious keywords and domains with a queued status', function (): void {
    $result = app(ContentModerationService::class)->analyze(
        'Buy followers today at https://promo.pornsite.com right now',
        ['content_type' => 'artwork_comment', 'content_id' => 1]
    );

    expect($result->score)->toBeGreaterThanOrEqual(110)
        ->and(in_array($result->severity, [ModerationSeverity::High, ModerationSeverity::Critical], true))->toBeTrue()
        ->and($result->matchedDomains)->toContain('promo.pornsite.com')
        ->and($result->matchedKeywords)->toContain('buy followers');
});

it('detects unicode obfuscation patterns', function (): void {
    $result = app(ContentModerationService::class)->analyze(
        'раypal giveaway click here',
        ['content_type' => 'artwork_comment', 'content_id' => 1]
    );

    expect($result->score)->toBeGreaterThan(0)
        ->and(collect($result->reasons)->implode(' '))->toContain('Unicode');
});

it('produces stable hashes for semantically identical whitespace variants', function (): void {
    $service = app(ContentModerationService::class);

    $first = $service->analyze("Visit my site\n\nnow", ['content_type' => 'artwork_comment', 'content_id' => 1]);
    $second = $service->analyze('  visit   my site now  ', ['content_type' => 'artwork_comment', 'content_id' => 2]);

    expect($first->contentHash)->toBe($second->contentHash);
});

it('detects keyword stuffing patterns', function (): void {
    $result = app(ContentModerationService::class)->analyze(
        'seo seo seo seo seo seo seo seo seo seo seo seo seo service service service service service cheap cheap cheap traffic traffic traffic',
        ['content_type' => 'artwork_description', 'content_id' => 1]
    );

    expect($result->score)->toBeGreaterThan(0)
        ->and($result->matchedKeywords)->toContain('seo');
});

it('maps score thresholds to the expected severities', function (): void {
    expect(ModerationSeverity::fromScore(0))->toBe(ModerationSeverity::Low)
        ->and(ModerationSeverity::fromScore(30))->toBe(ModerationSeverity::Medium)
        ->and(ModerationSeverity::fromScore(60))->toBe(ModerationSeverity::High)
        ->and(ModerationSeverity::fromScore(90))->toBe(ModerationSeverity::Critical);
});

it('applies db managed moderation rules alongside config rules', function (): void {
    ContentModerationRule::query()->create([
        'type' => ModerationRuleType::SuspiciousKeyword,
        'value' => 'rare promo blast',
        'enabled' => true,
        'weight' => 22,
    ]);

    $result = app(ContentModerationService::class)->analyze(
        'This rare promo blast just dropped.',
        ['content_type' => 'artwork_comment', 'content_id' => 1]
    );

    expect($result->matchedKeywords)->toContain('rare promo blast')
        ->and($result->score)->toBeGreaterThan(0);
});

it('uses domain reputation to escalate blocked domains and auto hide recommendations', function (): void {
    ContentModerationDomain::query()->create([
        'domain' => 'campaign.spam.test',
        'status' => ModerationDomainStatus::Blocked,
    ]);

    $result = app(ContentModerationService::class)->analyze(
        'Buy followers now at https://campaign.spam.test and claim your giveaway',
        ['content_type' => 'artwork_comment', 'content_id' => 1]
    );

    expect($result->matchedDomains)->toContain('campaign.spam.test')
        ->and($result->autoHideRecommended)->toBeTrue()
        ->and($result->score)->toBeGreaterThanOrEqual(95);
});

it('applies user risk modifiers conservatively', function (): void {
    $user = User::factory()->create();

    ContentModerationFinding::query()->create([
        'content_type' => 'artwork_comment',
        'content_id' => 11,
        'user_id' => $user->id,
        'status' => ModerationStatus::ConfirmedSpam->value,
        'severity' => 'high',
        'score' => 85,
        'content_hash' => hash('sha256', 'a'),
        'scanner_version' => '2.0',
        'content_snapshot' => 'spam one',
    ]);

    ContentModerationFinding::query()->create([
        'content_type' => 'artwork_comment',
        'content_id' => 12,
        'user_id' => $user->id,
        'status' => ModerationStatus::ConfirmedSpam->value,
        'severity' => 'critical',
        'score' => 120,
        'content_hash' => hash('sha256', 'b'),
        'scanner_version' => '2.0',
        'content_snapshot' => 'spam two',
    ]);

    $base = app(ContentModerationService::class)->analyze(
        'Visit https://safe.example.test for more info',
        ['content_type' => 'artwork_comment', 'content_id' => 1]
    );

    $risky = app(ContentModerationService::class)->analyze(
        'Visit https://safe.example.test for more info',
        ['content_type' => 'artwork_comment', 'content_id' => 2, 'user_id' => $user->id]
    );

    expect($risky->score)->toBeGreaterThan($base->score)
        ->and($risky->userRiskScore)->toBeGreaterThan(0)
        ->and($risky->ruleHits)->toHaveKey('user_risk_modifier');
});

it('applies strict seo policy and v3 assistive fields for link-heavy profile content', function (): void {
    $result = app(ContentModerationService::class)->analyze(
        'Visit https://promo.cluster-test.com now for a limited time offer and boost your traffic',
        [
            'content_type' => ModerationContentType::UserProfileLink->value,
            'content_id' => 77,
            'content_target_type' => 'user_social_link',
            'content_target_id' => 77,
            'is_publicly_exposed' => true,
        ]
    );

    expect($result->policyName)->toBe('strict_seo_protection')
        ->and($result->status)->toBe(ModerationStatus::Pending)
        ->and($result->priorityScore)->toBeGreaterThan($result->score)
        ->and(in_array($result->reviewBucket, ['urgent', 'high'], true))->toBeTrue()
        ->and($result->aiProvider)->toBe('heuristic_assist')
        ->and($result->aiLabel)->not->toBeNull()
        ->and($result->contentTargetType)->toBe('user_social_link')
        ->and($result->contentTargetId)->toBe(77)
        ->and($result->scoreBreakdown)->not->toBeEmpty();
});

it('builds v3 moderation source context for profile links and card text', function (): void {
    $service = app(ContentModerationSourceService::class);

    $profileLinkContext = $service->buildContext(ModerationContentType::UserProfileLink, (object) [
        'id' => 14,
        'user_id' => 5,
        'url' => 'https://promo.example.test',
    ]);

    $cardTextContext = $service->buildContext(ModerationContentType::CardText, (object) [
        'id' => 9,
        'user_id' => 3,
        'quote_text' => 'Promo headline',
        'description' => 'Additional landing page copy',
        'quote_author' => 'Campaign Bot',
        'quote_source' => 'promo.example.test',
        'visibility' => 'public',
    ]);

    expect($profileLinkContext['content_type'])->toBe(ModerationContentType::UserProfileLink->value)
        ->and($profileLinkContext['content_target_type'])->toBe('user_social_link')
        ->and($profileLinkContext['content_target_id'])->toBe(14)
        ->and($profileLinkContext['user_id'])->toBe(5)
        ->and($profileLinkContext['is_publicly_exposed'])->toBeTrue()
        ->and($cardTextContext['content_type'])->toBe(ModerationContentType::CardText->value)
        ->and($cardTextContext['content_target_type'])->toBe('nova_card')
        ->and($cardTextContext['content_target_id'])->toBe(9)
        ->and($cardTextContext['user_id'])->toBe(3)
        ->and($cardTextContext['is_publicly_exposed'])->toBeTrue()
        ->and($cardTextContext['content_snapshot'])->toContain('Promo headline')
        ->and($cardTextContext['content_snapshot'])->toContain('promo.example.test');
});