import { execSync } from "child_process";
import { readFileSync, writeFileSync, mkdirSync } from "fs";
import { dirname } from "path";

export interface ToolDefinition {
  name: string;
  description: string;
  input_schema: Record<string, unknown>;
}

export const toolDefs: ToolDefinition[] = [
  {
    name: "bash",
    description:
      "Execute a bash command. Returns stdout and stderr. Use for running commands, installing packages, git, etc. Timeout: 120s.",
    input_schema: {
      type: "object",
      properties: {
        command: {
          type: "string",
          description: "The bash command to execute",
        },
      },
      required: ["command"],
    },
  },
  {
    name: "read_file",
    description:
      "Read the contents of a file. Returns the text content. Use for examining code, configs, etc.",
    input_schema: {
      type: "object",
      properties: {
        path: { type: "string", description: "Path to the file" },
        limit: {
          type: "number",
          description: "Max lines to read (default: all)",
        },
        offset: {
          type: "number",
          description: "Line to start from, 1-indexed (default: 1)",
        },
      },
      required: ["path"],
    },
  },
  {
    name: "write_file",
    description:
      "Write content to a file. Creates parent directories if needed. Overwrites existing files.",
    input_schema: {
      type: "object",
      properties: {
        path: { type: "string", description: "Path to the file" },
        content: {
          type: "string",
          description: "Content to write",
        },
      },
      required: ["path", "content"],
    },
  },
  {
    name: "edit_file",
    description:
      "Edit a file by replacing exact text. oldText must match exactly including whitespace.",
    input_schema: {
      type: "object",
      properties: {
        path: { type: "string", description: "Path to the file" },
        old_text: {
          type: "string",
          description: "Exact text to find",
        },
        new_text: {
          type: "string",
          description: "Replacement text",
        },
      },
      required: ["path", "old_text", "new_text"],
    },
  },
  {
    name: "done",
    description:
      "Call this when the task is fully complete. Provide a short summary of what was accomplished.",
    input_schema: {
      type: "object",
      properties: {
        summary: {
          type: "string",
          description: "Short summary of what was done",
        },
      },
      required: ["summary"],
    },
  },
  {
    name: "ask_user",
    description:
      "Ask the user a question when you need clarification or a decision. The user will respond via Telegram.",
    input_schema: {
      type: "object",
      properties: {
        question: {
          type: "string",
          description: "The question to ask",
        },
      },
      required: ["question"],
    },
  },
];

export function executeTool(
  name: string,
  input: Record<string, unknown>
): { result: string; isDone?: boolean; isQuestion?: boolean } {
  try {
    switch (name) {
      case "bash": {
        const cmd = input.command as string;
        try {
          const output = execSync(cmd, {
            encoding: "utf-8",
            timeout: 120_000,
            maxBuffer: 1024 * 1024,
            cwd: process.cwd(),
          });
          const trimmed = output.length > 10000
            ? output.slice(0, 10000) + "\n...(truncated)"
            : output;
          return { result: trimmed || "(no output)" };
        } catch (e: any) {
          const stderr = e.stderr || "";
          const stdout = e.stdout || "";
          return {
            result: `Exit code: ${e.status}\nSTDOUT: ${stdout}\nSTDERR: ${stderr}`.slice(
              0,
              5000
            ),
          };
        }
      }

      case "read_file": {
        const path = input.path as string;
        const content = readFileSync(path, "utf-8");
        const lines = content.split("\n");
        const offset = ((input.offset as number) || 1) - 1;
        const limit = (input.limit as number) || lines.length;
        const slice = lines.slice(offset, offset + limit).join("\n");
        return {
          result:
            slice.length > 10000
              ? slice.slice(0, 10000) + "\n...(truncated)"
              : slice,
        };
      }

      case "write_file": {
        const path = input.path as string;
        mkdirSync(dirname(path), { recursive: true });
        writeFileSync(path, input.content as string, "utf-8");
        return { result: `Written ${(input.content as string).length} bytes to ${path}` };
      }

      case "edit_file": {
        const path = input.path as string;
        const content = readFileSync(path, "utf-8");
        const oldText = input.old_text as string;
        const newText = input.new_text as string;
        if (!content.includes(oldText)) {
          return { result: `ERROR: old_text not found in ${path}` };
        }
        writeFileSync(path, content.replace(oldText, newText), "utf-8");
        return { result: `Edited ${path}` };
      }

      case "done": {
        return { result: input.summary as string, isDone: true };
      }

      case "ask_user": {
        return { result: input.question as string, isQuestion: true };
      }

      default:
        return { result: `Unknown tool: ${name}` };
    }
  } catch (e: any) {
    return { result: `Tool error: ${e.message}` };
  }
}
