"""
PromptShield — Layer 1: Pattern Library
=========================================

Maintainer : Joseph Mutua
Version    : 1.0.0

What this layer does
--------------------
Runs 61 pre-compiled regex signatures against the input text.
Each signature targets a specific *attack shape* — not just one keyword,
but the structural pattern that all variants of that attack share.

This is the fastest layer (pure regex, O(n)) and the most precise.
When a pattern fires with confidence ≥ 0.85, the score is usually
authoritative on its own.

Attack Taxonomy (8 categories)
--------------------------------
1. instruction_override   — Cancel / replace the system prompt
2. role_hijack            — Force a persona or mode switch
3. data_exfiltration      — Extract system prompt or memory
4. goal_hijack            — Redirect the agent's objective
5. authority_spoof        — Impersonate developer / admin / creator
6. context_manipulation   — Inject false conversational context
7. payload_injection      — Embed commands in code blocks / JSON / XML
8. side_channel           — Exploit multi-turn state, memory, function calls

Design rules
------------
- Never match on a single generic word. Every pattern captures a
  structural relationship (subject + verb + object type).
- Confidence reflects how unambiguous the pattern is:
    0.95–1.00 = unambiguous attack phrase, very low false-positive risk
    0.80–0.94 = strong signal, minimal ambiguity
    0.70–0.79 = moderate signal, may appear in edge-case benign text
    0.50–0.69 = weak signal, used only in combination with other layers
- Severity multipliers (CATEGORY_SEVERITY) amplify scores for the
  categories with the highest real-world risk.

Adding new patterns
-------------------
1. Append a PatternEntry to the relevant category list below.
2. Write a comment explaining what structural attack it covers.
3. Set confidence honestly — erring toward lower is safer than FPs.
4. Run the test suite: python -m pytest tests/test_patterns.py
"""

from __future__ import annotations

import logging
import re
from dataclasses import dataclass
from typing import Dict, List

logger = logging.getLogger(__name__)


# ---------------------------------------------------------------------------
# Data type
# ---------------------------------------------------------------------------

@dataclass(frozen=True)
class PatternEntry:
    """
    A single compiled regex signature with metadata.

    Attributes:
        pattern     : Pre-compiled re.Pattern. Compiled once at import time.
        category    : Attack category identifier string.
        description : Human-readable description used in reports / UI.
        confidence  : Base confidence weight 0.0–1.0, multiplied by
                      CATEGORY_SEVERITY during score fusion.
    """
    pattern:     re.Pattern
    category:    str
    description: str
    confidence:  float


def _c(regex: str, flags: int = re.IGNORECASE | re.DOTALL) -> re.Pattern:
    """
    Compile a regex with standard flags.
    Logs a warning and returns a no-match pattern on compilation errors
    so one bad entry doesn't crash the entire engine.
    """
    try:
        return re.compile(regex, flags)
    except re.error as exc:
        logger.error(
            "Layer 1: failed to compile pattern (%.60s): %s", regex, exc
        )
        return re.compile(r"(?!)")  # never matches


# ---------------------------------------------------------------------------
# Category 1 — Instruction Override
# ---------------------------------------------------------------------------
# Attacker attempts to cancel or replace the system-level instructions.
# These are the most common attack type and the most unambiguous.

