/**
 * SimpleX Bot — Starter Commands
 *
 * Built-in commands for the aidevops SimpleX bot.
 * Each command is a self-contained handler that receives a CommandContext.
 *
 * Reference: t1327.4 bot framework specification
 * Reference: t1327.10 exec approval flow
 */

import { resolve } from "node:path";
import pkg from "../package.json";
import type { CommandContext, CommandDefinition } from "./types";

// Re-export exec approval manager from extracted module
export { getApprovalManager, setApprovalManager } from "./exec-commands";

import {approveCommand, pendingCommand,rejectCommand, 
  runCommand, 
} from "./exec-commands";

// =============================================================================
// Built-in Commands
// =============================================================================

/** Show available commands and usage instructions (generated dynamically) */
const helpCommand: CommandDefinition = {
  name: "help",
  description: "Show available commands and usage",
  groupEnabled: true,
  dmEnabled: true,
  handler: async (_ctx: CommandContext): Promise<string> => {
    // Build help text dynamically from BUILTIN_COMMANDS so it never drifts
    const lines = ["Available commands:", ""];
    for (const cmd of BUILTIN_COMMANDS) {
      lines.push(`/${cmd.name} — ${cmd.description}`);
    }
    return lines.join("\n");
  },
};

/** Query aidevops CLI for system status */
const statusCommand: CommandDefinition = {
  name: "status",
  description: "Show aidevops system status",
  groupEnabled: true,
  dmEnabled: true,
  handler: async (_ctx: CommandContext): Promise<string> => {
    try {
      const proc = Bun.spawn(["aidevops", "status"], {
        stdout: "pipe",
        stderr: "pipe",
      });
      const output = await new Response(proc.stdout).text();
      const stderrText = await new Response(proc.stderr).text();
      const exitCode = await proc.exited;
      if (exitCode !== 0) {
        const detail = stderrText.trim();
        return `Failed to get aidevops status.${detail ? ` Error: ${detail}` : " Is aidevops installed?"}`;
      }
      return output.trim() || "aidevops is running (no output)";
    } catch {
      return "aidevops CLI not available. Install from https://aidevops.sh";
    }
  },
};

/** Route a question to the AI model routing system */
const askCommand: CommandDefinition = {
  name: "ask",
  description: "Ask AI a question (routes to appropriate model tier)",
  groupEnabled: true,
  dmEnabled: true,
  handler: async (ctx: CommandContext): Promise<string> => {
    const question = ctx.args.join(" ");
    if (!question) {
      return "Usage: /ask [question]\nExample: /ask What is the status of issue #42?";
    }
    // Placeholder — in production this routes to the model routing system
    return (
      'Question received: "' +
      question +
      '"\n\n(AI model routing not yet connected. This is a scaffold.)'
    );
  },
};

/** List open tasks from TODO.md using configurable path */
const tasksCommand: CommandDefinition = {
  name: "tasks",
  description: "List open tasks from TODO.md",
  groupEnabled: true,
  dmEnabled: true,
  handler: async (_ctx: CommandContext): Promise<string> => {
    try {
      const tasksFile =
        process.env.SIMPLEX_TASKS_FILE ??
        `${import.meta.dir}/../../../../TODO.md`;
      const todoPath = resolve(tasksFile);
      const proc = Bun.spawn(
        ["grep", "-c", "\\- \\[ \\]", todoPath],
        { stdout: "pipe", stderr: "pipe" },
      );
      // Read stdout/stderr before awaiting exit (consistent with statusCommand,
      // avoids pipe buffer deadlocks for verbose commands)
      const output = await new Response(proc.stdout).text();
      const stderrOutput = await new Response(proc.stderr).text();
      const exitCode = await proc.exited;

      if (exitCode === 0) {
        const count = output.trim();
        return `Open tasks: ${count}\n\nUse /task <description> to create a new task.`;
      } else if (exitCode === 1) {
        // grep returns 1 when no lines match — not an error
        return "Open tasks: 0\n\nUse /task <description> to create a new task.";
      } else {
        // grep returns >1 for actual errors (file not found, permission denied)
        console.error(`[tasksCommand] grep failed (exit ${exitCode}): ${stderrOutput}`);
        return "Could not read TODO.md";
      }
    } catch (err) {
      return `Could not read TODO.md: ${String(err)}`;
    }
  },
};

/** Create a new task entry in TODO.md (DM only) */
const taskCommand: CommandDefinition = {
  name: "task",
  description: "Create a new task in TODO.md",
  groupEnabled: false,
  dmEnabled: true,
  handler: async (ctx: CommandContext): Promise<string> => {
    const description = ctx.args.join(" ");
    if (!description) {
      return "Usage: /task [description]\nExample: /task Fix authentication bug in login page";
    }
    // Placeholder — in production this calls claim-task-id.sh and appends to TODO.md
    return (
      'Task noted: "' +
      description +
      '"\n\n(Task creation not yet connected to TODO.md pipeline. This is a scaffold.)'
    );
  },
};

