// ═══════════════════════════════════════════════════════════
// Task Tools: get_pending, approve, reject
// ═══════════════════════════════════════════════════════════

import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { z } from "zod";
import * as api from "../api-client.js";
import type { Task, Priority } from "../types.js";

function formatTask(task: Task, includeContext: boolean): string {
  const slaInfo = task.slaBreached
    ? "🚨 SLA BREACHED"
    : task.slaDeadline
      ? `⏰ Due: ${new Date(task.slaDeadline).toLocaleString()}`
      : "";

  const priorityEmoji: Record<Priority, string> = {
    critical: "🔴",
    high: "🟡",
    medium: "🔵",
    low: "⚪",
  };

  let output = `${priorityEmoji[task.priority]} [${task.priority.toUpperCase()}] ${task.title}`;
  output += `\n   ID: ${task.id}`;
  output += `\n   Type: ${task.type} | Status: ${task.status}`;
  if (task.pipelineId) output += `\n   Pipeline: ${task.pipelineId}`;
  if (task.stageName) output += `\n   Stage: ${task.stageName}`;
  if (slaInfo) output += `\n   ${slaInfo}`;
  if (task.assigneeId) output += `\n   Assigned to: ${task.assigneeId}`;
  if (task.blocksStageAdvance) output += `\n   ⛔ Blocks stage advance`;

  if (includeContext && task.context) {
    output += `\n   Summary: ${task.context.summary}`;
    if (task.context.testResults) {
      const tr = task.context.testResults;
      output += `\n   Tests: ${tr.passed}/${tr.total} passed (${tr.coveragePercent}% coverage)`;
      if (tr.failureDetails?.length) {
        output += `\n   Failures:`;
        for (const f of tr.failureDetails.slice(0, 5)) {
          output += `\n     - ${f.testName}: ${f.error}`;
        }
      }
    }
    if (task.context.diffSummary) {
      const d = task.context.diffSummary;
      output += `\n   Diff: ${d.filesChanged} files, +${d.insertions}/-${d.deletions}`;
    }
  }

  return output;
}

export function registerTaskTools(server: McpServer): void {
  // ───────────────────────────────────────
  // factory_get_pending_tasks
  // ───────────────────────────────────────
  server.tool(
    "factory_get_pending_tasks",
    "Get all tasks requiring human attention, sorted by priority and SLA urgency. " +
      "This is the operator's decision inbox — the most important view in the factory.",
    {
      pipeline_id: z.string().uuid().optional().describe("Filter tasks to a specific pipeline (UUID)"),
      priority: z
        .enum(["critical", "high", "medium", "low"])
        .optional()
        .describe("Filter by priority level"),
      assignee: z.string().optional().describe("Filter by assignee. Use 'me' for current user."),
      include_context: z
        .boolean()
        .default(true)
        .describe("Include full task context (diffs, test results). Default: true"),
      limit: z.number().min(1).max(100).default(20).describe("Maximum tasks to return. Default: 20"),
    },
    async ({ pipeline_id, priority, assignee, include_context, limit }) => {
      try {
        const tasks = await api.listTasks({
          status: "pending",
          pipelineId: pipeline_id,
          priority: priority as Priority | undefined,
          assigneeId: assignee,
          limit,
          sort: "-priority,-sla_deadline",
        });

        if (tasks.length === 0) {
          return {
            content: [
              {
                type: "text" as const,
                text: "✅ No pending tasks! The factory is running smoothly.",
              },
            ],
          };
        }

        const slaBreached = tasks.filter((t) => t.slaBreached).length;
        const critical = tasks.filter((t) => t.priority === "critical").length;

        let header = `📥 **${tasks.length} Pending Tasks**`;
        if (slaBreached > 0) header += ` | 🚨 ${slaBreached} SLA breached`;
        if (critical > 0) header += ` | 🔴 ${critical} critical`;
        header += "\n" + "─".repeat(60);

        const taskList = tasks
          .map((t, i) => `\n${i + 1}. ${formatTask(t, include_context)}`)
          .join("\n");

        return {
          content: [
            {
              type: "text" as const,
              text: header + taskList,
            },
          ],
        };
      } catch (err) {
        const msg = err instanceof Error ? err.message : String(err);
        return {
          content: [{ type: "text" as const, text: `❌ Error fetching pending tasks: ${msg}` }],
          isError: true,
        };
      }
    },
  );

  // ───────────────────────────────────────
  // factory_approve_task
  // ───────────────────────────────────────
  server.tool(
    "factory_approve_task",
    "Approve a pending task or approval gate, allowing the pipeline to proceed. " +
      "Use this when the operator says 'approve', 'LGTM', 'ship it', etc.",
    {
      task_id: z.string().uuid().describe("UUID of the task to approve"),
      notes: z.string().optional().describe("Optional approval notes or conditions"),
      conditions: z
        .array(z.string())
        .optional()
        .describe("Conditions that must be met post-approval"),
    },
    async ({ task_id, notes, conditions }) => {
      try {
        const task = await api.completeTask(task_id, {
          decision: "approved",
          notes,
          decisionData: conditions ? { conditions } : {},
        });

        let response = `✅ **Task Approved**`;
        response += `\n   Task: ${task.title}`;
        response += `\n   ID: ${task.id}`;
        if (notes) response += `\n   Notes: ${notes}`;
        if (conditions?.length) {
          response += `\n   Conditions:`;
          conditions.forEach((c) => (response += `\n     • ${c}`));
        }
        if (task.pipelineId) {
          response += `\n\n🔄 Pipeline ${task.pipelineId} can now advance.`;
        }

        return {
          content: [{ type: "text" as const, text: response }],
        };
      } catch (err) {
        const msg = err instanceof Error ? err.message : String(err);
        return {
          content: [{ type: "text" as const, text: `❌ Error approving task: ${msg}` }],
          isError: true,
        };
      }
    },
  );

  // ───────────────────────────────────────
  // factory_reject_task
  // ───────────────────────────────────────
  server.tool(
    "factory_reject_task",
    "Reject a pending task with feedback. Sends pipeline back for rework. " +
      "Use when the operator says 'reject', 'needs work', 'fix this', etc.",
    {
      task_id: z.string().uuid().describe("UUID of the task to reject"),
      reason: z.string().describe("Why this was rejected — required for feedback loop"),
      requested_changes: z
        .array(z.string())
        .optional()
        .describe("Specific changes needed before re-submission"),
      severity: z
        .enum(["minor", "major", "critical"])
        .default("major")
        .describe("How serious the issues are. Default: major"),
    },
    async ({ task_id, reason, requested_changes, severity }) => {
      try {
        const task = await api.completeTask(task_id, {
          decision: "rejected",
          notes: reason,
          decisionData: {
            severity,
            requestedChanges: requested_changes || [],
          },
        });

        let response = `❌ **Task Rejected**`;
        response += `\n   Task: ${task.title}`;
        response += `\n   ID: ${task.id}`;
        response += `\n   Severity: ${severity}`;
        response += `\n   Reason: ${reason}`;
        if (requested_changes?.length) {
          response += `\n   Requested Changes:`;
          requested_changes.forEach((c) => (response += `\n     • ${c}`));
        }
        if (task.pipelineId) {
          response += `\n\n🔙 Pipeline ${task.pipelineId} sent back for rework.`;
        }

        return {
          content: [{ type: "text" as const, text: response }],
        };
      } catch (err) {
        const msg = err instanceof Error ? err.message : String(err);
        return {
          content: [{ type: "text" as const, text: `❌ Error rejecting task: ${msg}` }],
          isError: true,
        };
      }
    },
  );
}
