/**
 * Agentic tools registry.
 *
 * Exports tool definitions (for the API request) and tool executors
 * (for the executor to dispatch to). All tools use a common interface.
 */

import { definition as readDef, execute as readExec } from './read.mjs';
import { definition as writeDef, execute as writeExec } from './write.mjs';
import { definition as editDef, execute as editExec } from './edit.mjs';
import { definition as multiEditDef, execute as multiEditExec } from './multiedit.mjs';
import { definition as globDef, execute as globExec } from './glob.mjs';
import { definition as grepDef, execute as grepExec } from './grep.mjs';

// These will be added in later phases — lazy-loaded to avoid import errors
const LAZY_TOOLS = ['bash', 'websearch', 'webfetch', 'task', 'askuser', 'planmode'];

/**
 * Try to dynamically import a tool module.
 * Returns null if the module doesn't exist yet.
 */
async function tryImportTool(name) {
  try {
    return await import(`./${name}.mjs`);
  } catch {
    return null;
  }
}

/**
 * Get tool definitions for the API request (tools array).
 * These are static JSON schemas, safe to call at any time.
 *
 * @param {string} workspaceRoot
 * @param {string} agentRoot
 * @returns {Object[]} Array of { name, description, input_schema }
 */
export function getToolDefinitions(workspaceRoot, agentRoot) {
  const defs = [readDef, writeDef, editDef, multiEditDef, globDef, grepDef];

  // Add lazy-loaded tools if their modules exist
  // These are populated by loadLazyTools() at runtime
  for (const def of _lazyDefs) {
    defs.push(def);
  }

  return defs;
}

/**
 * Get tool executors as a Map<name, function>.
 * Each executor has signature: (input, context) => { content, is_error }
 *
 * @param {string} workspaceRoot
 * @param {string} agentRoot
 * @returns {Map<string, Function>}
 */
export function getToolExecutors(workspaceRoot, agentRoot) {
  const executors = new Map();
  executors.set('Read', readExec);
  executors.set('Write', writeExec);
  executors.set('Edit', editExec);
  executors.set('MultiEdit', multiEditExec);
  executors.set('Glob', globExec);
  executors.set('Grep', grepExec);

  // Add lazy-loaded executors
  for (const [name, exec] of _lazyExecutors) {
    executors.set(name, exec);
  }

  return executors;
}

// Lazy-loaded tool storage
const _lazyDefs = [];
const _lazyExecutors = new Map();

/**
 * Load tools that may not be available at initial import time.
 * Call this once during adapter initialization.
 */
export async function loadLazyTools() {
  _lazyDefs.length = 0;
  _lazyExecutors.clear();

  for (const name of LAZY_TOOLS) {
    const mod = await tryImportTool(name);
    if (mod && mod.definition && mod.execute) {
      _lazyDefs.push(mod.definition);
      _lazyExecutors.set(mod.definition.name, mod.execute);
    }
    // planmode exports two tools
    if (mod && mod.enterDefinition && mod.exitDefinition) {
      _lazyDefs.push(mod.enterDefinition);
      _lazyDefs.push(mod.exitDefinition);
      if (mod.executeEnter) _lazyExecutors.set(mod.enterDefinition.name, mod.executeEnter);
      if (mod.executeExit) _lazyExecutors.set(mod.exitDefinition.name, mod.executeExit);
    }
  }
}

/**
 * Get the list of all registered tool names.
 */
export function getToolNames() {
  const names = ['Read', 'Write', 'Edit', 'MultiEdit', 'Glob', 'Grep'];
  for (const def of _lazyDefs) {
    names.push(def.name);
  }
  return names;
}
