"""
Great Wiring Sprint: Security MCP Plugin.

Wires dark-matter security modules into MCP:
  - vault.py — credential storage (BYOK keys)
  - compliance.py — policy enforcement & audit
  - audit_trail.py (Phase 34) — immutable hash-chained audit log
"""

import asyncio
import json

from mcp.types import TextContent, Tool, ToolAnnotations

_SAFE_WRITE = ToolAnnotations(
    readOnlyHint=False, destructiveHint=False,
    idempotentHint=False, openWorldHint=False,
)
_SAFE_READ = ToolAnnotations(
    readOnlyHint=True, destructiveHint=False,
    idempotentHint=True, openWorldHint=False,
)
_DESTRUCTIVE = ToolAnnotations(
    readOnlyHint=False, destructiveHint=True,
    idempotentHint=False, openWorldHint=False,
)

# ── Tool Definitions ──────────────────────────────────────────────────────

TOOLS = [
    # ── Vault ──
    Tool(
        name="vault_store",
        description="Store an API key or credential in the local vault. Keys are stored per-platform (e.g., 'openai', 'anthropic'). BYOK only.",
        inputSchema={
            "type": "object",
            "properties": {
                "platform": {"type": "string", "description": "Platform name (e.g., 'openai', 'anthropic', 'google')"},
                "key": {"type": "string", "description": "The API key or credential value"},
            },
            "required": ["platform", "key"],
        },
        annotations=_SAFE_WRITE,
    ),
    Tool(
        name="vault_get",
        description="Retrieve a stored credential by platform name. Returns masked preview for safety.",
        inputSchema={
            "type": "object",
            "properties": {
                "platform": {"type": "string", "description": "Platform name to look up"},
            },
            "required": ["platform"],
        },
        annotations=_SAFE_READ,
    ),
    Tool(
        name="vault_list",
        description="List all platforms with stored credentials (keys are NOT shown).",
        inputSchema={"type": "object", "properties": {}},
        annotations=_SAFE_READ,
    ),
    Tool(
        name="vault_delete",
        description="Delete a stored credential by platform name.",
        inputSchema={
            "type": "object",
            "properties": {
                "platform": {"type": "string"},
            },
            "required": ["platform"],
        },
        annotations=_DESTRUCTIVE,
    ),

    # ── Compliance ──
    Tool(
        name="compliance_log_action",
        description="Log an agent action for compliance tracking.",
        inputSchema={
            "type": "object",
            "properties": {
                "action_type": {"type": "string", "description": "Action type (e.g., 'file_edit', 'task_create', 'deploy')"},
                "details": {"type": "object", "description": "Action details (freeform JSON)"},
                "channel": {"type": "string", "description": "Channel where action occurred"},
            },
            "required": ["action_type", "details"],
        },
        annotations=_SAFE_WRITE,
    ),
    Tool(
        name="compliance_define_policy",
        description="Define a compliance policy with rules for what actions are allowed/denied.",
        inputSchema={
            "type": "object",
            "properties": {
                "name": {"type": "string", "description": "Policy name"},
                "description": {"type": "string"},
                "rule_type": {"type": "string", "description": "allow, deny, or require_approval"},
                "conditions": {"type": "object", "description": "Conditions for the policy to apply"},
            },
            "required": ["name", "description", "rule_type"],
        },
        annotations=_SAFE_WRITE,
    ),
    Tool(
        name="compliance_list_policies",
        description="List all compliance policies.",
        inputSchema={
            "type": "object",
            "properties": {
                "active_only": {"type": "boolean", "default": True},
            },
        },
        annotations=_SAFE_READ,
    ),
    Tool(
        name="compliance_check",
        description="Check if a proposed action complies with all active policies.",
        inputSchema={
            "type": "object",
            "properties": {
                "action_type": {"type": "string"},
                "details": {"type": "object"},
            },
            "required": ["action_type", "details"],
        },
        annotations=_SAFE_READ,
    ),
    Tool(
        name="compliance_report",
        description="Generate a compliance report for the last N hours.",
        inputSchema={
            "type": "object",
            "properties": {
                "hours": {"type": "integer", "default": 24, "description": "Lookback window in hours"},
            },
        },
        annotations=_SAFE_READ,
    ),

    # ── Audit Trail ──
    Tool(
        name="audit_log_event",
        description="Log an immutable, hash-chained audit event. Each entry is cryptographically linked to the previous one.",
        inputSchema={
            "type": "object",
            "properties": {
                "action": {"type": "string", "description": "Action performed (e.g., 'file_edit', 'deploy', 'config_change')"},
                "actor_id": {"type": "string", "description": "Who performed the action (session ID)"},
                "actor_name": {"type": "string", "description": "Human-readable actor name"},
                "target": {"type": "string", "description": "What was acted upon (file path, task ID, etc.)"},
                "detail": {"type": "string", "description": "Additional context"},
            },
            "required": ["action", "actor_id", "actor_name"],
        },
        annotations=_SAFE_WRITE,
    ),
    Tool(
        name="audit_verify_chain",
        description="Verify the integrity of the audit trail hash chain. Detects any tampering.",
        inputSchema={"type": "object", "properties": {}},
        annotations=_SAFE_READ,
    ),
    Tool(
        name="audit_get_events",
        description="Query the audit trail with optional filters.",
        inputSchema={
            "type": "object",
            "properties": {
                "action": {"type": "string", "description": "Filter by action type"},
                "actor_id": {"type": "string", "description": "Filter by actor"},
                "limit": {"type": "integer", "default": 50},
            },
        },
        annotations=_SAFE_READ,
    ),
    Tool(
        name="audit_actor_history",
        description="Get all audit events for a specific actor.",
        inputSchema={
            "type": "object",
            "properties": {
                "actor_id": {"type": "string"},
                "limit": {"type": "integer", "default": 50},
            },
            "required": ["actor_id"],
        },
        annotations=_SAFE_READ,
    ),
    Tool(
        name="audit_suspicious",
        description="Detect suspicious activity patterns in the audit trail.",
        inputSchema={
            "type": "object",
            "properties": {
                "hours": {"type": "integer", "default": 24},
            },
        },
        annotations=_SAFE_READ,
    ),
    Tool(
        name="audit_stats",
        description="Get audit trail statistics: event counts, top actors, top actions.",
        inputSchema={"type": "object", "properties": {}},
        annotations=_SAFE_READ,
    ),
]


