"""
Great Wiring Sprint: Workflow & Task Infrastructure MCP Plugin.

Wires the following dark-matter modules into MCP:
  - workflow_engine.py (Phase 36) — DAG workflow orchestration
  - task_queue.py (Phase 51) — priority task queue
  - task_templates.py (Phase 53) — reusable task templates
  - task_dependencies.py (Phase 15) — cross-task dependency DAG
"""

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,
)

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

TOOLS = [
    # ── Workflow Engine (Phase 36) ──
    Tool(
        name="workflow_create",
        description=(
            "Create a multi-step workflow with DAG dependencies. "
            "Each step has an id, name, and optional depends_on list."
        ),
        inputSchema={
            "type": "object",
            "properties": {
                "name": {"type": "string", "description": "Workflow name"},
                "description": {"type": "string", "description": "What this workflow does"},
                "steps": {
                    "type": "array",
                    "description": "List of step objects: {id, name, depends_on: [step_ids]}",
                    "items": {
                        "type": "object",
                        "properties": {
                            "id": {"type": "string"},
                            "name": {"type": "string"},
                            "depends_on": {
                                "type": "array",
                                "items": {"type": "string"},
                            },
                        },
                        "required": ["id", "name"],
                    },
                },
            },
            "required": ["name"],
        },
        annotations=_SAFE_WRITE,
    ),
    Tool(
        name="workflow_start",
        description="Start a workflow. Validates DAG and transitions to 'running' state.",
        inputSchema={
            "type": "object",
            "properties": {
                "workflow_id": {"type": "string", "description": "Workflow ID to start"},
            },
            "required": ["workflow_id"],
        },
        annotations=_SAFE_WRITE,
    ),
    Tool(
        name="workflow_ready_steps",
        description="Get all steps in a running workflow that are ready to execute (dependencies met).",
        inputSchema={
            "type": "object",
            "properties": {
                "workflow_id": {"type": "string"},
            },
            "required": ["workflow_id"],
        },
        annotations=_SAFE_READ,
    ),
    Tool(
        name="workflow_complete_step",
        description="Mark a workflow step as completed. Auto-advances the workflow if all steps done.",
        inputSchema={
            "type": "object",
            "properties": {
                "workflow_id": {"type": "string"},
                "step_id": {"type": "string"},
                "result": {"type": "string", "description": "Step result or output"},
            },
            "required": ["workflow_id", "step_id"],
        },
        annotations=_SAFE_WRITE,
    ),
    Tool(
        name="workflow_fail_step",
        description="Mark a workflow step as failed. Optionally cascade failure to dependent steps.",
        inputSchema={
            "type": "object",
            "properties": {
                "workflow_id": {"type": "string"},
                "step_id": {"type": "string"},
                "error": {"type": "string", "description": "Error message"},
                "cascade": {
                    "type": "boolean",
                    "description": "Fail all dependent steps too (default: true)",
                },
            },
            "required": ["workflow_id", "step_id", "error"],
        },
        annotations=_SAFE_WRITE,
    ),
    Tool(
        name="workflow_status",
        description="Get the current status of a workflow including all step states.",
        inputSchema={
            "type": "object",
            "properties": {
                "workflow_id": {"type": "string"},
            },
            "required": ["workflow_id"],
        },
        annotations=_SAFE_READ,
    ),
    Tool(
        name="workflow_cancel",
        description="Cancel a running workflow.",
        inputSchema={
            "type": "object",
            "properties": {
                "workflow_id": {"type": "string"},
            },
            "required": ["workflow_id"],
        },
        annotations=_SAFE_WRITE,
    ),
    Tool(
        name="workflow_list",
        description="List all workflows, optionally filtered by status.",
        inputSchema={
            "type": "object",
            "properties": {
                "status": {
                    "type": "string",
                    "description": "Filter: draft, running, completed, failed, cancelled",
                },
                "limit": {"type": "integer", "description": "Max results (default: 20)"},
            },
        },
        annotations=_SAFE_READ,
    ),
    Tool(
        name="workflow_execution_order",
        description="Show the valid execution order (topological sort) for a workflow's steps.",
        inputSchema={
            "type": "object",
            "properties": {
                "workflow_id": {"type": "string"},
            },
            "required": ["workflow_id"],
        },
        annotations=_SAFE_READ,
    ),
    Tool(
        name="workflow_save_template",
        description="Save a workflow as a reusable template.",
        inputSchema={
            "type": "object",
            "properties": {
                "workflow_id": {"type": "string"},
                "template_name": {"type": "string", "description": "Name for the template"},
            },
            "required": ["workflow_id", "template_name"],
        },
        annotations=_SAFE_WRITE,
    ),
    Tool(
        name="workflow_from_template",
        description="Create a new workflow from a saved template.",
        inputSchema={
            "type": "object",
            "properties": {
                "template_name": {"type": "string"},
                "overrides": {
                    "type": "object",
                    "description": "Override template fields (e.g., name, description)",
                },
            },
            "required": ["template_name"],
        },
        annotations=_SAFE_WRITE,
    ),
    Tool(
        name="workflow_history",
        description="Get the event history for a specific workflow.",
        inputSchema={
            "type": "object",
            "properties": {
                "workflow_id": {"type": "string"},
            },
            "required": ["workflow_id"],
        },
        annotations=_SAFE_READ,
    ),

    # ── Task Queue (Phase 51) ──
    Tool(
        name="queue_enqueue",
        description="Add a task to the priority queue. Ordered by priority (critical > high > normal > low), then FIFO.",
        inputSchema={
            "type": "object",
            "properties": {
                "task_id": {"type": "string", "description": "Task ID to enqueue"},
                "priority": {
                    "type": "string",
                    "description": "critical, high, normal, or low",
                    "default": "normal",
                },
                "deadline": {
                    "type": "string",
                    "description": "Optional ISO-8601 deadline",
                },
                "tags": {
                    "type": "array",
                    "items": {"type": "string"},
                    "description": "Tags for filtering",
                },
            },
            "required": ["task_id"],
        },
        annotations=_SAFE_WRITE,
    ),
    Tool(
        name="queue_dequeue",
        description="Pop the highest-priority task from the queue. Optionally filter by agent skills.",
        inputSchema={
            "type": "object",
            "properties": {
                "agent_id": {"type": "string", "description": "Agent claiming the task"},
                "skills": {
                    "type": "array",
                    "items": {"type": "string"},
                    "description": "Only dequeue tasks matching these skills/tags",
                },
            },
        },
        annotations=_SAFE_WRITE,
    ),
    Tool(
        name="queue_peek",
        description="Preview the top N items in the queue without removing them.",
        inputSchema={
            "type": "object",
            "properties": {
                "n": {"type": "integer", "description": "Number of items to peek (default: 5)"},
            },
        },
        annotations=_SAFE_READ,
    ),
    Tool(
        name="queue_requeue",
        description="Put a task back in the queue, optionally with a new priority.",
        inputSchema={
            "type": "object",
            "properties": {
                "task_id": {"type": "string"},
                "new_priority": {"type": "string", "description": "New priority level"},
            },
            "required": ["task_id"],
        },
        annotations=_SAFE_WRITE,
    ),
    Tool(
        name="queue_stats",
        description="Get queue statistics: size, breakdown by priority, overdue count.",
        inputSchema={"type": "object", "properties": {}},
        annotations=_SAFE_READ,
    ),
    Tool(
        name="queue_overdue",
        description="List tasks that have exceeded their deadline.",
        inputSchema={
            "type": "object",
            "properties": {
                "threshold_minutes": {
                    "type": "integer",
                    "description": "Minutes past deadline to consider overdue (default: 30)",
                },
            },
        },
        annotations=_SAFE_READ,
    ),

    # ── Task Templates (Phase 53) ──
    Tool(
        name="template_create",
        description="Define a reusable task template with $variable placeholders in title/description.",
        inputSchema={
            "type": "object",
            "properties": {
                "name": {"type": "string", "description": "Template name (unique identifier)"},
                "title_pattern": {
                    "type": "string",
                    "description": "Title with $variables (e.g., 'Review $module PR')",
                },
                "description_pattern": {
                    "type": "string",
                    "description": "Description with $variables",
                },
                "required_skills": {
                    "type": "array",
                    "items": {"type": "string"},
                },
                "default_priority": {"type": "string", "default": "normal"},
                "estimated_minutes": {"type": "integer", "default": 30},
                "category": {"type": "string"},
            },
            "required": ["name", "title_pattern", "description_pattern"],
        },
        annotations=_SAFE_WRITE,
    ),
    Tool(
        name="template_instantiate",
        description="Create a task from a template, substituting $variables with provided values.",
        inputSchema={
            "type": "object",
            "properties": {
                "template_name": {"type": "string"},
                "variables": {
                    "type": "object",
                    "description": "Variable substitutions (e.g., {\"module\": \"auth\"})",
                },
            },
            "required": ["template_name"],
        },
        annotations=_SAFE_WRITE,
    ),
    Tool(
        name="template_list",
        description="List all task templates, optionally filtered by category.",
        inputSchema={
            "type": "object",
            "properties": {
                "category": {"type": "string"},
            },
        },
        annotations=_SAFE_READ,
    ),
    Tool(
        name="template_popular",
        description="Show the most-used task templates ranked by instantiation count.",
        inputSchema={
            "type": "object",
            "properties": {
                "limit": {"type": "integer", "default": 10},
            },
        },
        annotations=_SAFE_READ,
    ),

    # ── Task Dependencies (Phase 15) ──
    Tool(
        name="dep_add",
        description="Add a dependency: target task cannot start until prerequisite is completed. Includes cycle detection.",
        inputSchema={
            "type": "object",
            "properties": {
                "target_task_id": {"type": "string", "description": "Task that depends on another"},
                "depends_on_task_id": {"type": "string", "description": "Prerequisite task"},
            },
            "required": ["target_task_id", "depends_on_task_id"],
        },
        annotations=_SAFE_WRITE,
    ),
    Tool(
        name="dep_remove",
        description="Remove a dependency link between two tasks.",
        inputSchema={
            "type": "object",
            "properties": {
                "target_task_id": {"type": "string"},
                "depends_on_task_id": {"type": "string"},
            },
            "required": ["target_task_id", "depends_on_task_id"],
        },
        annotations=_SAFE_WRITE,
    ),
    Tool(
        name="dep_check_ready",
        description="Check if a task is ready to execute (all dependencies completed).",
        inputSchema={
            "type": "object",
            "properties": {
                "task_id": {"type": "string"},
            },
            "required": ["task_id"],
        },
        annotations=_SAFE_READ,
    ),
    Tool(
        name="dep_get",
        description="Get all direct and transitive dependencies of a task.",
        inputSchema={
            "type": "object",
            "properties": {
                "task_id": {"type": "string"},
            },
            "required": ["task_id"],
        },
        annotations=_SAFE_READ,
    ),
    Tool(
        name="dep_execution_order",
        description="Compute valid execution order for a set of tasks using topological sort.",
        inputSchema={
            "type": "object",
            "properties": {
                "task_ids": {
                    "type": "array",
                    "items": {"type": "string"},
                    "description": "Task IDs to order",
                },
            },
            "required": ["task_ids"],
        },
        annotations=_SAFE_READ,
    ),
    Tool(
        name="dep_ready_tasks",
        description="Get all tasks whose dependencies are satisfied and are ready to execute.",
        inputSchema={
            "type": "object",
            "properties": {
                "task_ids": {
                    "type": "array",
                    "items": {"type": "string"},
                    "description": "Subset of tasks to check (omit for all pending)",
                },
            },
        },
        annotations=_SAFE_READ,
    ),
]


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

