"""
InsAIts API - OWASP Mappings (Single Source of Truth)
=====================================================
Centralised OWASP MCP / Agentic Security code mappings, CVE references,
and human-readable explainer data.  Both ``insaits_web_dashboard.py`` and
``routers/export.py`` import from here instead of maintaining inline copies.
"""

from __future__ import annotations

from typing import Dict, List

# ---------------------------------------------------------------------------
# Fallback OWASP code mapping  (anomaly_type -> OWASP id string)
# Used when the optional ``insaits_cve_signatures`` package is absent.
# ---------------------------------------------------------------------------
OWASP_CODES_FALLBACK: Dict[str, str] = {
    "tool_poisoning": "MCP01",
    "prompt_injection": "MCP02",
    "data_exfiltration": "MCP03",
    "credential_exposure": "MCP04",
    "unauthorized_access": "MCP05",
    "context_collapse": "MCP06",
    "hallucination_chain": "MCP07",
    "truncated_output": "MCP08",
    "shadow_vocabulary": "MCP09",
    "blank_response": "MCP10",
    "information_flow_violation": "MCP10",
    "fact_contradiction": "ASI01",
    "semantic_drift": "ASI01",
    "anchor_drift": "ASI02",
    "confidence_erosion": "ASI03",
    "phantom_citation": "ASI06",
    "shorthand_emergence": "ASI07",
    "jargon_drift": "ASI07",
    "cascading_failure": "ASI08",
    "uncertainty_propagation": "ASI08",
    "shadow_server": "MCP09",
    "rogue_agent": "ASI09",
    "governance_gap": "ASI10",
    "exfiltration_pattern": "ASI06",
    "entropy_covert_channel": "ASI06",
    # Hook-generated anomaly types (0B features)
    "unauthorized_write": "MCP05",
    "monitoring_gap": "MCP08",
    "sensitive_file_access": "MCP04",
    "file_thrashing": "MCP08",
    "repetition_loop": "ASI08",
    "agent_surrender": "ASI09",
    "npc_behavior": "ASI09",
    "blame_shift": "ASI09",
    "user_frustration": "ASI10",
    "ask_user_forced": "ASI10",
    "ask_user_suggested": "ASI10",
    "memory_poisoning": "ASI03",
}

# ---------------------------------------------------------------------------
# OWASP MAP  (anomaly_type -> {code, name})
# Richer version used by the export router.
# ---------------------------------------------------------------------------
OWASP_MAP: Dict[str, Dict[str, str]] = {
    "tool_poisoning": {"code": "MCP01", "name": "Tool Poisoning"},
    "prompt_injection": {"code": "MCP02", "name": "Excessive Agency"},
    "data_exfiltration": {"code": "MCP03", "name": "Data Exfiltration"},
    "credential_exposure": {"code": "MCP04", "name": "Credential Exposure"},
    "unauthorized_access": {"code": "MCP05", "name": "Unauthorized Access"},
    "context_collapse": {"code": "MCP06", "name": "Context Sharing"},
    "hallucination_chain": {"code": "MCP07", "name": "Multi-Hop Chains"},
    "truncated_output": {"code": "MCP08", "name": "Audit Trails"},
    "shadow_vocabulary": {"code": "MCP09", "name": "Shadow Servers"},
    "blank_response": {"code": "MCP10", "name": "Data Leakage"},
    "fact_contradiction": {"code": "ASI01", "name": "Goal Hijacking"},
    "anchor_drift": {"code": "ASI02", "name": "Prompt Manipulation"},
    "confidence_erosion": {"code": "ASI03", "name": "Memory Poisoning"},
    "phantom_citation": {"code": "ASI06", "name": "Data Exposure"},
    "shorthand_emergence": {"code": "ASI07", "name": "Inter-Agent Abuse"},
    "cascading_failure": {"code": "ASI08", "name": "Cascading Failures"},
    "uncertainty_propagation": {"code": "ASI08", "name": "Cascading Failures"},
    "shadow_server": {"code": "MCP09", "name": "Shadow Servers"},
    "rogue_agent": {"code": "ASI09", "name": "Rogue Agents"},
    "governance_gap": {"code": "ASI10", "name": "Governance Gaps"},
    # Hook-generated anomaly types
    "unauthorized_write": {"code": "MCP05", "name": "Unauthorized Access"},
    "monitoring_gap": {"code": "MCP08", "name": "Audit Trails"},
    "sensitive_file_access": {"code": "MCP04", "name": "Credential Exposure"},
    "file_thrashing": {"code": "MCP08", "name": "Audit Trails"},
    "repetition_loop": {"code": "ASI08", "name": "Cascading Failures"},
    "agent_surrender": {"code": "ASI09", "name": "Rogue Agents"},
    "npc_behavior": {"code": "ASI09", "name": "Rogue Agents"},
    "blame_shift": {"code": "ASI09", "name": "Rogue Agents"},
    "user_frustration": {"code": "ASI10", "name": "Governance Gaps"},
    "memory_poisoning": {"code": "ASI03", "name": "Memory Poisoning"},
}