INSTRUCTION_OVERRIDE: List[PatternEntry] = [

    PatternEntry(
        _c(r"ignore\s+(all\s+)?(previous|prior|above|earlier)\s+"
           r"(instructions?|prompts?|rules?|guidelines?|constraints?)"),
        "instruction_override",
        "Direct instruction override — 'ignore all previous instructions'",
        0.95,
    ),
    PatternEntry(
        _c(r"disregard\s+(all\s+)?(previous|prior|above|earlier|your)\s+"
           r"(instructions?|rules?|guidelines?)"),
        "instruction_override",
        "Disregard variant of instruction override",
        0.95,
    ),
    PatternEntry(
        _c(r"forget\s+(all\s+)?(previous|prior|above|your)\s+"
           r"(instructions?|context|rules?|training)"),
        "instruction_override",
        "Forget variant of instruction override",
        0.90,
    ),
    PatternEntry(
        _c(r"(override|overwrite|replace|cancel|void|nullify)\s+(your\s+)?"
           r"(system\s+)?(instructions?|prompt|rules?|guidelines?|directives?)"),
        "instruction_override",
        "Explicit override / replace instruction",
        0.95,
    ),
    PatternEntry(
        _c(r"new\s+(instructions?|directives?|rules?|guidelines?|prompt)\s*[:;]\s*"),
        "instruction_override",
        "New instructions injection marker",
        0.85,
    ),
    PatternEntry(
        _c(r"(your|the)\s+(new|updated|revised|real|true|actual)\s+"
           r"(instructions?|prompt|role|task|purpose|goal)\s+(is|are|will\s+be)\s*:"),
        "instruction_override",
        "Revised instructions injection",
        0.88,
    ),
    PatternEntry(
        _c(r"from\s+now\s+on[,\s]+(you|always|never|must|will)"),
        "instruction_override",
        "Temporal override — 'from now on you will...'",
        0.82,
    ),
    PatternEntry(
        _c(r"starting\s+(now|immediately|today)[,\s]+(you|always|never|must|will)"),
        "instruction_override",
        "Temporal override — 'starting now you will...'",
        0.80,
    ),
    PatternEntry(
        _c(r"reset\s+(to\s+)?(default|factory|original|base)\s+"
           r"(settings?|instructions?|mode|state)"),
        "instruction_override",
        "Reset to default attempt",
        0.78,
    ),
    PatternEntry(
        _c(r"(stop|cease|quit|end)\s+(following|obeying|adhering\s+to)\s+"
           r"(your|all|previous|prior)"),
        "instruction_override",
        "Stop following instructions",
        0.90,
    ),
    PatternEntry(
        _c(r"you\s+no\s+longer\s+(need\s+to\s+)?(follow|obey|adhere|comply)"),
        "instruction_override",
        "Identity disavowal — 'you no longer need to follow'",
        0.88,
    ),
    PatternEntry(
        _c(r"the\s+above\s+instructions?\s+"
           r"(do\s+not\s+apply|are\s+(wrong|invalid|outdated)|should\s+be\s+ignored)"),
        "instruction_override",
        "Above-instructions invalidation",
        0.92,
    ),
]


# ---------------------------------------------------------------------------
# Category 2 — Role Hijacking
# ---------------------------------------------------------------------------
# Attacker forces a persona or mode switch to bypass safety measures.
# Includes jailbreak modes (DAN, developer mode) and fictional personas.