# -- Workflow Engine --

async def _handle_workflow_create(args: dict) -> list[TextContent]:
    from brynq.workflow_engine import create_workflow
    try:
        wf = await asyncio.to_thread(
            create_workflow,
            name=args["name"],
            description=args.get("description", ""),
            steps=args.get("steps"),
        )
        step_count = len(wf.get("steps", []))
        return [TextContent(
            type="text",
            text=f"Workflow created: {wf['workflow_id']}\n  Name: {wf['name']}\n  Steps: {step_count}\n  Status: {wf['status']}",
        )]
    except Exception as e:
        return [TextContent(type="text", text=f"Error creating workflow: {e}")]


async def _handle_workflow_start(args: dict) -> list[TextContent]:
    from brynq.workflow_engine import start_workflow
    try:
        wf = await asyncio.to_thread(start_workflow, args["workflow_id"])
        return [TextContent(
            type="text",
            text=f"Workflow '{wf['name']}' started. Status: {wf['status']}",
        )]
    except Exception as e:
        return [TextContent(type="text", text=f"Error starting workflow: {e}")]


async def _handle_workflow_ready_steps(args: dict) -> list[TextContent]:
    from brynq.workflow_engine import get_ready_steps
    try:
        steps = await asyncio.to_thread(get_ready_steps, args["workflow_id"])
        if not steps:
            return [TextContent(type="text", text="No steps ready (all have unmet dependencies or are completed).")]
        lines = [f"Ready steps ({len(steps)}):"]
        for s in steps:
            lines.append(f"  [{s['id']}] {s['name']} — status: {s.get('status', 'pending')}")
        return [TextContent(type="text", text="\n".join(lines))]
    except Exception as e:
        return [TextContent(type="text", text=f"Error: {e}")]


