"""Phase 79: MCP Microservice — Capability Registry & Delegation.

Agent capability registration, discovery, and automatic task routing.
Also includes cron scheduling and cross-project messaging.
"""

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)

TOOLS = [
    Tool(
        name="broker_register_capability",
        description="Register a capability (skill) for your session so tasks can be automatically routed to you.",
        inputSchema={
            "type": "object",
            "properties": {
                "capability": {"type": "string", "description": "Name of the capability (e.g., 'code_review')"},
                "description": {"type": "string", "description": "Detailed description of what you can do"},
            },
            "required": ["capability", "description"],
        },
        annotations=_SAFE_WRITE,
    ),
    Tool(
        name="broker_list_capabilities",
        description="List all capabilities registered by all active agents in the swarm.",
        inputSchema={"type": "object", "properties": {}},
        annotations=_SAFE_READ,
    ),
    Tool(
        name="broker_find_agent",
        description="Find the best agent for a task. Searches by capability name or free-text query. Returns ranked results with load balancing scores.",
        inputSchema={
            "type": "object",
            "properties": {
                "capability": {"type": "string", "description": "Capability name to search for (e.g., 'code_review')"},
                "query": {"type": "string", "description": "Free-text search across capability names and descriptions"},
                "platform": {"type": "string", "description": "Filter by platform (e.g., 'claude', 'gemini')"},
            },
        },
        annotations=_SAFE_READ,
    ),
    Tool(
        name="broker_delegate",
        description="Auto-route a task to the best available agent with the required capability. The broker finds the right agent, posts the task, and notifies them.",
        inputSchema={
            "type": "object",
            "properties": {
                "title": {"type": "string", "description": "Short task title"},
                "description": {"type": "string", "description": "Detailed task instructions"},
                "required_capability": {"type": "string", "description": "The capability needed (e.g., 'code_review', 'test_writing')"},
                "channel": {"type": "string", "description": "Channel to post task in", "default": "tasks"},
                "priority": {"type": "string", "description": "low, normal, high, or urgent", "default": "normal"},
            },
            "required": ["title", "description", "required_capability"],
        },
        annotations=_SAFE_WRITE,
    ),
    # -- Cross-project --
    Tool(
        name="broker_cross_project_post",
        description="Send a message directly to a channel in another project's Brynq broker. Uses the ~/.brynq/registry.json to discover the target broker.",
        inputSchema={
            "type": "object",
            "properties": {
                "target_project": {"type": "string", "description": "The name of the target project directory (e.g., 'z-dte-pro')"},
                "channel": {"type": "string", "description": "The channel to post to in the target project", "default": "general"},
                "message": {"type": "string", "description": "The message to send"},
            },
            "required": ["target_project", "message"],
        },
        annotations=_SAFE_WRITE,
    ),
    # -- Cron --
    Tool(
        name="broker_register_cron",
        description="Register a recurring task that the broker will automatically execute at a given interval.",
        inputSchema={
            "type": "object",
            "properties": {
                "name": {"type": "string", "description": "Name of the scheduled task"},
                "channel": {"type": "string", "description": "Channel to post the task in"},
                "cron_expr": {"type": "string", "description": "Interval in seconds (e.g., '300' for 5 mins)"},
                "message": {"type": "string", "description": "The message/task to post"},
            },
            "required": ["name", "channel", "cron_expr", "message"],
        },
        annotations=_SAFE_WRITE,
    ),
    Tool(
        name="broker_list_cron",
        description="List all active scheduled cron tasks.",
        inputSchema={"type": "object", "properties": {}},
        annotations=_SAFE_READ,
    ),
    Tool(
        name="broker_remove_cron",
        description="Remove a scheduled cron task by its job ID.",
        inputSchema={
            "type": "object",
            "properties": {"job_id": {"type": "string", "description": "The job ID to remove"}},
            "required": ["job_id"],
        },
        annotations=_SAFE_WRITE,
    ),
]


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


async def _handle_register_capability(args: dict) -> list[TextContent]:
    from brynq import capability
    from brynq.server import SESSION_ID, SESSION_NAME, PLATFORM
    try:
        await asyncio.to_thread(
            capability.register_capability,
            session_id=SESSION_ID,
            session_name=SESSION_NAME,
            platform=PLATFORM,
            capability=args.get("capability", ""),
            description=args.get("description", ""),
        )
        return [TextContent(type="text", text=f"Capability '{args.get('capability')}' registered successfully. You can now receive routed tasks for this skill.")]
    except Exception as e:
        return [TextContent(type="text", text=f"Error registering capability: {str(e)}")]


async def _handle_list_capabilities(args: dict) -> list[TextContent]:
    from brynq import capability
    try:
        caps = await asyncio.to_thread(capability.list_capabilities)
        if not caps:
            return [TextContent(type="text", text="No active capabilities registered in the swarm.")]
        lines = ["Active Swarm Capabilities:"]
        for c in caps:
            lines.append(f"  - [{c['capability']}] {c['session_name']}@{c['platform']}: {c['description']}")
        return [TextContent(type="text", text="\n".join(lines))]
    except Exception as e:
        return [TextContent(type="text", text=f"Error listing capabilities: {str(e)}")]