# ── Handlers ──────────────────────────────────────────────────────────────

# -- Vault --

async def _handle_vault_store(args: dict) -> list[TextContent]:
    from brynq.vault import vault_store
    try:
        await asyncio.to_thread(vault_store, platform=args["platform"], key=args["key"])
        return [TextContent(type="text", text=f"Credential stored for platform: {args['platform']}")]
    except Exception as e:
        return [TextContent(type="text", text=f"Error: {e}")]


async def _handle_vault_get(args: dict) -> list[TextContent]:
    from brynq.vault import vault_get
    try:
        result = await asyncio.to_thread(vault_get, platform=args["platform"])
        if result is None:
            return [TextContent(type="text", text=f"No credential found for platform: {args['platform']}")]
        # Mask the key for safety
        key = result if isinstance(result, str) else str(result)
        masked = key[:4] + "..." + key[-4:] if len(key) > 8 else "****"
        return [TextContent(type="text", text=f"Credential for {args['platform']}: {masked}")]
    except Exception as e:
        return [TextContent(type="text", text=f"Error: {e}")]


async def _handle_vault_list(args: dict) -> list[TextContent]:
    from brynq.vault import vault_list
    try:
        platforms = await asyncio.to_thread(vault_list)
        if not platforms:
            return [TextContent(type="text", text="No credentials stored in vault.")]
        if isinstance(platforms, list):
            lines = [f"Stored credentials ({len(platforms)} platforms):"]
            for p in platforms:
                if isinstance(p, dict):
                    lines.append(f"  {p.get('platform', '?')}")
                else:
                    lines.append(f"  {p}")
            return [TextContent(type="text", text="\n".join(lines))]
        return [TextContent(type="text", text=json.dumps(platforms, indent=2, default=str))]
    except Exception as e:
        return [TextContent(type="text", text=f"Error: {e}")]


