<?php
declare(strict_types=1);

namespace App\Services\Security;

use App\Core\Database;
use Throwable;

class ForbiddenWordChecker
{
    private const DEFAULT_WORDS = [
        ['word' => 'spamlink', 'severity' => 35],
        ['word' => 'scamcoin', 'severity' => 60],
        ['word' => 'malware', 'severity' => 75],
        ['word' => 'phishing', 'severity' => 75],
        ['word' => 'illegaldownload', 'severity' => 70],
        ['word' => 'adultcontent', 'severity' => 65],
        ['word' => 'gambling', 'severity' => 50],
    ];

    private ?array $loadedWords = null;

    public function __construct(private array $words = [])
    {
    }

    public function scan(string $content): array
    {
        $matches = [];
        $riskScore = 0;
        $normalized = $this->normalize($content);

        foreach ($this->loadWords() as $item) {
            $word = $this->normalize((string) ($item['word'] ?? ''));

            if ($word !== '' && str_contains($normalized, $word)) {
                $matches[] = $word;
                $riskScore = max($riskScore, min(100, max(0, (int) ($item['severity'] ?? 60))));
            }
        }

        $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',
            },
            'matches' => array_values(array_unique($matches)),
            'reasons' => $matches === [] ? [] : ['forbidden_words'],
        ];
    }

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

    public function loadWords(): array
    {
        if ($this->loadedWords !== null) {
            return $this->loadedWords;
        }

        $words = self::DEFAULT_WORDS;

        foreach ($this->words as $word) {
            if (is_array($word)) {
                $words[] = [
                    'word' => (string) ($word['word'] ?? ''),
                    'severity' => (int) ($word['severity'] ?? 60),
                ];
                continue;
            }

            $words[] = ['word' => (string) $word, 'severity' => 60];
        }

        try {
            $statement = Database::connection()->query('SELECT word, severity FROM forbidden_words ORDER BY severity DESC, word ASC');
            foreach ($statement->fetchAll() as $row) {
                $words[] = [
                    'word' => (string) ($row['word'] ?? ''),
                    'severity' => (int) ($row['severity'] ?? 60),
                ];
            }
        } catch (Throwable) {
        }

        $unique = [];
        foreach ($words as $word) {
            $key = $this->normalize((string) ($word['word'] ?? ''));
            if ($key === '') {
                continue;
            }

            $unique[$key] = [
                'word' => (string) ($word['word'] ?? ''),
                'severity' => min(100, max(0, (int) ($word['severity'] ?? 60))),
            ];
        }

        return $this->loadedWords = array_values($unique);
    }

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

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