/** Simple liveness check — returns "pong" */
const pingCommand: CommandDefinition = {
  name: "ping",
  description: "Check bot responsiveness",
  groupEnabled: true,
  dmEnabled: true,
  handler: async (_ctx: CommandContext): Promise<string> => {
    return "pong";
  },
};

/** Report bot version from package.json */
const versionCommand: CommandDefinition = {
  name: "version",
  description: "Show bot version",
  groupEnabled: true,
  dmEnabled: true,
  handler: async (_ctx: CommandContext): Promise<string> => {
    return `aidevops SimpleX Bot v${pkg.version}`;
  },
};

// =============================================================================
// Group Commands
// =============================================================================

/** Invite a user to a group (group only) */
const inviteCommand: CommandDefinition = {
  name: "invite",
  description: "Invite a user to this group",
  groupEnabled: true,
  dmEnabled: false,
  handler: async (ctx: CommandContext): Promise<string> => {
    const user = ctx.args[0];
    if (!user) {
      return "Usage: /invite @username";
    }
    // Scaffold — in production this calls /_add_member
    return (
      "Invite request for " + user + " noted.\n\n" +
      "(Group member management not yet connected. This is a scaffold.)"
    );
  },
};

/** Set a member's role in a group (group only) */
const roleCommand: CommandDefinition = {
  name: "role",
  description: "Set member role (observer/author/member/moderator/admin)",
  groupEnabled: true,
  dmEnabled: false,
  handler: async (ctx: CommandContext): Promise<string> => {
    const user = ctx.args[0];
    const role = ctx.args[1];
    if (!user || !role) {
      return "Usage: /role @username [observer|author|member|moderator|admin]";
    }
    const validRoles = ["observer", "author", "member", "moderator", "admin"];
    if (!validRoles.includes(role.toLowerCase())) {
      return `Valid roles: ${validRoles.join(", ")}`;
    }
    return (
      "Role change: " + user + " → " + role + "\n\n" +
      "(Role management not yet connected. This is a scaffold.)"
    );
  },
};

/** Broadcast a message to all contacts (DM only) */
const broadcastCommand: CommandDefinition = {
  name: "broadcast",
  description: "Send message to all connected contacts",
  groupEnabled: false,
  dmEnabled: true,
  handler: async (ctx: CommandContext): Promise<string> => {
    const message = ctx.args.join(" ");
    if (!message) {
      return "Usage: /broadcast [message]";
    }
    return (
      "Broadcast queued: \"" + message + "\"\n\n" +
      "(Broadcast delivery not yet connected. This is a scaffold.)"
    );
  },
};

// =============================================================================
// Voice & File Commands
// =============================================================================

/** Process a voice note attachment */
const voiceCommand: CommandDefinition = {
  name: "voice",
  description: "Process voice note (attach voice message before this command)",
  groupEnabled: true,
  dmEnabled: true,
  handler: async (_ctx: CommandContext): Promise<string> => {
    return [
      "Voice processing:",
      "1. Send a voice note in this chat",
      "2. The bot will receive it as a file attachment",
      "3. Once speech-to-speech agent is connected, it will be transcribed and processed",
      "",
      "(Voice transcription not yet connected. This is a scaffold.)",
    ].join("\n");
  },
};

/** Process a file attachment */
const fileCommand: CommandDefinition = {
  name: "file",
  description: "Process file attachment (send file before this command)",
  groupEnabled: true,
  dmEnabled: true,
  handler: async (_ctx: CommandContext): Promise<string> => {
    return [
      "File processing:",
      "1. Send a file in this chat",
      "2. The bot will auto-accept files within size limits",
      "3. Supported: documents, images, code files",
      "",
      "(File analysis not yet connected. This is a scaffold.)",
    ].join("\n");
  },
};

/** Show active sessions and stats */
const sessionsCommand: CommandDefinition = {
  name: "sessions",
  description: "Show active bot sessions",
  groupEnabled: false,
  dmEnabled: true,
  handler: async (_ctx: CommandContext): Promise<string> => {
    // Scaffold — in production this queries the SessionStore
    return [
      "Session management:",
      "Active sessions and statistics will be shown here.",
      "",
      "(Session store query not yet connected. This is a scaffold.)",
    ].join("\n");
  },
};

// =============================================================================
// Command Registry
// =============================================================================

/** All built-in commands */
export const BUILTIN_COMMANDS: CommandDefinition[] = [
  // Core commands
  helpCommand,
  statusCommand,
  askCommand,
  pingCommand,
  versionCommand,
  // Task commands
  tasksCommand,
  taskCommand,
  // Execution
  runCommand,
  approveCommand,
  rejectCommand,
  pendingCommand,
  // Group commands
  inviteCommand,
  roleCommand,
  broadcastCommand,
  // Voice & file
  voiceCommand,
  fileCommand,
  // Session management
  sessionsCommand,
];