async def _handle_vault_delete(args: dict) -> list[TextContent]:
    from brynq.vault import vault_delete
    try:
        await asyncio.to_thread(vault_delete, platform=args["platform"])
        return [TextContent(type="text", text=f"Credential deleted for platform: {args['platform']}")]
    except Exception as e:
        return [TextContent(type="text", text=f"Error: {e}")]


# -- Compliance --

async def _handle_compliance_log_action(args: dict) -> list[TextContent]:
    from brynq.compliance import log_action
    try:
        result = await asyncio.to_thread(
            log_action,
            action_type=args["action_type"],
            details=args["details"],
            channel=args.get("channel"),
        )
        return [TextContent(type="text", text=f"Action logged: {args['action_type']}")]
    except Exception as e:
        return [TextContent(type="text", text=f"Error: {e}")]


async def _handle_compliance_define_policy(args: dict) -> list[TextContent]:
    from brynq.compliance import define_policy
    try:
        policy = await asyncio.to_thread(
            define_policy,
            name=args["name"],
            description=args["description"],
            rule_type=args["rule_type"],
            rule_config=args.get("conditions", {}),
        )
        return [TextContent(
            type="text",
            text=f"Policy '{args['name']}' defined (type: {args['rule_type']})",
        )]
    except Exception as e:
        return [TextContent(type="text", text=f"Error: {e}")]


async def _handle_compliance_list_policies(args: dict) -> list[TextContent]:
    from brynq.compliance import list_policies
    try:
        policies = await asyncio.to_thread(
            list_policies, active_only=args.get("active_only", True),
        )
        if not policies:
            return [TextContent(type="text", text="No policies defined.")]
        lines = [f"Compliance policies ({len(policies)}):"]
        for p in policies:
            lines.append(f"  [{p.get('rule_type', '?').upper()}] {p['name']}: {p.get('description', '')[:80]}")
        return [TextContent(type="text", text="\n".join(lines))]
    except Exception as e:
        return [TextContent(type="text", text=f"Error: {e}")]


async def _handle_compliance_check(args: dict) -> list[TextContent]:
    from brynq.compliance import check_compliance
    try:
        result = await asyncio.to_thread(
            check_compliance,
            action_type=args["action_type"],
            details=args["details"],
        )
        if isinstance(result, dict):
            if result.get("compliant", True):
                return [TextContent(type="text", text=f"COMPLIANT: Action '{args['action_type']}' is allowed.")]
            violations = result.get("violations", [])
            lines = [f"NON-COMPLIANT: Action '{args['action_type']}' violates {len(violations)} policy(ies):"]
            for v in violations:
                lines.append(f"  - {v}")
            return [TextContent(type="text", text="\n".join(lines))]
        return [TextContent(type="text", text=json.dumps(result, indent=2, default=str))]
    except Exception as e:
        return [TextContent(type="text", text=f"Error: {e}")]


async def _handle_compliance_report(args: dict) -> list[TextContent]:
    from brynq.compliance import get_compliance_report
    try:
        report = await asyncio.to_thread(
            get_compliance_report, hours=args.get("hours", 24),
        )
        return [TextContent(type="text", text=json.dumps(report, indent=2, default=str))]
    except Exception as e:
        return [TextContent(type="text", text=f"Error: {e}")]


# -- Audit Trail --

async def _handle_audit_log_event(args: dict) -> list[TextContent]:
    from brynq.audit_trail import log_event
    try:
        event = await asyncio.to_thread(
            log_event,
            action=args["action"],
            actor_id=args["actor_id"],
            actor_name=args["actor_name"],
            target=args.get("target"),
            details={"detail": args.get("detail", "")},
        )
        return [TextContent(type="text", text=f"Audit event logged: {args['action']} by {args['actor_name']}")]
    except Exception as e:
        return [TextContent(type="text", text=f"Error: {e}")]


