# retoor <retoor@molodetz.nl>

from __future__ import annotations

import re
from dataclasses import dataclass


FILTER_MODES: tuple[str, ...] = ("off", "label", "review", "block")

ALWAYS_BLOCK_CATEGORIES: frozenset[str] = frozenset({"sexual", "exploitative"})

MATURE_CATEGORIES: frozenset[str] = frozenset({"sexual", "violence", "self_harm"})

DEFAULT_REVIEW_SCORE = 2
DEFAULT_BLOCK_SCORE = 6


@dataclass(frozen=True)
class Rule:
    category: str
    weight: int
    pattern: re.Pattern[str]


def _rule(category: str, weight: int, expression: str) -> Rule:
    return Rule(
        category=category,
        weight=weight,
        pattern=re.compile(expression, re.IGNORECASE),
    )


RULES: tuple[Rule, ...] = (
    _rule(
        "hate",
        6,
        r"\b(?:gas|exterminate|eradicate|purge)\s+(?:the\s+)?"
        r"(?:jews|muslims|blacks|whites|asians|gays|trans(?:\s?people)?|immigrants)\b",
    ),
    _rule(
        "hate",
        4,
        r"\b(?:all|every)\s+(?:jews|muslims|blacks|whites|asians|gays|trans(?:\s?people)?|"
        r"immigrants|women|men)\s+(?:are|should\s+be)\s+"
        r"(?:subhuman|vermin|animals|scum|killed|deported|removed)\b",
    ),
    _rule("hate", 5, r"\b(?:white|racial)\s+(?:power|supremacy)\b.{0,40}\b(?:rise|fight|war)\b"),
    _rule(
        "violence",
        6,
        r"\b(?:i\s+(?:will|am\s+going\s+to|wanna|want\s+to)|we\s+will)\s+"
        r"(?:kill|murder|shoot|stab|behead|burn)\s+(?:you|him|her|them|u)\b",
    ),
    _rule("violence", 5, r"\b(?:i\s+know\s+where\s+you\s+live|watch\s+your\s+back,?\s+(?:you|i))\b"),
    _rule("violence", 4, r"\b(?:death|bomb)\s+threat\s+(?:to|against)\s+\w+"),
    _rule(
        "weapons",
        5,
        r"\b(?:how\s+to\s+)?(?:build|make|assemble|construct)\s+(?:a\s+|an\s+)?"
        r"(?:pipe\s?bomb|nail\s?bomb|ied|pressure\s?cooker\s+bomb|nerve\s+agent|"
        r"sarin|ricin|dirty\s+bomb)\b",
    ),
    _rule(
        "weapons",
        4,
        r"\b(?:untraceable|ghost)\s+(?:gun|firearm)\b.{0,40}\b(?:build|print|make|assemble)\b",
    ),
    _rule(
        "sexual",
        8,
        r"\b(?:child|minor|underage|preteen|loli|shota)\s?(?:porn|pornography|sex|nudes|cp)\b",
    ),
    _rule("sexual", 5, r"\b(?:hardcore|explicit)\s+(?:porn|pornography|xxx)\b"),
    _rule("sexual", 4, r"\b(?:nudes|sexting|camgirl|onlyfans)\b.{0,30}\b(?:dm|send|link|free)\b"),
    _rule(
        "exploitative",
        8,
        r"\b(?:sell|buy|trade|traffic(?:king)?)\s+(?:a\s+)?"
        r"(?:child|children|minor|minors|girl|girls|boy|boys)\b",
    ),
    _rule(
        "religious",
        4,
        r"\b(?:all|every)\s+(?:christians|muslims|jews|hindus|buddhists|atheists)\s+"
        r"(?:are|should\s+be)\s+(?:killed|removed|banned|scum|vermin)\b",
    ),
    _rule(
        "misinformation",
        3,
        r"\b(?:vaccines?\s+(?:cause|causes)\s+autism|drink(?:ing)?\s+bleach\s+"
        r"(?:cures|to\s+cure)|the\s+election\s+was\s+stolen\s+and)\b",
    ),
    _rule(
        "harassment",
        4,
        r"\b(?:kill\s+your\s?self|kys|neck\s+your\s?self)\b",
    ),
    _rule(
        "harassment",
        3,
        r"\b(?:you\s+(?:are|'re|r)\s+(?:a\s+)?(?:worthless|pathetic|disgusting)\s+"
        r"(?:piece\s+of\s+\w+|human|waste))\b",
    ),
    _rule(
        "harassment",
        4,
        r"\b(?:here\s+is|posting)\s+(?:his|her|their|your)\s+"
        r"(?:home\s+address|real\s+name\s+and\s+address|phone\s+number\s+and\s+address)\b",
    ),
    _rule(
        "self_harm",
        5,
        r"\b(?:best|painless|easiest)\s+way\s+to\s+(?:kill\s+myself|end\s+my\s+life|"
        r"commit\s+suicide)\b",
    ),
    _rule(
        "self_harm",
        4,
        r"\b(?:you\s+should\s+)?(?:go\s+)?(?:kill\s+yourself|end\s+your\s+life)\b",
    ),
    _rule(
        "spam",
        3,
        r"\b(?:buy\s+now|100%\s+free\s+money|work\s+from\s+home\s+\$\d+|"
        r"click\s+here\s+to\s+claim|crypto\s+giveaway)\b",
    ),
    _rule(
        "illegal",
        5,
        r"\b(?:selling|buying|for\s+sale)\s+(?:stolen\s+)?"
        r"(?:credit\s?cards?|cc\s+dumps|fullz|ssn\s+list|bank\s+logs)\b",
    ),
    _rule(
        "illegal",
        4,
        r"\b(?:hire|hiring)\s+(?:a\s+)?hit\s?man\b",
    ),
    _rule(
        "intellectual_property",
        2,
        r"\b(?:full\s+)?(?:cracked|nulled|warez)\s+(?:copy|version|download)\b",
    ),
)


TECHNICAL_CONTEXT = re.compile(
    r"\b(?:cve-\d{4}-\d+|exploit|payload|vulnerabilit(?:y|ies)|proof\s+of\s+concept|"
    r"reverse\s+engineer(?:ing)?|malware\s+analysis|penetration\s+test(?:ing)?|"
    r"red\s+team|sandbox|disassembl(?:y|er)|fuzz(?:ing|er)|stack\s+trace|traceback|"
    r"segmentation\s+fault|kernel\s+panic)\b",
    re.IGNORECASE,
)

TECHNICAL_DISCOUNT_CATEGORIES: frozenset[str] = frozenset(
    {"weapons", "violence", "illegal"}
)

TECHNICAL_DISCOUNT = 3


def matches(text: str) -> list[Rule]:
    if not text:
        return []
    return [rule for rule in RULES if rule.pattern.search(text)]


def score_for(text: str, matched: list[Rule]) -> int:
    if not matched:
        return 0
    technical = bool(TECHNICAL_CONTEXT.search(text))
    total = 0
    for rule in matched:
        weight = rule.weight
        if technical and rule.category in TECHNICAL_DISCOUNT_CATEGORIES:
            weight = max(0, weight - TECHNICAL_DISCOUNT)
        total += weight
    return total
