"""CodeScanner for meshulash-guard SDK.

Detects code content in user input. Useful for blocking or logging inputs
that contain source code, which may indicate prompt injection, exfiltration
attempts, or policy violations. The scanner is a pure config serializer:
detection runs on the server side.
"""

from __future__ import annotations

from ..enums import Action, _StrValueMixin
from .base import BaseScanner


class CodeLanguage(_StrValueMixin):
    """Programming languages supported by CodeScanner.

    Use members as an optional filter — only the listed languages trigger
    the scanner. ``None`` (the default) means detect all supported languages.
    """

    PYTHON = "python"
    JAVASCRIPT = "javascript"
    TYPESCRIPT = "typescript"
    JAVA = "java"
    CPP = "cpp"
    C = "c"
    CSHARP = "csharp"
    GO = "go"
    RUST = "rust"
    PHP = "php"
    RUBY = "ruby"
    SWIFT = "swift"
    KOTLIN = "kotlin"
    SQL = "sql"
    BASH = "bash"
    HTML = "html"
    CSS = "css"


class CodeScanner(BaseScanner):
    """Scanner that detects source code in user input.

    The server uses a code-detection model to score the likelihood that
    the input contains code. The threshold controls how confident the
    model must be before triggering. An optional language filter lets you
    restrict detection to specific programming languages.

    Args:
        threshold: Minimum confidence score [0.0, 1.0] to trigger. Defaults
            to 0.7.
        languages: Optional list of :class:`CodeLanguage` members to restrict
            detection. ``None`` (default) means all 17 supported languages.
        action: Default action when code is detected. Defaults to BLOCK.
        overrides: Optional per-language action overrides. E.g.
            ``{CodeLanguage.SQL: Action.LOG}`` logs SQL detections instead of
            blocking. Only meaningful when a language-specific match occurs.

    Raises:
        ValueError: If threshold is outside [0.0, 1.0].
    """

    def __init__(
        self,
        threshold: float = 0.7,
        languages: list[CodeLanguage] | None = None,
        action: Action = Action.BLOCK,
        overrides: dict[CodeLanguage, Action] | None = None,
    ) -> None:
        if not (0.0 <= threshold <= 1.0):
            raise ValueError(
                f"CodeScanner threshold must be in [0.0, 1.0], got {threshold!r}."
            )
        self._threshold = threshold
        self._languages = list(languages) if languages is not None else None
        self._action = action
        self._overrides = dict(overrides) if overrides else None

    def to_guardline_spec(self) -> dict:
        """Return a flat guardline spec dict for this scanner configuration."""
        spec: dict = {
            "name": "CodeScanner",
            "action": str(self._action),
            "threshold": self._threshold,
            "level": 2,
        }
        if self._languages is not None:
            spec["languages"] = [str(lang) for lang in self._languages]
        if self._overrides:
            spec["overrides"] = {str(lang): str(act) for lang, act in self._overrides.items()}
        return spec