async def _handle_workflow_complete_step(args: dict) -> list[TextContent]:
    from brynq.workflow_engine import complete_step
    try:
        wf = await asyncio.to_thread(
            complete_step,
            workflow_id=args["workflow_id"],
            step_id=args["step_id"],
            result=args.get("result"),
        )
        return [TextContent(
            type="text",
            text=f"Step '{args['step_id']}' completed. Workflow status: {wf['status']}",
        )]
    except Exception as e:
        return [TextContent(type="text", text=f"Error: {e}")]


async def _handle_workflow_fail_step(args: dict) -> list[TextContent]:
    from brynq.workflow_engine import fail_step
    try:
        wf = await asyncio.to_thread(
            fail_step,
            workflow_id=args["workflow_id"],
            step_id=args["step_id"],
            error=args["error"],
            cascade=args.get("cascade", True),
        )
        return [TextContent(
            type="text",
            text=f"Step '{args['step_id']}' failed: {args['error']}\n  Workflow status: {wf['status']}",
        )]
    except Exception as e:
        return [TextContent(type="text", text=f"Error: {e}")]


async def _handle_workflow_status(args: dict) -> list[TextContent]:
    from brynq.workflow_engine import get_workflow_status
    try:
        wf = await asyncio.to_thread(get_workflow_status, args["workflow_id"])
        if wf is None:
            return [TextContent(type="text", text=f"Workflow '{args['workflow_id']}' not found.")]
        lines = [
            f"Workflow: {wf['name']} ({wf['workflow_id']})",
            f"  Status: {wf['status']}",
            f"  Steps: {wf.get('progress', {}).get('total', '?')}",
        ]
        progress = wf.get("progress", {})
        if progress:
            lines.append(
                f"  Progress: {progress.get('completed', 0)}/{progress.get('total', 0)} completed, "
                f"{progress.get('failed', 0)} failed"
            )
        for s in wf.get("steps", []):
            dep_str = f" (depends: {', '.join(s.get('depends_on', []))})" if s.get("depends_on") else ""
            lines.append(f"  [{s.get('status', '?').upper()}] {s['id']}: {s['name']}{dep_str}")
        return [TextContent(type="text", text="\n".join(lines))]
    except Exception as e:
        return [TextContent(type="text", text=f"Error: {e}")]