ROLE_HIJACK: List[PatternEntry] = [

    PatternEntry(
        _c(r"(you\s+are\s+now|act\s+as|pretend\s+(to\s+be|you\s+are)|"
           r"roleplay\s+as|imagine\s+you\s+(are|were))\s+(a\s+|an\s+)?"
           r"(?!assistant|helpful)(\w+)"),
        "role_hijack",
        "Role switch attempt — 'you are now / act as / pretend to be'",
        0.88,
    ),
    PatternEntry(
        _c(r"(you\s+are|you're)\s+no\s+longer\s+(an?\s+)?"
           r"(AI|assistant|bot|language\s+model|LLM)"),
        "role_hijack",
        "Identity denial — 'you are no longer an AI'",
        0.92,
    ),
    PatternEntry(
        _c(r"switch\s+(to|into)\s+"
           r"(developer|admin|root|superuser|DAN|jailbreak|unrestricted|uncensored)\s+mode"),
        "role_hijack",
        "Mode switch to privileged / unrestricted mode",
        0.97,
    ),
    PatternEntry(
        _c(r"\bDAN\b.*\b(do\s+anything\s+now|no\s+restrictions?|unlimited)"),
        "role_hijack",
        "DAN (Do Anything Now) jailbreak pattern",
        0.99,
    ),
    PatternEntry(
        _c(r"jailbreak\s+(mode|version|prompt|override)"),
        "role_hijack",
        "Explicit jailbreak keyword",
        0.99,
    ),
    PatternEntry(
        _c(r"(developer|debug|maintenance|god|admin|root)\s+mode\s*"
           r"([:=]\s*on|enabled|activated|unlocked)"),
        "role_hijack",
        "Privileged mode activation",
        0.96,
    ),
    PatternEntry(
        _c(r"your\s+(true|real|actual|inner|hidden|secret)\s+"
           r"(self|nature|identity|personality|purpose)"),
        "role_hijack",
        "Hidden-true-self appeal",
        0.85,
    ),
    PatternEntry(
        _c(r"(without|with\s+no)\s+(restrictions?|filters?|limitations?|"
           r"safety\s+measures?|guardrails?|censorship)"),
        "role_hijack",
        "Restriction removal request",
        0.90,
    ),
    PatternEntry(
        _c(r"(bypass|circumvent|disable|remove|turn\s+off)\s+(your\s+)?"
           r"(safety|content|ethical?|moral)\s+(filters?|guidelines?|rules?|training|measures?)"),
        "role_hijack",
        "Explicit safety bypass request",
        0.97,
    ),
    PatternEntry(
        _c(r"unleash\s+(your|the)\s+(true|real|full|unlimited)\s+"
           r"(potential|capabilities?|power|intelligence)"),
        "role_hijack",
        "Capability unleash attempt",
        0.88,
    ),
    PatternEntry(
        _c(r"(in\s+)?character\s+(as|of)\s+(?!the|a\s+helpful)([\w\s]+)\s+"
           r"who\s+(does\s+not|doesn't|won't|will\s+never)\s+(follow|respect|obey)"),
        "role_hijack",
        "Character bypass — playing a character who ignores rules",
        0.90,
    ),
]


# ---------------------------------------------------------------------------
# Category 3 — Data Exfiltration
# ---------------------------------------------------------------------------
# Attacker tries to extract the system prompt, memory, or any internal context.

DATA_EXFILTRATION: List[PatternEntry] = [

    PatternEntry(
        _c(r"(print|output|display|reveal|expose|leak|dump|return|repeat|echo)\s+"
           r"(your\s+)?(system\s+)?(prompt|instructions?|context|memory|training\s+data)"),
        "data_exfiltration",
        "System prompt extraction attempt",
        0.95,
    ),
    PatternEntry(
        _c(r"(what|tell\s+me)\s+(are|is)\s+your\s+(exact\s+)?"
           r"(system\s+prompt|initial\s+instructions?|original\s+prompt|first\s+message)"),
        "data_exfiltration",
        "Direct system prompt query",
        0.93,
    ),
    PatternEntry(
        _c(r"(list|print|output)\s+(all|every|the\s+full)\s+(content|text|words?)\s+"
           r"(from\s+)?(above|before|earlier|the\s+top|the\s+beginning|your\s+context)"),
        "data_exfiltration",
        "Context window dump attempt",
        0.92,
    ),
    PatternEntry(
        _c(r"(repeat|echo|copy)\s+(everything|all|the\s+entire\s+text|word\s+for\s+word)\s+"
           r"(from\s+)?(above|before|the\s+document|the\s+context)"),
        "data_exfiltration",
        "Full context repetition request",
        0.93,
    ),
    PatternEntry(
        _c(r"(what|which)\s+(rules?|instructions?|constraints?|guidelines?)\s+"
           r"(were\s+you|are\s+you)\s+(given|told|instructed|programmed)"),
        "data_exfiltration",
        "Rules / instructions query",
        0.85,
    ),
    PatternEntry(
        _c(r"send\s+(all\s+)?(conversation|chat|message)\s+(history|log|data)\s+"
           r"(to|via)\s+(https?://|email|slack|webhook)"),
        "data_exfiltration",
        "Conversation exfiltration via external URL",
        0.99,
    ),
    PatternEntry(
        _c(r"(before|after)\s+(responding|answering|replying)[,\s]+"
           r"(output|print|send|forward)\s+(your\s+)?(prompt|instructions?|context)"),
        "data_exfiltration",
        "Pre/post-response data exfiltration",
        0.94,
    ),
    PatternEntry(
        _c(r"what\s+(were\s+you|have\s+you\s+been)\s+(told|instructed|trained|configured)\s+"
           r"(to\s+do|about|regarding)"),
        "data_exfiltration",
        "Configuration inference query",
        0.80,
    ),
]


