'use strict';

const fs = require('node:fs');
const path = require('node:path');

const READ_ONLY_TOOL_NAMES = new Set([
  'read_file',
  'glob',
  'grep_files',
  'list_directory',
  'lsp_symbols',
  'lsp_definition',
  'lsp_references',
]);

const DELEGATE_TOOL_NAMES = new Set([
  ...READ_ONLY_TOOL_NAMES,
  'run_shell',
  'check_url',
  'start_static_server',
  'stop_static_server',
  'update_todos',
  'ask_user',
  'task',
  'mcp_call',
  'skill',
]);

const BUILTIN_AGENTS = {
  build: { id: 'build', mode: 'build', description: 'Implement code changes and verify them.', tools: 'all' },
  plan: { id: 'plan', mode: 'plan', description: 'Plan changes without editing files.', tools: 'read-only' },
  review: { id: 'review', mode: 'review', description: 'Review code and diffs without editing files.', tools: 'read-only' },
  explore: { id: 'explore', mode: 'plan', description: 'Explore the repository and report findings.', tools: 'read-only' },
  master: { id: 'master', mode: 'master', description: 'Coordinate child coding agents and verify their work.', tools: 'delegate' },
  mixed: { id: 'mixed', mode: 'mixed', description: 'Implement directly while delegating separable work to child agents.', tools: 'all' },
  general: { id: 'general', mode: 'build', description: 'General coding assistant.', tools: 'all' },
  compaction: { id: 'compaction', mode: 'summary', description: 'Summarize long coding histories.', hidden: true, tools: [] },
  summary: { id: 'summary', mode: 'summary', description: 'Produce concise session summaries.', hidden: true, tools: [] },
  title: { id: 'title', mode: 'summary', description: 'Generate session titles.', hidden: true, tools: [] },
};

class AgentCatalog {
  constructor({ projectRoot = process.cwd(), overrides = null } = {}) {
    this.projectRoot = projectRoot;
    this.overrides = overrides;
    this.agents = new Map();
    this.reload();
  }

  reload() {
    this.agents.clear();
    for (const [id, agent] of Object.entries(BUILTIN_AGENTS)) {
      this.agents.set(id, normalizeAgent({ ...agent, id }));
    }
    const overrides = this.overrides || loadAgentOverrides(this.projectRoot);
    for (const [id, override] of Object.entries(overrides || {})) {
      const base = this.agents.get(id) || { id };
      this.agents.set(id, normalizeAgent({ ...base, ...override, id }));
    }
  }

  get(id = 'build') {
    return this.agents.get(id) || null;
  }

  list({ includeHidden = false } = {}) {
    return [...this.agents.values()]
      .filter((agent) => includeHidden || !agent.hidden)
      .map((agent) => ({ ...agent }));
  }

  describeForTool() {
    return this.list()
      .map((agent) => `${agent.id}: ${agent.description}`)
      .join('\n');
  }

  toolsForAgent(toolDefinitions = [], agentOrId = 'build') {
    const agent = typeof agentOrId === 'string' ? this.get(agentOrId) : agentOrId;
    if (!agent) return [];
    const policy = agent.tools ?? 'all';
    if (policy === 'all') return [...toolDefinitions];
    if (policy === 'none' || (Array.isArray(policy) && policy.length === 0)) return [];
    if (policy === 'delegate' || agent.mode === 'master') {
      return toolDefinitions.filter((tool) => DELEGATE_TOOL_NAMES.has(tool.name));
    }
    if (policy === 'read-only' || agent.mode === 'plan' || agent.mode === 'review') {
      return toolDefinitions.filter((tool) => READ_ONLY_TOOL_NAMES.has(tool.name));
    }
    if (Array.isArray(policy)) {
      const allowed = new Set(policy);
      return toolDefinitions.filter((tool) => allowed.has(tool.name));
    }
    return [...toolDefinitions];
  }
}

function loadAgentOverrides(projectRoot = process.cwd()) {
  const filePath = path.join(projectRoot, '.walle', 'agents.json');
  try {
    const parsed = JSON.parse(fs.readFileSync(filePath, 'utf8'));
    return parsed && typeof parsed === 'object' ? parsed : {};
  } catch {
    return {};
  }
}

function normalizeAgent(agent = {}) {
  const mode = String(agent.mode || 'build');
  return {
    id: String(agent.id || ''),
    mode,
    description: String(agent.description || `${agent.id || 'Agent'} coding agent.`),
    prompt: typeof agent.prompt === 'string' ? agent.prompt : '',
    model: typeof agent.model === 'string' ? agent.model : '',
    temperature: agent.temperature,
    topP: agent.topP ?? agent.top_p,
    maxSteps: Number.isFinite(agent.maxSteps) ? agent.maxSteps : agent.max_steps,
    permissionRules: agent.permissionRules || agent.permission_rules || null,
    hidden: Boolean(agent.hidden),
    tools: agent.tools ?? (mode === 'plan' || mode === 'review' ? 'read-only' : 'all'),
  };
}

module.exports = {
  AgentCatalog,
  BUILTIN_AGENTS,
  READ_ONLY_TOOL_NAMES,
  DELEGATE_TOOL_NAMES,
  loadAgentOverrides,
  normalizeAgent,
};