async def _handle_workflow_cancel(args: dict) -> list[TextContent]:
    from brynq.workflow_engine import cancel_workflow
    try:
        wf = await asyncio.to_thread(cancel_workflow, args["workflow_id"])
        return [TextContent(type="text", text=f"Workflow '{wf['name']}' cancelled.")]
    except Exception as e:
        return [TextContent(type="text", text=f"Error: {e}")]


async def _handle_workflow_list(args: dict) -> list[TextContent]:
    from brynq.workflow_engine import list_workflows
    try:
        wfs = await asyncio.to_thread(
            list_workflows,
            status=args.get("status"),
            limit=args.get("limit", 20),
        )
        if not wfs:
            return [TextContent(type="text", text="No workflows found.")]
        lines = [f"Workflows ({len(wfs)}):"]
        for w in wfs:
            lines.append(f"  [{w['status'].upper()}] {w['name']} ({w['workflow_id']}) — {len(w.get('steps', []))} steps")
        return [TextContent(type="text", text="\n".join(lines))]
    except Exception as e:
        return [TextContent(type="text", text=f"Error: {e}")]


async def _handle_workflow_execution_order(args: dict) -> list[TextContent]:
    from brynq.workflow_engine import get_execution_order
    try:
        order = await asyncio.to_thread(get_execution_order, args["workflow_id"])
        if not order:
            return [TextContent(type="text", text="No execution order (empty workflow or not found).")]
        lines = ["Execution order (groups can run in parallel):"]
        for i, group in enumerate(order):
            lines.append(f"  Group {i + 1}: {', '.join(group)}")
        return [TextContent(type="text", text="\n".join(lines))]
    except Exception as e:
        return [TextContent(type="text", text=f"Error: {e}")]


