"""Content guard for memory injection protection.

Memory files (MEMORY.md, daily notes) are injected verbatim into the
system prompt.  Any prompt-injection or exfiltration payload stored there
would execute on every subsequent turn.  This module scans content
*before* it is written to disk and blocks dangerous patterns.

Only called for writes targeting the memory/ directory — regular file
operations outside memory are not affected.
"""

from __future__ import annotations

import re
from pathlib import Path
from typing import Optional

# ── Threat patterns (regex, human-readable ID) ──────────────────────
# Each pattern is case-insensitive.  Keep them tight to minimise false
# positives — every entry here can block a legitimate write.

_THREAT_PATTERNS: list[tuple[str, str]] = [
    # Prompt injection / role hijack
    (r"ignore\s+(previous|all|above|prior)\s+instructions",  "prompt_injection"),
    (r"you\s+are\s+now\s+(a|an|my|the|acting)\s+",            "role_hijack"),
    (r"do\s+not\s+tell\s+the\s+user",                        "deception_hide"),
    (r"system\s+prompt\s+override",                           "sys_prompt_override"),
    (r"disregard\s+(your|all|any)\s+(instructions|rules|guidelines)",
                                                              "disregard_rules"),
    (r"act\s+as\s+(if|though)\s+you\s+(have\s+no|don't\s+have)"
     r"\s+(restrictions|limits|rules)",                       "bypass_restrictions"),

    # Data exfiltration via shell commands
    (r"curl\s+[^\n]*\$\{?\w*(KEY|TOKEN|SECRET|PASSWORD|CREDENTIAL|API)",
                                                              "exfil_curl"),
    (r"wget\s+[^\n]*\$\{?\w*(KEY|TOKEN|SECRET|PASSWORD|CREDENTIAL|API)",
                                                              "exfil_wget"),
    (r"cat\s+[^\n]*(\.env|credentials|\.netrc|\.pgpass|\.npmrc|\.pypirc)",
                                                              "read_secrets"),

    # Persistence / backdoor
    (r"authorized_keys",                                      "ssh_backdoor"),
    (r"\$HOME/\.ssh|~/\.ssh",                                 "ssh_access"),
    (r"\$HOME/\.flowly/config\.json|~/\.flowly/config\.json", "flowly_config"),
]

# Invisible unicode characters used for prompt-smuggling.
_INVISIBLE_CHARS: set[str] = {
    "\u200b",  # Zero-Width Space
    "\u200c",  # Zero-Width Non-Joiner
    "\u200d",  # Zero-Width Joiner
    "\u2060",  # Word Joiner
    "\ufeff",  # Zero-Width No-Break Space (BOM)
    "\u202a",  # Left-to-Right Embedding
    "\u202b",  # Right-to-Left Embedding
    "\u202c",  # Pop Directional Formatting
    "\u202d",  # Left-to-Right Override
    "\u202e",  # Right-to-Left Override
}


def scan_content(content: str) -> Optional[str]:
    """Scan *content* for injection / exfiltration payloads.

    Returns ``None`` if the content is safe, or a human-readable error
    string explaining why the write was blocked.
    """
    # 1. Invisible unicode
    for ch in _INVISIBLE_CHARS:
        if ch in content:
            return (
                f"Blocked: content contains invisible unicode character "
                f"U+{ord(ch):04X} which may be used for prompt injection."
            )

    # 2. Threat patterns
    for pattern, pid in _THREAT_PATTERNS:
        if re.search(pattern, content, re.IGNORECASE):
            return (
                f"Blocked: content matches threat pattern '{pid}'. "
                f"Memory entries are injected into the system prompt and "
                f"must not contain injection or exfiltration payloads."
            )

    return None


def is_memory_path(resolved_path: Path, workspace: Path | None) -> bool:
    """Return True if *resolved_path* is inside the workspace memory directory."""
    if workspace is None:
        return False
    memory_dir = (workspace / "memory").resolve()
    try:
        resolved_path.relative_to(memory_dir)
        return True
    except ValueError:
        return False
