<?php
declare(strict_types=1);

namespace App\Services\Security;

class ContentModerator
{
    private const CATEGORY_RULES = [
        'profanity' => [
            'severity' => 35,
            'terms' => ['badword', 'curseword', 'kufur'],
        ],
        'insult' => [
            'severity' => 35,
            'terms' => ['hakaret', 'aptal', 'salak'],
        ],
        'illegal_content' => [
            'severity' => 70,
            'terms' => ['illegaldownload', 'warez', 'pirated', 'crack', 'keygen'],
        ],
        'adult_content' => [
            'severity' => 65,
            'terms' => ['adultcontent', 'nsfw', 'xxx'],
        ],
        'gambling' => [
            'severity' => 50,
            'terms' => ['gambling', 'casino', 'betting'],
        ],
        'crypto_scam' => [
            'severity' => 60,
            'terms' => ['scamcoin', 'freecrypto', 'airdrop', 'seedphrase', 'walletseed'],
        ],
        'malware' => [
            'severity' => 75,
            'terms' => ['malware', 'phishing', 'trojan', 'keylogger', 'virus'],
        ],
        'spam' => [
            'severity' => 35,
            'terms' => ['spamlink', 'clickherenow', 'freefollowers'],
        ],
        'hate_speech' => [
            'severity' => 70,
            'terms' => ['hategroup', 'racistcontent', 'nefretsoylemi'],
        ],
        'violence_threat' => [
            'severity' => 70,
            'terms' => ['violentthreat', 'deaththreat', 'tehdit'],
        ],
    ];

    public function __construct(private ForbiddenWordChecker $wordChecker)
    {
    }

    public function scan(string $content): array
    {
        $content = trim($content);

        if ($content === '') {
            return $this->format(0, ['empty_content']);
        }

        $riskScore = 0;
        $reasons = [];

        $wordResult = $this->wordChecker->scan($content);
        if (($wordResult['matches'] ?? []) !== []) {
            $riskScore = max($riskScore, (int) ($wordResult['risk_score'] ?? 0));
            $reasons[] = 'admin_forbidden_words';
        }

        $normalized = $this->normalizeText($content);
        foreach (self::CATEGORY_RULES as $reason => $rule) {
            foreach ($rule['terms'] as $term) {
                if (str_contains($normalized, $this->normalizeText($term))) {
                    $riskScore += (int) $rule['severity'];
                    $reasons[] = $reason;
                    break;
                }
            }
        }

        if (substr_count(strtolower($content), 'http://') + substr_count(strtolower($content), 'https://') >= 3) {
            $riskScore += 35;
            $reasons[] = 'too_many_links';
        }

        if (preg_match('/(.)\1{8,}/', $content) === 1) {
            $riskScore += 20;
            $reasons[] = 'repeated_characters';
        }

        if (strlen($content) > 0 && strlen($content) <= 240) {
            $letters = preg_replace('/[^a-zA-Z]/', '', $content) ?: '';
            $upper = preg_replace('/[^A-Z]/', '', $letters) ?: '';

            if (strlen($letters) >= 20 && strlen($upper) / max(strlen($letters), 1) > 0.7) {
                $riskScore += 15;
                $reasons[] = 'excessive_uppercase';
            }
        }

        return $this->format($riskScore, $reasons ?: ['clean_content']);
    }

    public function scanText(string $text): array
    {
        return $this->scan($text);
    }

    private function format(int $riskScore, array $reasons): array
    {
        $riskScore = min(100, max(0, $riskScore));
        $status = $riskScore >= 61 ? 'blocked' : ($riskScore >= 31 ? 'review' : 'safe');

        return [
            'risk_score' => $riskScore,
            'status' => $status,
            'action_taken' => match ($status) {
                'blocked' => 'blocked',
                'review' => 'pending_review',
                default => 'allow',
            },
            'reasons' => array_values(array_unique($reasons)),
        ];
    }

    private function normalizeText(string $value): string
    {
        $value = function_exists('mb_strtolower') ? mb_strtolower($value) : strtolower($value);

        return preg_replace('/[^a-z0-9]+/u', '', $value) ?: '';
    }
}
