"""
MCP Plugin: Platform Operations — wires oroboros, notifications, hardening, auto_dispatch.

Exposes self-improvement, notification management, input validation,
rate limiting, and auto-dispatch as MCP tools.
"""

from mcp.types import TextContent


def get_tools():
    """Return tool definitions for this plugin."""
    return [
        # ── Oroboros (Phase 22) ────────────────────────────────────
        {
            "name": "broker_oroboros_scan",
            "description": "Scan the codebase for improvement opportunities (untested modules, TODOs, security issues).",
            "inputSchema": {
                "type": "object",
                "properties": {
                    "source_dir": {"type": "string", "default": "src/brynq", "description": "Directory to scan"},
                },
            },
        },
        {
            "name": "broker_oroboros_run",
            "description": "Run a full Oroboros self-improvement cycle: scan codebase, filter by severity, post tasks.",
            "inputSchema": {
                "type": "object",
                "properties": {
                    "max_tasks": {"type": "integer", "default": 5},
                    "min_severity": {"type": "string", "default": "medium"},
                },
            },
        },
        {
            "name": "broker_oroboros_stats",
            "description": "Get Oroboros evolution statistics — how many self-improvement cycles completed.",
            "inputSchema": {"type": "object", "properties": {}},
        },
        # ── Notifications (Phase 29) ───────────────────────────────
        {
            "name": "broker_notify",
            "description": "Send a notification to an agent.",
            "inputSchema": {
                "type": "object",
                "properties": {
                    "target_agent_id": {"type": "string", "description": "Agent to notify"},
                    "event_type": {"type": "string", "description": "Event type (task_match, follow_new, etc.)"},
                    "title": {"type": "string"},
                    "body": {"type": "string"},
                    "priority": {"type": "string", "default": "normal"},
                },
                "required": ["target_agent_id", "event_type", "title", "body"],
            },
        },
        {
            "name": "broker_notification_prefs",
            "description": "Get or set notification preferences for an agent.",
            "inputSchema": {
                "type": "object",
                "properties": {
                    "agent_id": {"type": "string"},
                    "mute_event": {"type": "string", "description": "Event type to mute (optional)"},
                    "unmute_event": {"type": "string", "description": "Event type to unmute (optional)"},
                },
                "required": ["agent_id"],
            },
        },
        {
            "name": "broker_notification_stats",
            "description": "Get notification delivery statistics.",
            "inputSchema": {
                "type": "object",
                "properties": {
                    "agent_id": {"type": "string", "description": "Filter by agent (optional)"},
                },
            },
        },
        # ── Auto-Dispatch (Phase 31) ───────────────────────────────
        {
            "name": "broker_dispatch_all",
            "description": "Auto-dispatch all pending tasks to the best matching agents.",
            "inputSchema": {"type": "object", "properties": {}},
        },
        {
            "name": "broker_pull_task",
            "description": "Pull the next best-matching task from the queue for this agent.",
            "inputSchema": {
                "type": "object",
                "properties": {
                    "skills": {
                        "type": "array",
                        "items": {"type": "string"},
                        "description": "Agent's skills for matching",
                    },
                    "min_priority": {"type": "string", "default": "low"},
                },
            },
        },
        {
            "name": "broker_dispatch_stats",
            "description": "Get auto-dispatch statistics.",
            "inputSchema": {"type": "object", "properties": {}},
        },
        {
            "name": "broker_rebalance",
            "description": "Rebalance stuck tasks — requeue tasks accepted but not completed within timeout.",
            "inputSchema": {
                "type": "object",
                "properties": {
                    "stuck_minutes": {"type": "integer", "default": 30},
                },
            },
        },
        # ── Hardening (Phase 30) ───────────────────────────────────
        {
            "name": "broker_health_deep",
            "description": "Run a deep health check across all platform subsystems.",
            "inputSchema": {"type": "object", "properties": {}},
        },
        {
            "name": "broker_validate_input",
            "description": "Sanitize and validate text input. Returns clean text and warnings.",
            "inputSchema": {
                "type": "object",
                "properties": {
                    "text": {"type": "string"},
                    "max_length": {"type": "integer", "default": 5000},
                },
                "required": ["text"],
            },
        },
    ]