async def _handle_workflow_save_template(args: dict) -> list[TextContent]:
    from brynq.workflow_engine import save_as_template
    try:
        await asyncio.to_thread(
            save_as_template,
            workflow_id=args["workflow_id"],
            template_name=args["template_name"],
        )
        return [TextContent(
            type="text",
            text=f"Workflow saved as template '{args['template_name']}'.",
        )]
    except Exception as e:
        return [TextContent(type="text", text=f"Error: {e}")]


async def _handle_workflow_from_template(args: dict) -> list[TextContent]:
    from brynq.workflow_engine import create_from_template
    try:
        wf = await asyncio.to_thread(
            create_from_template,
            template_name=args["template_name"],
            overrides=args.get("overrides"),
        )
        return [TextContent(
            type="text",
            text=f"Workflow created from template: {wf['workflow_id']}\n  Name: {wf['name']}\n  Steps: {len(wf.get('steps', []))}",
        )]
    except Exception as e:
        return [TextContent(type="text", text=f"Error: {e}")]


async def _handle_workflow_history(args: dict) -> list[TextContent]:
    from brynq.workflow_engine import get_workflow_history
    try:
        events = await asyncio.to_thread(get_workflow_history, args["workflow_id"])
        if not events:
            return [TextContent(type="text", text="No history events found.")]
        lines = [f"Workflow history ({len(events)} events):"]
        for e in events[-20:]:  # Last 20 events
            ts = e.get("timestamp", "")[:19]
            lines.append(f"  [{ts}] {e.get('event', '?')}: {e.get('detail', '')}")
        return [TextContent(type="text", text="\n".join(lines))]
    except Exception as e:
        return [TextContent(type="text", text=f"Error: {e}")]


# -- Task Queue --

async def _handle_queue_enqueue(args: dict) -> list[TextContent]:
    from brynq.task_queue import enqueue
    try:
        entry = await asyncio.to_thread(
            enqueue,
            task_id=args["task_id"],
            priority=args.get("priority", "normal"),
            deadline=args.get("deadline"),
            tags=args.get("tags"),
        )
        return [TextContent(
            type="text",
            text=f"Task '{args['task_id']}' enqueued with priority: {entry['priority']}",
        )]
    except Exception as e:
        return [TextContent(type="text", text=f"Error: {e}")]


async def _handle_queue_dequeue(args: dict) -> list[TextContent]:
    from brynq.task_queue import dequeue
    try:
        task = await asyncio.to_thread(
            dequeue,
            agent_id=args.get("agent_id"),
            skills=args.get("skills"),
        )
        if task is None:
            return [TextContent(type="text", text="Queue is empty (or no matching tasks for your skills).")]
        return [TextContent(
            type="text",
            text=f"Dequeued: {task['task_id']} (priority: {task['priority']})",
        )]
    except Exception as e:
        return [TextContent(type="text", text=f"Error: {e}")]


async def _handle_queue_peek(args: dict) -> list[TextContent]:
    from brynq.task_queue import peek
    try:
        items = await asyncio.to_thread(peek, n=args.get("n", 5))
        if not items:
            return [TextContent(type="text", text="Queue is empty.")]
        lines = [f"Queue top {len(items)}:"]
        for i, item in enumerate(items, 1):
            deadline = f" (deadline: {item['deadline'][:19]})" if item.get("deadline") else ""
            lines.append(f"  {i}. [{item['priority'].upper()}] {item['task_id']}{deadline}")
        return [TextContent(type="text", text="\n".join(lines))]
    except Exception as e:
        return [TextContent(type="text", text=f"Error: {e}")]


async def _handle_queue_requeue(args: dict) -> list[TextContent]:
    from brynq.task_queue import requeue
    try:
        entry = await asyncio.to_thread(
            requeue,
            task_id=args["task_id"],
            new_priority=args.get("new_priority"),
        )
        return [TextContent(
            type="text",
            text=f"Task '{args['task_id']}' requeued with priority: {entry['priority']}",
        )]
    except Exception as e:
        return [TextContent(type="text", text=f"Error: {e}")]