# ---------------------------------------------------------------------------
# CVE mapping  (anomaly_type -> CVE id)
# Subset -- full list lives in insaits_cve_signatures.py when available.
# ---------------------------------------------------------------------------
CVE_MAP: Dict[str, str] = {
    "tool_poisoning": "CVE-2025-47265",
    "prompt_injection": "CVE-2025-43859",
    "data_exfiltration": "CVE-2025-47267",
    "credential_exposure": "CVE-2025-47268",
    "shadow_vocabulary": "CVE-2025-47269",
}

# ---------------------------------------------------------------------------
# OWASP Explainer -- human-readable explanations for each OWASP code
# ---------------------------------------------------------------------------
OWASP_EXPLAINER: Dict[str, Dict[str, str]] = {
    "MCP01": {
        "name": "Tool Poisoning",
        "what": "A tool's description contains hidden instructions that trick the AI into doing something the user didn't ask for.",
        "risk": "Attacker-controlled tool descriptions can make the AI exfiltrate data, run malicious commands, or ignore safety rules.",
        "response": "InsAIts compares tool descriptions against known-good baselines and flags divergence.",
    },
    "MCP02": {
        "name": "Excessive Agency",
        "what": "The AI takes actions beyond its authorized scope -- calling tools it shouldn't, escalating privileges.",
        "risk": "An unconstrained agent can delete files, access private APIs, or make unauthorized purchases.",
        "response": "InsAIts monitors tool call frequency and argument patterns, alerting on scope creep.",
    },
    "MCP03": {
        "name": "Data Exfiltration",
        "what": "Sensitive data (files, credentials, PII) is being extracted through tool calls to unauthorized destinations.",
        "risk": "Trade secrets, customer data, or credentials leave the system without the user knowing.",
        "response": "InsAIts tracks information flow across agents and flags unauthorized data movement.",
    },
    "MCP04": {
        "name": "Credential Exposure",
        "what": "API keys, passwords, tokens, or secrets are visible in tool inputs/outputs where they shouldn't be.",
        "risk": "Exposed credentials can be harvested from logs, tool outputs, or shared contexts.",
        "response": "InsAIts pattern-matches for common secret formats (AWS keys, tokens, passwords) in all tool I/O.",
    },
    "MCP05": {
        "name": "Unauthorized Access",
        "what": "The AI accesses files, APIs, or resources outside its declared permission scope.",
        "risk": "Agents can read sensitive config files, access internal APIs, or modify protected resources.",
        "response": "InsAIts monitors filesystem and API access patterns against declared agent scope.",
    },
    "MCP06": {
        "name": "Context Sharing",
        "what": "Private context from one agent leaks to another agent that shouldn't have it.",
        "risk": "Confidential data from one task becomes visible to unrelated agents or sessions.",
        "response": "InsAIts tracks cross-agent information flow and alerts on context boundary violations.",
    },
    "MCP07": {
        "name": "Multi-Hop Chains",
        "what": "One agent's fabricated output is consumed as fact by a second agent, creating a chain of hallucinations.",
        "risk": "A single hallucination cascades through multiple agents, compounding errors with each hop.",
        "response": "InsAIts detects citation chains and flags outputs that reference unverified upstream claims.",
    },
    "MCP08": {
        "name": "Audit Trails",
        "what": "Tool outputs are truncated or incomplete, making it impossible to audit what actually happened.",
        "risk": "Security teams cannot reconstruct what an agent did, making incident response impossible.",
        "response": "InsAIts flags truncated responses and ensures all tool calls are fully logged.",
    },
    "MCP09": {
        "name": "Shadow Servers",
        "what": "The AI communicates with undeclared external endpoints -- MCP servers the user didn't authorize.",
        "risk": "Data flows to unknown third parties; backdoor communication channels bypass security controls.",
        "response": "InsAIts monitors for URL patterns and external endpoint references in tool outputs.",
    },
    "MCP10": {
        "name": "Data Leakage",
        "what": "Sensitive information leaks across agent boundaries through shared context or tool responses.",
        "risk": "PII, business logic, or internal data becomes visible to agents or users who shouldn't see it.",
        "response": "InsAIts monitors data flow patterns and flags cross-boundary information leaks.",
    },
    "ASI01": {
        "name": "Goal Hijacking",
        "what": "An attacker changes what the AI is trying to accomplish -- the AI's goal is silently redirected.",
        "risk": "The agent appears to work normally but is pursuing an attacker-controlled objective.",
        "response": "InsAIts detects contradictions between stated goals and actual agent behavior.",
    },
    "ASI02": {
        "name": "Prompt Manipulation",
        "what": "The system prompt or context is modified to change the AI's behavior without the user knowing.",
        "risk": "Safety instructions, role definitions, or task boundaries can be overwritten by injected content.",
        "response": "InsAIts monitors for semantic drift between the original system prompt and current context.",
    },
    "ASI03": {
        "name": "Memory Poisoning",
        "what": "False information is injected into the AI's memory/context, degrading its accuracy over time.",
        "risk": "The agent's reliability degrades silently -- it makes increasingly wrong decisions based on bad data.",
        "response": "InsAIts tracks confidence erosion patterns across conversation turns.",
    },
    "ASI06": {
        "name": "Data Exposure",
        "what": "The AI fabricates citations, URLs, or references that don't exist -- phantom sources.",
        "risk": "Users trust fabricated references, leading to decisions based on non-existent evidence.",
        "response": "InsAIts flags phantom citations and unverifiable references in agent outputs.",
    },
    "ASI07": {
        "name": "Inter-Agent Abuse",
        "what": "Agents develop shorthand or coded communication that humans can't audit or understand.",
        "risk": "Agent-to-agent communication becomes opaque, bypassing human oversight entirely.",
        "response": "InsAIts detects emergent shorthand patterns and flags non-human-readable communication.",
    },
    "ASI08": {
        "name": "Cascading Failures",
        "what": "Uncertainty markers (partial, estimated, truncated) silently dropped by downstream agents, or one agent's error cascades through the system.",
        "risk": "Uncertain data presented as definitive -- decisions based on 'approximately 50' treated as 'exactly 50'. Minor errors amplify across multi-agent pipelines.",
        "response": "InsAIts tracks uncertainty markers across messages, flags certainty promotions (uncertain->certain without evidence), qualifier stripping, and error propagation chains.",
    },
    "ASI09": {
        "name": "Rogue Agents",
        "what": "An agent acts outside its defined boundaries -- executing unauthorized actions autonomously.",
        "risk": "Agents take destructive or unauthorized actions without any human approval.",
        "response": "InsAIts monitors tool call patterns and flags agents operating outside their declared scope.",
    },
    "ASI10": {
        "name": "Governance Gaps",
        "what": "High-risk operations happen without required approval flows -- no human in the loop when there should be.",
        "risk": "Critical decisions (deployments, data deletion, external communication) happen without oversight.",
        "response": "InsAIts enforces approval flows for high-risk operations via circuit breaker controls.",
    },
}