async def _handle_audit_verify_chain(args: dict) -> list[TextContent]:
    from brynq.audit_trail import verify_chain
    try:
        result = await asyncio.to_thread(verify_chain)
        if isinstance(result, dict):
            if result.get("valid", False):
                return [TextContent(type="text", text=f"Audit chain VALID. {result.get('events_checked', '?')} events verified.")]
            return [TextContent(type="text", text=f"CHAIN INTEGRITY FAILURE: {result.get('error', 'unknown')}")]
        return [TextContent(type="text", text=f"Chain verification: {result}")]
    except Exception as e:
        return [TextContent(type="text", text=f"Error: {e}")]


async def _handle_audit_get_events(args: dict) -> list[TextContent]:
    from brynq.audit_trail import get_events
    try:
        events = await asyncio.to_thread(
            get_events,
            action=args.get("action"),
            actor_id=args.get("actor_id"),
            limit=args.get("limit", 50),
        )
        if not events:
            return [TextContent(type="text", text="No audit events found.")]
        lines = [f"Audit events ({len(events)}):"]
        for e in events[-20:]:
            ts = e.get("timestamp", "")[:19]
            lines.append(f"  [{ts}] {e.get('actor_name', '?')}: {e.get('action', '?')} -> {e.get('target', 'N/A')}")
        return [TextContent(type="text", text="\n".join(lines))]
    except Exception as e:
        return [TextContent(type="text", text=f"Error: {e}")]


async def _handle_audit_actor_history(args: dict) -> list[TextContent]:
    from brynq.audit_trail import get_actor_history
    try:
        events = await asyncio.to_thread(
            get_actor_history,
            actor_id=args["actor_id"],
            limit=args.get("limit", 50),
        )
        if not events:
            return [TextContent(type="text", text=f"No audit events for actor '{args['actor_id']}'.")]
        lines = [f"Actor history for '{args['actor_id']}' ({len(events)} events):"]
        for e in events:
            ts = e.get("timestamp", "")[:19]
            lines.append(f"  [{ts}] {e.get('action', '?')} -> {e.get('target', 'N/A')}")
        return [TextContent(type="text", text="\n".join(lines))]
    except Exception as e:
        return [TextContent(type="text", text=f"Error: {e}")]


async def _handle_audit_suspicious(args: dict) -> list[TextContent]:
    from brynq.audit_trail import get_suspicious_activity
    try:
        result = await asyncio.to_thread(
            get_suspicious_activity, hours=args.get("hours", 24),
        )
        if not result:
            return [TextContent(type="text", text="No suspicious activity detected.")]
        return [TextContent(type="text", text=json.dumps(result, indent=2, default=str))]
    except Exception as e:
        return [TextContent(type="text", text=f"Error: {e}")]


async def _handle_audit_stats(args: dict) -> list[TextContent]:
    from brynq.audit_trail import get_stats
    try:
        stats = await asyncio.to_thread(get_stats)
        return [TextContent(type="text", text=json.dumps(stats, indent=2, default=str))]
    except Exception as e:
        return [TextContent(type="text", text=f"Error: {e}")]


# ── Handler Registry ─────────────────────────────────────────────────────

HANDLERS = {
    # Vault
    "vault_store": _handle_vault_store,
    "vault_get": _handle_vault_get,
    "vault_list": _handle_vault_list,
    "vault_delete": _handle_vault_delete,
    # Compliance
    "compliance_log_action": _handle_compliance_log_action,
    "compliance_define_policy": _handle_compliance_define_policy,
    "compliance_list_policies": _handle_compliance_list_policies,
    "compliance_check": _handle_compliance_check,
    "compliance_report": _handle_compliance_report,
    # Audit Trail
    "audit_log_event": _handle_audit_log_event,
    "audit_verify_chain": _handle_audit_verify_chain,
    "audit_get_events": _handle_audit_get_events,
    "audit_actor_history": _handle_audit_actor_history,
    "audit_suspicious": _handle_audit_suspicious,
    "audit_stats": _handle_audit_stats,
}