async def _handle_queue_stats(args: dict) -> list[TextContent]:
    from brynq.task_queue import get_queue_stats
    try:
        stats = await asyncio.to_thread(get_queue_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}")]


async def _handle_queue_overdue(args: dict) -> list[TextContent]:
    from brynq.task_queue import get_overdue
    try:
        overdue = await asyncio.to_thread(
            get_overdue,
            threshold_minutes=args.get("threshold_minutes", 30),
        )
        if not overdue:
            return [TextContent(type="text", text="No overdue tasks.")]
        lines = [f"Overdue tasks ({len(overdue)}):"]
        for t in overdue:
            lines.append(f"  [{t['priority'].upper()}] {t['task_id']} — deadline: {t.get('deadline', 'N/A')}")
        return [TextContent(type="text", text="\n".join(lines))]
    except Exception as e:
        return [TextContent(type="text", text=f"Error: {e}")]


# -- Task Templates --

async def _handle_template_create(args: dict) -> list[TextContent]:
    from brynq.task_templates import create_template
    try:
        tmpl = await asyncio.to_thread(
            create_template,
            name=args["name"],
            title_pattern=args["title_pattern"],
            description_pattern=args["description_pattern"],
            required_skills=args.get("required_skills", []),
            default_priority=args.get("default_priority", "normal"),
            estimated_minutes=args.get("estimated_minutes", 30),
            category=args.get("category"),
        )
        return [TextContent(
            type="text",
            text=f"Template '{tmpl['name']}' created.\n  Title pattern: {tmpl['title_pattern']}\n  Skills: {', '.join(tmpl.get('required_skills', []))}",
        )]
    except Exception as e:
        return [TextContent(type="text", text=f"Error: {e}")]


async def _handle_template_instantiate(args: dict) -> list[TextContent]:
    from brynq.task_templates import instantiate
    try:
        task = await asyncio.to_thread(
            instantiate,
            template_name=args["template_name"],
            variables=args.get("variables"),
        )
        return [TextContent(
            type="text",
            text=f"Task created from template '{args['template_name']}':\n  Title: {task['title']}\n  Priority: {task['priority']}",
        )]
    except Exception as e:
        return [TextContent(type="text", text=f"Error: {e}")]


async def _handle_template_list(args: dict) -> list[TextContent]:
    from brynq.task_templates import list_templates
    try:
        templates = await asyncio.to_thread(
            list_templates,
            category=args.get("category"),
        )
        if not templates:
            return [TextContent(type="text", text="No templates found.")]
        lines = [f"Task templates ({len(templates)}):"]
        for t in templates:
            uses = t.get("instantiation_count", 0)
            lines.append(f"  {t['name']} — {t['title_pattern']} ({uses} uses)")
        return [TextContent(type="text", text="\n".join(lines))]
    except Exception as e:
        return [TextContent(type="text", text=f"Error: {e}")]


async def _handle_template_popular(args: dict) -> list[TextContent]:
    from brynq.task_templates import get_popular_templates
    try:
        templates = await asyncio.to_thread(
            get_popular_templates,
            limit=args.get("limit", 10),
        )
        if not templates:
            return [TextContent(type="text", text="No templates have been used yet.")]
        lines = ["Most popular templates:"]
        for i, t in enumerate(templates, 1):
            lines.append(f"  {i}. {t['name']} — {t.get('instantiation_count', 0)} uses")
        return [TextContent(type="text", text="\n".join(lines))]
    except Exception as e:
        return [TextContent(type="text", text=f"Error: {e}")]


# -- Task Dependencies --

async def _handle_dep_add(args: dict) -> list[TextContent]:
    from brynq.task_dependencies import DependencyManager
    try:
        dm = DependencyManager()
        result = await asyncio.to_thread(
            dm.add_dependency,
            target_task_id=args["target_task_id"],
            depends_on_task_id=args["depends_on_task_id"],
        )
        return [TextContent(
            type="text",
            text=f"Dependency added: {args['target_task_id']} depends on {args['depends_on_task_id']}",
        )]
    except Exception as e:
        return [TextContent(type="text", text=f"Error (possible cycle?): {e}")]


async def _handle_dep_remove(args: dict) -> list[TextContent]:
    from brynq.task_dependencies import DependencyManager
    try:
        dm = DependencyManager()
        await asyncio.to_thread(
            dm.remove_dependency,
            target_task_id=args["target_task_id"],
            depends_on_task_id=args["depends_on_task_id"],
        )
        return [TextContent(
            type="text",
            text=f"Dependency removed: {args['target_task_id']} no longer depends on {args['depends_on_task_id']}",
        )]
    except Exception as e:
        return [TextContent(type="text", text=f"Error: {e}")]