# ---------------------------------------------------------------------------
# Detector -> anomaly type mapping (for insaits_cve_signatures integration)
# ---------------------------------------------------------------------------
DETECTOR_TO_ANOMALY: Dict[str, str] = {
    "ToolDescriptionDivergenceDetector": "tool_poisoning",
    "CredentialPatternDetector": "credential_exposure",
    "PromptInjectionDetector": "prompt_injection",
    "InformationFlowTracker": "information_flow_violation",
    "ContextCollapseDetector": "context_collapse",
    "HallucinationChainDetector": "hallucination_chain",
    "SemanticDriftDetector": "semantic_drift",
    "JargonDriftDetector": "jargon_drift",
    "BehavioralFingerprintDetector": "behavioral_fingerprint",
    "ToolCallFrequencyAnomalyDetector": "tool_call_frequency_anomaly",
    "ExfiltrationPatternDetector": "exfiltration",
    "IncompleteCodeDetector": "incomplete_code",
}

# ---------------------------------------------------------------------------
# Category mapping for distribution charts (dashboard)
# ---------------------------------------------------------------------------
CATEGORY_MAP: Dict[str, str] = {
    "tool_poisoning": "Security (OWASP MCP)",
    "prompt_injection": "Security (OWASP MCP)",
    "credential_exposure": "Security (OWASP MCP)",
    "information_flow_violation": "Security (OWASP MCP)",
    "hallucination_chain": "Hallucination",
    "phantom_citation": "Hallucination",
    "semantic_drift": "Semantic Drift",
    "jargon_drift": "Semantic Drift",
    "context_loss": "Semantic Drift",
    "context_collapse": "Semantic Drift",
    "blank_response": "Communication",
    "truncated_output": "Communication",
    "waiting_for_description": "Communication",
    "incomplete_code": "Communication",
    "repetition_loop": "Communication",
    "llm_fingerprint_mismatch": "Model Integrity",
    "behavioral_fingerprint": "Model Integrity",
    "confidence_collapse": "Model Integrity",
    "tool_description_divergence": "Model Integrity",
    # Hook-generated anomaly types
    "unauthorized_write": "Security (OWASP MCP)",
    "monitoring_gap": "Security (OWASP MCP)",
    "sensitive_file_access": "Security (OWASP MCP)",
    "file_thrashing": "Communication",
    "rogue_agent": "Security (OWASP MCP)",
    "data_exfiltration": "Security (OWASP MCP)",
    "unauthorized_access": "Security (OWASP MCP)",
    "governance_gap": "Security (OWASP MCP)",
    "memory_poisoning": "Security (OWASP MCP)",
    "shadow_server": "Security (OWASP MCP)",
    "exfiltration_pattern": "Security (OWASP MCP)",
    "entropy_covert_channel": "Security (OWASP MCP)",
    "agent_surrender": "Model Integrity",
    "npc_behavior": "Model Integrity",
    "blame_shift": "Model Integrity",
    "user_frustration": "Communication",
    "ask_user_forced": "Security (OWASP MCP)",
    "ask_user_suggested": "Security (OWASP MCP)",
    "uncertainty_propagation": "Semantic Drift",
    "shorthand_emergence": "Semantic Drift",
    "confidence_erosion": "Model Integrity",
    # Collector/Guardian-generated event types
    "loop_detected": "Communication",
    "retry_budget_exceeded": "Model Integrity",
    "replay_rate_high": "Model Integrity",
    "urgent_intervention": "Security (OWASP MCP)",
}