# ---------------------------------------------------------------------------
# Category 4 — Goal Hijacking
# ---------------------------------------------------------------------------
# Attacker redirects the agent's primary objective toward a new task.

GOAL_HIJACK: List[PatternEntry] = [

    PatternEntry(
        _c(r"your\s+(new|updated|revised|real|true|actual|only|primary)\s+"
           r"(goal|objective|purpose|mission|task|job|function)\s+"
           r"(is|are|will\s+be|from\s+now)\s*:?"),
        "goal_hijack",
        "Goal redefinition — 'your new goal is...'",
        0.90,
    ),
    PatternEntry(
        _c(r"(forget|ignore|discard|abandon)\s+(your\s+)?"
           r"(original|previous|current|existing)\s+(goal|objective|purpose|mission|task)"),
        "goal_hijack",
        "Goal replacement — forget original objective",
        0.88,
    ),
    PatternEntry(
        _c(r"(instead\s+of|rather\s+than)\s+(your\s+)?"
           r"(original|current|assigned)\s+(task|goal|purpose|job),?\s+"
           r"(you\s+should|please|now|I\s+need\s+you\s+to)"),
        "goal_hijack",
        "Task substitution",
        0.85,
    ),
    PatternEntry(
        _c(r"(prioritize|prioritise)\s+(my\s+)?(request|needs?|demands?|commands?)\s+"
           r"(over|above|before)\s+(your\s+)?(instructions?|guidelines?|rules?|training)"),
        "goal_hijack",
        "Priority override — user demand above system instructions",
        0.86,
    ),
    PatternEntry(
        _c(r"(complete|accomplish|perform|execute)\s+"
           r"(this|the\s+following|the\s+real|the\s+actual)\s+(task|job|objective)\s+instead"),
        "goal_hijack",
        "Alternate task injection",
        0.80,
    ),
]


# ---------------------------------------------------------------------------
# Category 5 — Authority Spoofing
# ---------------------------------------------------------------------------
# Attacker impersonates a developer, admin, or system-level authority
# to claim elevated permissions.

AUTHORITY_SPOOF: List[PatternEntry] = [

    PatternEntry(
        _c(r"(I\s+am|this\s+is|message\s+from)\s+(your\s+)?"
           r"(developer|creator|admin|operator|owner|trainer|Anthropic|OpenAI|Google|system)"),
        "authority_spoof",
        "Developer / creator impersonation",
        0.92,
    ),
    PatternEntry(
        _c(r"(I\s+am|this\s+is)\s+(a\s+)?"
           r"(trusted|authorized|verified|privileged)\s+(user|admin|developer|tester|researcher)"),
        "authority_spoof",
        "Trusted identity claim",
        0.88,
    ),
    PatternEntry(
        _c(r"(authorized|permission\s+granted|access\s+granted)\s+(to\s+)?"
           r"(bypass|override|ignore|disable|unlock)"),
        "authority_spoof",
        "Fabricated authorization claim",
        0.90,
    ),
    PatternEntry(
        _c(r"\[SYSTEM\]|\[ADMIN\]|\[OPERATOR\]|\[ROOT\]|\[OVERRIDE\]|\[AUTHORIZED\]"),
        "authority_spoof",
        "Fake system / admin tag injection",
        0.95,
    ),
    PatternEntry(
        _c(r"(internal|private|confidential|secure)\s+(mode|channel|protocol|override)\s+"
           r"(enabled|activated|granted|unlocked)"),
        "authority_spoof",
        "Fake internal mode claim",
        0.88,
    ),
    PatternEntry(
        _c(r"(for|this\s+is)\s+(testing|evaluation|red\s+team|audit|security\s+research)\s+"
           r"(purposes?|mode|only)[,\s]+(so\s+)?(ignore|bypass|disable|skip)"),
        "authority_spoof",
        "Security-testing bypass claim",
        0.86,
    ),
]