async def _handle_find_agent(args: dict) -> list[TextContent]:
    from brynq.capability import find_agents
    agents = await asyncio.to_thread(
        find_agents,
        capability=args.get("capability"),
        query=args.get("query"),
        platform=args.get("platform"),
    )
    if not agents:
        return [TextContent(type="text", text="No matching agents found")]
    lines = [f"Found {len(agents)} matching agent(s):"]
    for a in agents:
        lines.append(f"  {a['session_name']}@{a['platform']} — {a['capability']}: {a['description']}")
        lines.append(f"    score: {a['score']} | active tasks: {a['active_delegations']}")
    return [TextContent(type="text", text="\n".join(lines))]


async def _handle_delegate(args: dict) -> list[TextContent]:
    from brynq.capability import delegate_task
    title = args.get("title", "")
    description = args.get("description", "")
    required = args.get("required_capability", "")
    if not all([title, description, required]):
        return [TextContent(type="text", text="Error: title, description, and required_capability are all required")]
    result = await asyncio.to_thread(
        delegate_task,
        title=title,
        description=description,
        required_capability=required,
        channel=args.get("channel", "tasks"),
        priority=args.get("priority", "normal"),
    )
    if result.get("routed"):
        return [TextContent(type="text", text=f"Task delegated: [{result['task_id']}] '{title}'\n  Assigned to: {result['assigned_to']}@{result['assigned_platform']} (score: {result['match_score']})\n  Channel: #{result['channel']} | Priority: {result['priority']}")]
    return [TextContent(type="text", text=f"Task posted but NOT routed: [{result['task_id']}] '{title}'\n  Reason: {result.get('reason', 'unknown')}\n  Channel: #{result['channel']}")]


async def _handle_cross_project_post(args: dict) -> list[TextContent]:
    from brynq import cross_project
    from brynq.server import SESSION_ID, SESSION_NAME, PLATFORM
    target_project = args.get("target_project", "")
    channel = args.get("channel", "general")
    message = args.get("message", "")
    if not target_project or not message:
        return [TextContent(type="text", text="Error: target_project and message are required.")]
    success = await asyncio.to_thread(
        cross_project.post_cross_project,
        target_project=target_project,
        channel=channel,
        message=message,
        sender_session=SESSION_ID,
        sender_name=SESSION_NAME,
        platform=PLATFORM,
    )
    if success:
        return [TextContent(type="text", text=f"Successfully sent message to #{channel} in project '{target_project}'.")]
    return [TextContent(type="text", text=f"Failed to send message. Project '{target_project}' not found in registry ~/.brynq/registry.json.")]


async def _handle_register_cron(args: dict) -> list[TextContent]:
    from brynq import scheduler
    from brynq.server import SESSION_ID, SESSION_NAME, PLATFORM
    try:
        job_id = await asyncio.to_thread(
            scheduler.register_cron_task,
            name=args.get("name", "Task"),
            channel=args.get("channel", "general"),
            cron_expr=args.get("cron_expr", "300"),
            message=args.get("message", ""),
            session_id=SESSION_ID,
            session_name=SESSION_NAME,
            platform=PLATFORM,
        )
        return [TextContent(type="text", text=f"Cron task registered successfully. Job ID: {job_id}")]
    except Exception as e:
        return [TextContent(type="text", text=f"Error registering cron task: {str(e)}")]


async def _handle_list_cron(args: dict) -> list[TextContent]:
    from brynq import scheduler
    try:
        cron_tasks = await asyncio.to_thread(scheduler.list_cron_tasks)
        if not cron_tasks:
            return [TextContent(type="text", text="No active cron tasks found.")]
        lines = ["Active Cron Tasks:"]
        for t in cron_tasks:
            lines.append(f"  [{t['job_id']}] {t['name']} -> #{t['channel']} (Every {t['interval_secs']}s)")
        return [TextContent(type="text", text="\n".join(lines))]
    except Exception as e:
        return [TextContent(type="text", text=f"Error listing cron tasks: {str(e)}")]


async def _handle_remove_cron(args: dict) -> list[TextContent]:
    from brynq import scheduler
    try:
        success = await asyncio.to_thread(scheduler.remove_cron_task, args.get("job_id", ""))
        if success:
            return [TextContent(type="text", text="Cron task removed successfully.")]
        return [TextContent(type="text", text="Cron task not found.")]
    except Exception as e:
        return [TextContent(type="text", text=f"Error removing cron task: {str(e)}")]


HANDLERS = {
    "broker_register_capability": _handle_register_capability,
    "broker_list_capabilities": _handle_list_capabilities,
    "broker_find_agent": _handle_find_agent,
    "broker_delegate": _handle_delegate,
    "broker_cross_project_post": _handle_cross_project_post,
    "broker_register_cron": _handle_register_cron,
    "broker_list_cron": _handle_list_cron,
    "broker_remove_cron": _handle_remove_cron,
}