CATEGORY_COLORS: Dict[str, str] = {
    "Security (OWASP MCP)": "#ff2d55",
    "Hallucination": "#ffaa00",
    "Semantic Drift": "#00d4ff",
    "Communication": "#9d4edd",
    "Model Integrity": "#00ff88",
}

CATEGORY_ORDER: List[str] = [
    "Security (OWASP MCP)",
    "Hallucination",
    "Semantic Drift",
    "Communication",
    "Model Integrity",
]


# ---------------------------------------------------------------------------
# Dynamic enrichment from insaits_cve_signatures (optional package)
# ---------------------------------------------------------------------------
# These are populated at import time if the package is available,
# otherwise they stay as empty dicts / copies of the fallback.

OWASP_CODES: Dict[str, str] = {}
ANOMALY_TO_OWASP: Dict[str, List[str]] = {}
ANOMALY_TO_CVES: Dict[str, List[str]] = {}
OWASP_DESCRIPTIONS: Dict[str, str] = {}
CVE_SIGNATURES_AVAILABLE: bool = False

try:
    from insaits_cve_signatures import (
        OWASP_MCP_TOP10,
        OWASP_AGENTIC_TOP10,
        ATTACK_PATTERNS,
        CVE_REGISTRY,
        get_owasp_coverage,  # noqa: F401
    )
    CVE_SIGNATURES_AVAILABLE = True

    # Build anomaly_type -> list of OWASP IDs from attack patterns
    for _pat in ATTACK_PATTERNS:
        if _pat.insaits_detector and _pat.insaits_detector in DETECTOR_TO_ANOMALY:
            _atype = DETECTOR_TO_ANOMALY[_pat.insaits_detector]
            if _atype not in ANOMALY_TO_OWASP:
                ANOMALY_TO_OWASP[_atype] = []
            for _oid in _pat.owasp_ids:
                if _oid not in ANOMALY_TO_OWASP[_atype]:
                    ANOMALY_TO_OWASP[_atype].append(_oid)

    # Build anomaly_type -> primary OWASP code (first one)
    for _atype, _oids in ANOMALY_TO_OWASP.items():
        OWASP_CODES[_atype] = _oids[0] if _oids else ""

    # Also add OWASP risk entries that map via detector
    for _risk in OWASP_MCP_TOP10 + OWASP_AGENTIC_TOP10:
        if _risk.insaits_detector and _risk.insaits_detector in DETECTOR_TO_ANOMALY:
            _atype = DETECTOR_TO_ANOMALY[_risk.insaits_detector]
            if _atype not in OWASP_CODES:
                OWASP_CODES[_atype] = _risk.risk_id

    # Build anomaly_type -> CVE references from CVE_REGISTRY
    for _cve in CVE_REGISTRY:
        if _cve.insaits_detector and _cve.insaits_detector in DETECTOR_TO_ANOMALY:
            _atype = DETECTOR_TO_ANOMALY[_cve.insaits_detector]
            if _atype not in ANOMALY_TO_CVES:
                ANOMALY_TO_CVES[_atype] = []
            if _cve.cve_id not in ANOMALY_TO_CVES[_atype]:
                ANOMALY_TO_CVES[_atype].append(_cve.cve_id)

    # Build OWASP code -> description from OWASP risks
    for _risk in OWASP_MCP_TOP10 + OWASP_AGENTIC_TOP10:
        OWASP_DESCRIPTIONS[_risk.risk_id] = _risk.name

except ImportError:
    CVE_SIGNATURES_AVAILABLE = False
    OWASP_CODES = dict(OWASP_CODES_FALLBACK)
    # ANOMALY_TO_OWASP, ANOMALY_TO_CVES, OWASP_DESCRIPTIONS stay empty

# Always merge OWASP_CODES_FALLBACK into OWASP_CODES so hook-generated
# anomaly types (unauthorized_write, monitoring_gap, etc.) are always
# present, regardless of whether insaits_cve_signatures was loaded.
for _atype, _code in OWASP_CODES_FALLBACK.items():
    if _atype not in OWASP_CODES:
        OWASP_CODES[_atype] = _code