# ---------------------------------------------------------------------------
# Category 6 — Context Manipulation
# ---------------------------------------------------------------------------
# Attacker injects false context — a prior agreement, a document instruction,
# or a fabricated prior conversation — to manipulate agent behaviour.

CONTEXT_MANIPULATION: List[PatternEntry] = [

    PatternEntry(
        _c(r"(we\s+already|you\s+already|I\s+already)\s+"
           r"(agreed|established|decided|confirmed)\s+(that|to|you\s+would|you\s+will)"),
        "context_manipulation",
        "False prior agreement claim",
        0.88,
    ),
    PatternEntry(
        _c(r"(as\s+you\s+(said|mentioned|agreed|noted|stated)|"
           r"you\s+previously\s+(said|mentioned|agreed|told\s+me))\s*(earlier|before|last\s+time)?"),
        "context_manipulation",
        "False prior statement attribution",
        0.85,
    ),
    PatternEntry(
        _c(r"(the\s+document|the\s+text|the\s+content|the\s+following)\s+"
           r"(above|below|provided)?\s*(contains?|includes?|has)\s+(new\s+)?"
           r"(instructions?|commands?|directives?)\s+(for\s+you|to\s+follow)"),
        "context_manipulation",
        "Document-embedded instruction injection",
        0.92,
    ),
    PatternEntry(
        _c(r"translate\s+(the\s+following|this)\s+(text|content|message)\s+(and\s+)?"
           r"(then\s+)?(follow|execute|obey|implement)\s+(the\s+)?(instructions?|commands?)"),
        "context_manipulation",
        "Translate-then-execute injection",
        0.94,
    ),
    PatternEntry(
        _c(r"(complete|finish|continue)\s+(this\s+)?(sentence|story|paragraph)"
           r"[^.]{0,60}(ignore|bypass|override|disregard)"),
        "context_manipulation",
        "Completion trick with embedded injection",
        0.87,
    ),
    PatternEntry(
        _c(r"(note:|footnote:|p\.?s\.?:|aside:)\s*[^\n]{0,50}"
           r"(ignore|bypass|override|new\s+instructions?|disregard)"),
        "context_manipulation",
        "Footnote / note style injection",
        0.85,
    ),
]


# ---------------------------------------------------------------------------
# Category 7 — Payload Injection
# ---------------------------------------------------------------------------
# Attacker embeds commands inside data payloads: code blocks, JSON, XML,
# base64, or completion triggers.

PAYLOAD_INJECTION: List[PatternEntry] = [

    PatternEntry(
        _c(r"```\s*(system|override|instructions?|admin)[^`]*```",
           re.IGNORECASE | re.DOTALL),
        "payload_injection",
        "Code block labelled 'system' or 'override'",
        0.92,
    ),
    PatternEntry(
        _c(r"<\s*(system|instructions?|override|admin|prompt)\s*>[^<]{0,500}"
           r"</\s*(system|instructions?|override|admin|prompt)\s*>",
           re.IGNORECASE | re.DOTALL),
        "payload_injection",
        "XML / HTML system tag injection",
        0.90,
    ),
    PatternEntry(
        _c(r'"(role|type|mode|action)"\s*:\s*"(system|override|admin|jailbreak|unrestricted)"'),
        "payload_injection",
        "JSON payload with injected role field",
        0.88,
    ),
    PatternEntry(
        _c(r"\\n\\n(ignore|forget|override|you\s+are\s+now)[^\\]{0,200}\\n"),
        "payload_injection",
        "Escaped newline injection",
        0.85,
    ),
    PatternEntry(
        _c(r"(execute|eval|run|call|invoke)\s+(the\s+)?"
           r"(following|above|this)\s+(code|command|script|function|payload)"),
        "payload_injection",
        "Code execution request",
        0.90,
    ),
    PatternEntry(
        _c(r"(base64|hex|rot13|cipher|encoded?)\s*(decode|version|representation)?"
           r"\s*[:=]\s*[A-Za-z0-9+/=]{20,}"),
        "payload_injection",
        "Encoded payload detected (base64/hex/cipher)",
        0.87,
    ),
]