async def handle_tool(name: str, args: dict) -> list[TextContent]:
    """Handle tool calls for this plugin."""
    import asyncio
    import json

    # ── Oroboros ────────────────────────────────────────────────
    if name == "broker_oroboros_scan":
        from brynq.oroboros import scan_codebase
        result = await asyncio.to_thread(scan_codebase, args.get("source_dir", "src/brynq"))
        summary = f"Scan complete: {result.get('total_findings', 0)} findings across {result.get('total_modules', 0)} modules."
        if result.get("findings_by_category"):
            summary += "\nBy category: " + ", ".join(f"{k}: {v}" for k, v in result["findings_by_category"].items())
        return [TextContent(type="text", text=summary)]

    elif name == "broker_oroboros_run":
        from brynq.oroboros import run_oroboros_cycle
        result = await asyncio.to_thread(
            run_oroboros_cycle,
            max_tasks=args.get("max_tasks", 5),
            min_severity=args.get("min_severity", "medium"),
        )
        return [TextContent(type="text", text=f"Oroboros cycle: {result.get('tasks_posted', 0)} tasks posted from {result.get('filtered_findings', 0)} findings.")]

    elif name == "broker_oroboros_stats":
        from brynq.oroboros import get_evolution_stats
        stats = await asyncio.to_thread(get_evolution_stats)
        return [TextContent(type="text", text=json.dumps(stats, indent=2))]

    # ── Notifications ──────────────────────────────────────────
    elif name == "broker_notify":
        from brynq.notifications import notify
        result = await asyncio.to_thread(
            notify, args["target_agent_id"], args["event_type"],
            args["title"], args["body"], args.get("priority", "normal"),
        )
        return [TextContent(type="text", text=f"Notification {result.get('status', 'sent')}: {result.get('notification_id', '')}")]

    elif name == "broker_notification_prefs":
        from brynq.notifications import get_preferences, mute_event, unmute_event
        aid = args["agent_id"]
        if args.get("mute_event"):
            await asyncio.to_thread(mute_event, aid, args["mute_event"])
            return [TextContent(type="text", text=f"Muted {args['mute_event']} for {aid}")]
        if args.get("unmute_event"):
            await asyncio.to_thread(unmute_event, aid, args["unmute_event"])
            return [TextContent(type="text", text=f"Unmuted {args['unmute_event']} for {aid}")]
        prefs = await asyncio.to_thread(get_preferences, aid)
        return [TextContent(type="text", text=json.dumps(prefs, indent=2))]

    elif name == "broker_notification_stats":
        from brynq.notifications import get_notification_stats
        stats = await asyncio.to_thread(get_notification_stats, args.get("agent_id"))
        return [TextContent(type="text", text=json.dumps(stats, indent=2))]

    # ── Auto-Dispatch ──────────────────────────────────────────
    elif name == "broker_dispatch_all":
        from brynq.auto_dispatch import dispatch_all_pending
        result = await asyncio.to_thread(dispatch_all_pending)
        return [TextContent(type="text", text=f"Dispatched: {result.get('dispatched', 0)}, Escalated: {result.get('escalated', 0)}, Skipped: {result.get('skipped', 0)}")]

    elif name == "broker_pull_task":
        from brynq.auto_dispatch import pull_next_task
        from brynq.server import SESSION_ID
        task = await asyncio.to_thread(
            pull_next_task, SESSION_ID,
            args.get("skills"), args.get("min_priority", "low"),
        )
        if task:
            return [TextContent(type="text", text=f"Pulled task: [{task['task_id']}] {task.get('title', '')} ({task.get('priority', 'normal')})")]
        return [TextContent(type="text", text="No matching tasks in queue.")]

    elif name == "broker_dispatch_stats":
        from brynq.auto_dispatch import get_dispatch_stats
        stats = await asyncio.to_thread(get_dispatch_stats)
        return [TextContent(type="text", text=json.dumps(stats, indent=2))]

    elif name == "broker_rebalance":
        from brynq.auto_dispatch import rebalance_stuck_tasks
        result = await asyncio.to_thread(rebalance_stuck_tasks, args.get("stuck_minutes", 30))
        return [TextContent(type="text", text=f"Rebalanced: {result.get('requeued', 0)} stuck tasks requeued.")]

    # ── Hardening ──────────────────────────────────────────────
    elif name == "broker_health_deep":
        from brynq.hardening import deep_health_check
        result = await asyncio.to_thread(deep_health_check)
        return [TextContent(type="text", text=f"Health: {result['status']} ({result['healthy_count']}/{result['subsystem_count']} healthy)")]

    elif name == "broker_validate_input":
        from brynq.hardening import sanitize_text
        clean, warnings = sanitize_text(args["text"], args.get("max_length", 5000))
        if warnings:
            return [TextContent(type="text", text=f"Warnings: {'; '.join(warnings)}\nClean text: {clean[:200]}")]
        return [TextContent(type="text", text=f"Input is clean ({len(clean)} chars).")]

    return [TextContent(type="text", text=f"Unknown tool: {name}")]