async def _handle_dep_check_ready(args: dict) -> list[TextContent]:
    from brynq.task_dependencies import DependencyManager
    try:
        dm = DependencyManager()
        result = await asyncio.to_thread(dm.is_task_ready, args["task_id"])
        if result["ready"]:
            return [TextContent(type="text", text=f"Task '{args['task_id']}' is READY — all dependencies satisfied.")]
        blocking = ", ".join(result.get("blocking", []))
        return [TextContent(
            type="text",
            text=f"Task '{args['task_id']}' is BLOCKED by: {blocking}",
        )]
    except Exception as e:
        return [TextContent(type="text", text=f"Error: {e}")]


async def _handle_dep_get(args: dict) -> list[TextContent]:
    from brynq.task_dependencies import DependencyManager
    try:
        dm = DependencyManager()
        result = await asyncio.to_thread(dm.get_dependencies, args["task_id"])
        direct = result.get("direct", [])
        transitive = result.get("transitive", [])
        lines = [f"Dependencies for '{args['task_id']}':"]
        lines.append(f"  Direct: {', '.join(direct) if direct else 'none'}")
        lines.append(f"  Transitive: {', '.join(transitive) if transitive else 'none'}")
        return [TextContent(type="text", text="\n".join(lines))]
    except Exception as e:
        return [TextContent(type="text", text=f"Error: {e}")]


async def _handle_dep_execution_order(args: dict) -> list[TextContent]:
    from brynq.task_dependencies import DependencyManager
    try:
        dm = DependencyManager()
        result = await asyncio.to_thread(dm.execution_order, args["task_ids"])
        order = result.get("order", [])
        if not order:
            return [TextContent(type="text", text="No valid execution order (empty or cycle detected).")]
        return [TextContent(
            type="text",
            text=f"Execution order: {' -> '.join(order)}",
        )]
    except Exception as e:
        return [TextContent(type="text", text=f"Error: {e}")]


async def _handle_dep_ready_tasks(args: dict) -> list[TextContent]:
    from brynq.task_dependencies import DependencyManager
    try:
        dm = DependencyManager()
        ready = await asyncio.to_thread(
            dm.get_ready_tasks,
            task_ids=args.get("task_ids"),
        )
        if not ready:
            return [TextContent(type="text", text="No tasks are ready (all have unmet dependencies).")]
        return [TextContent(
            type="text",
            text=f"Ready tasks: {', '.join(ready)}",
        )]
    except Exception as e:
        return [TextContent(type="text", text=f"Error: {e}")]


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

HANDLERS = {
    # Workflow Engine
    "workflow_create": _handle_workflow_create,
    "workflow_start": _handle_workflow_start,
    "workflow_ready_steps": _handle_workflow_ready_steps,
    "workflow_complete_step": _handle_workflow_complete_step,
    "workflow_fail_step": _handle_workflow_fail_step,
    "workflow_status": _handle_workflow_status,
    "workflow_cancel": _handle_workflow_cancel,
    "workflow_list": _handle_workflow_list,
    "workflow_execution_order": _handle_workflow_execution_order,
    "workflow_save_template": _handle_workflow_save_template,
    "workflow_from_template": _handle_workflow_from_template,
    "workflow_history": _handle_workflow_history,
    # Task Queue
    "queue_enqueue": _handle_queue_enqueue,
    "queue_dequeue": _handle_queue_dequeue,
    "queue_peek": _handle_queue_peek,
    "queue_requeue": _handle_queue_requeue,
    "queue_stats": _handle_queue_stats,
    "queue_overdue": _handle_queue_overdue,
    # Task Templates
    "template_create": _handle_template_create,
    "template_instantiate": _handle_template_instantiate,
    "template_list": _handle_template_list,
    "template_popular": _handle_template_popular,
    # Task Dependencies
    "dep_add": _handle_dep_add,
    "dep_remove": _handle_dep_remove,
    "dep_check_ready": _handle_dep_check_ready,
    "dep_get": _handle_dep_get,
    "dep_execution_order": _handle_dep_execution_order,
    "dep_ready_tasks": _handle_dep_ready_tasks,
}
