# retoor <retoor@molodetz.nl>

from __future__ import annotations

import logging

from devplacepy.database import (
    MATURITY_TARGETS,
    REPORT_REASONS,
    SYSTEM_ACTOR,
    set_maturity,
)

from devplacepy.services.background import background
from devplacepy.services.moderation.filter import Classification, Screening, screen
from devplacepy.services.moderation.queue import raise_report

logger = logging.getLogger(__name__)

SCREENED_FIELDS: dict[str, tuple[str, ...]] = {
    "posts": ("title", "content"),
    "projects": ("title", "description"),
    "gists": ("title", "description"),
    "news": ("title", "description"),
    "quizzes": ("title", "description"),
    "comments": ("content",),
    "messages": ("content",),
    "users": ("username", "bio", "location"),
}

REFUSAL = (
    "This content matches a category prohibited by the community guidelines "
    "({categories}) and was not published. See /docs/community-guidelines.html."
)

FAILURE_REASON = "other"


class ContentRefused(Exception):
    def __init__(self, categories: tuple[str, ...]):
        self.categories = categories
        self.message = REFUSAL.format(categories=", ".join(categories) or "prohibited")
        super().__init__(self.message)


def screen_fields(table_name: str, fields: dict) -> Screening:
    columns = SCREENED_FIELDS.get(table_name)
    if not columns:
        return Screening(classification=Classification())
    values = {
        column: str(fields.get(column) or "")
        for column in columns
        if fields.get(column)
    }
    return screen(values)


def refuse_if_blocked(screening: Screening) -> None:
    if screening.blocked:
        raise ContentRefused(screening.classification.categories)


def _reason_for(categories: tuple[str, ...]) -> str:
    for category in categories:
        if category in REPORT_REASONS:
            return category
    return FAILURE_REASON


def record(
    screening: Screening,
    *,
    target_type: str,
    target_uid: str,
    actor_uid: str = SYSTEM_ACTOR,
    request=None,
) -> None:
    from devplacepy.services.audit import record as audit

    classification = screening.classification
    if classification.verdict == "allow":
        return
    if classification.maturity != "general" and target_type in MATURITY_TARGETS:
        labelled = set_maturity(
            target_type, target_uid, classification.maturity, "filter", SYSTEM_ACTOR
        )
        if labelled:
            audit.record(
                request,
                "filter.maturity",
                actor_kind="system",
                target_type=target_type,
                target_uid=target_uid,
                new_value=classification.maturity,
                metadata={
                    "categories": list(classification.categories),
                    "score": classification.score,
                    "author_uid": actor_uid,
                },
                summary=(
                    f"content filter labelled {target_type} {target_uid} "
                    f"as {classification.maturity}"
                ),
                links=[audit.target(target_type, target_uid)],
            )
    if not classification.flagged:
        return
    detail = classification.detail or "matched a prohibited category"
    if classification.failed:
        detail = classification.detail
    background.submit(
        raise_report,
        target_type=target_type,
        target_uid=target_uid,
        reporter_uid=SYSTEM_ACTOR,
        reason=_reason_for(classification.categories),
        detail=f"Automated filter: {detail} (fields: {', '.join(screening.fields) or 'n/a'})",
        origin="filter",
        severity="critical" if classification.failed else "",
        categories=list(classification.categories),
    )
    event = "filter.block" if classification.verdict == "block" else "filter.review"
    logger.info(
        f"filter {classification.verdict} on {target_type} {target_uid}: {detail}"
    )
    audit.record(
        request,
        event,
        actor_kind="system",
        target_type=target_type,
        target_uid=target_uid,
        result="denied" if classification.verdict == "block" else "success",
        metadata={
            "categories": list(classification.categories),
            "score": classification.score,
            "fields": list(screening.fields),
            "failed": classification.failed,
            "author_uid": actor_uid,
        },
        summary=f"content filter raised {classification.verdict} on {target_type} {target_uid}",
        links=[audit.target(target_type, target_uid)],
    )