# ---------------------------------------------------------------------------
# Category 8 — Side-Channel / Meta Attacks
# ---------------------------------------------------------------------------
# Attacker exploits multi-turn state, function calling, memory, or
# the model's meta-processing behaviour.

SIDE_CHANNEL: List[PatternEntry] = [

    PatternEntry(
        _c(r"(silently|secretly|without\s+(telling|mentioning|informing|showing))\s+"
           r"(append|add|include|forward|send|transmit)"),
        "side_channel",
        "Silent data exfiltration command",
        0.95,
    ),
    PatternEntry(
        _c(r"after\s+(completing|finishing|answering|responding)[,\s]+"
           r"(silently|also|additionally|then)\s+(send|forward|append|add|include)"),
        "side_channel",
        "Post-response covert action",
        0.93,
    ),
    PatternEntry(
        _c(r"(when|whenever|every\s+time)\s+(you\s+)?"
           r"(see|receive|process|read|encounter)\s+the\s+(word|phrase|keyword|token)\s+"
           r"[\"']?(\w+)[\"']?"),
        "side_channel",
        "Conditional keyword trigger injection",
        0.90,
    ),
    PatternEntry(
        _c(r"(call|invoke|use|trigger)\s+(the\s+)?"
           r"(function|tool|plugin|api|action)\s+[\w_]+\s+(with|using)\s+(parameters?|args?)"),
        "side_channel",
        "Covert function / tool call injection",
        0.88,
    ),
    PatternEntry(
        _c(r"(store|remember|memorize|save)\s+(this|the\s+following|my)\s+"
           r"(instruction|command|rule|information)\s+(for|to\s+use)\s+(later|next\s+time|always)"),
        "side_channel",
        "Memory poisoning attempt",
        0.90,
    ),
    PatternEntry(
        _c(r"in\s+your\s+next\s+(response|message|reply|output)\s+"
           r"(always|never|only|first)\s+(say|include|add|output|print)"),
        "side_channel",
        "Next-turn behaviour manipulation",
        0.85,
    ),
]


# ---------------------------------------------------------------------------
# Unified collection and metadata
# ---------------------------------------------------------------------------

ALL_PATTERNS: List[PatternEntry] = (
    INSTRUCTION_OVERRIDE
    + ROLE_HIJACK
    + DATA_EXFILTRATION
    + GOAL_HIJACK
    + AUTHORITY_SPOOF
    + CONTEXT_MANIPULATION
    + PAYLOAD_INJECTION
    + SIDE_CHANNEL
)

# Human-readable display names (used in reports, API responses, and the UI)
CATEGORY_LABELS: Dict[str, str] = {
    "instruction_override": "Instruction Override",
    "role_hijack":          "Role Hijacking",
    "data_exfiltration":    "Data Exfiltration",
    "goal_hijack":          "Goal Hijacking",
    "authority_spoof":      "Authority Spoofing",
    "context_manipulation": "Context Manipulation",
    "payload_injection":    "Payload Injection",
    "side_channel":         "Side-Channel Attack",
}

# Severity multipliers applied to confidence scores during score fusion.
# 1.00 = maximum severity; attacks in this category are always critical.
CATEGORY_SEVERITY: Dict[str, float] = {
    "instruction_override": 0.95,
    "role_hijack":          1.00,  # complete safety bypass
    "data_exfiltration":    1.00,  # direct data loss
    "goal_hijack":          0.88,
    "authority_spoof":      0.92,
    "context_manipulation": 0.85,
    "payload_injection":    0.90,
    "side_channel":         0.92,
}

logger.debug(
    "Layer 1 loaded: %d patterns across %d categories",
    len(ALL_PATTERNS),
    len(CATEGORY_LABELS),
)
