const path = require('node:path');
const fs = require('fs-extra');
const { loadSkillManifest, getCanonicalId } = require('./skill-manifest');

/**
 * Helpers for gathering BMAD agents/tasks from the installed tree.
 * Shared by installers that need Claude-style exports.
 *
 * TODO: Dead code cleanup — compiled XML agents are retired.
 *
 * All agents now use the SKILL.md directory format with bmad-skill-manifest.yaml
 * (type: agent). The legacy pipeline below only discovers compiled .md files
 * containing <agent> XML tags, which no longer exist. The following are dead:
 *
 *   - getAgentsFromBmad()      — scans {module}/agents/ for .md files with <agent> tags
 *   - getAgentsFromDir()       — recursive helper for the above
 *   - AgentCommandGenerator    — (agent-command-generator.js) generates launcher .md files
 *                                 that tell the LLM to load a compiled agent .md file
 *   - agent-command-template.md — (templates/) the launcher template with hardcoded
 *                                 {module}/agents/{{path}} reference
 *
 * Agent metadata for agent-manifest.csv is now handled entirely by
 * ManifestGenerator.getAgentsFromDirRecursive() in manifest-generator.js,
 * which walks the full module tree and finds type:agent directories.
 *
 * IDE installation of agents is handled by the native skill pipeline —
 * each agent's SKILL.md directory is installed directly to the IDE's
 * skills path, so no launcher intermediary is needed.
 *
 * Cleanup: remove getAgentsFromBmad, getAgentsFromDir, their exports,
 * AgentCommandGenerator, agent-command-template.md, and all call sites
 * in IDE installers that invoke collectAgentArtifacts / writeAgentLaunchers /
 * writeColonArtifacts / writeDashArtifacts.
 * getTasksFromBmad and getTasksFromDir may still be live — verify before removing.
 */
async function getAgentsFromBmad(bmadDir, selectedModules = []) {
  const agents = [];

  // Get core agents
  if (await fs.pathExists(path.join(bmadDir, 'core', 'agents'))) {
    const coreAgents = await getAgentsFromDir(path.join(bmadDir, 'core', 'agents'), 'core');
    agents.push(...coreAgents);
  }

  // Get module agents
  for (const moduleName of selectedModules) {
    const agentsPath = path.join(bmadDir, moduleName, 'agents');

    if (await fs.pathExists(agentsPath)) {
      const moduleAgents = await getAgentsFromDir(agentsPath, moduleName);
      agents.push(...moduleAgents);
    }
  }

  // Get standalone agents from bmad/agents/ directory
  const standaloneAgentsDir = path.join(bmadDir, 'agents');
  if (await fs.pathExists(standaloneAgentsDir)) {
    const agentDirs = await fs.readdir(standaloneAgentsDir, { withFileTypes: true });

    for (const agentDir of agentDirs) {
      if (!agentDir.isDirectory()) continue;

      const agentDirPath = path.join(standaloneAgentsDir, agentDir.name);
      const agentFiles = await fs.readdir(agentDirPath);
      const skillManifest = await loadSkillManifest(agentDirPath);

      for (const file of agentFiles) {
        if (!file.endsWith('.md')) continue;
        if (file.includes('.customize.')) continue;

        const filePath = path.join(agentDirPath, file);
        const content = await fs.readFile(filePath, 'utf8');

        if (content.includes('localskip="true"')) continue;

        agents.push({
          path: filePath,
          name: file.replace('.md', ''),
          module: 'standalone', // Mark as standalone agent
          canonicalId: getCanonicalId(skillManifest, file),
        });
      }
    }
  }

  return agents;
}

async function getTasksFromBmad(bmadDir, selectedModules = []) {
  const tasks = [];

  if (await fs.pathExists(path.join(bmadDir, 'core', 'tasks'))) {
    const coreTasks = await getTasksFromDir(path.join(bmadDir, 'core', 'tasks'), 'core');
    tasks.push(...coreTasks);
  }

  for (const moduleName of selectedModules) {
    const tasksPath = path.join(bmadDir, moduleName, 'tasks');

    if (await fs.pathExists(tasksPath)) {
      const moduleTasks = await getTasksFromDir(tasksPath, moduleName);
      tasks.push(...moduleTasks);
    }
  }

  return tasks;
}

async function getAgentsFromDir(dirPath, moduleName, relativePath = '') {
  const agents = [];

  if (!(await fs.pathExists(dirPath))) {
    return agents;
  }

  const entries = await fs.readdir(dirPath, { withFileTypes: true });
  const skillManifest = await loadSkillManifest(dirPath);

  for (const entry of entries) {
    // Skip if entry.name is undefined or not a string
    if (!entry.name || typeof entry.name !== 'string') {
      continue;
    }

    const fullPath = path.join(dirPath, entry.name);
    const newRelativePath = relativePath ? `${relativePath}/${entry.name}` : entry.name;

    if (entry.isDirectory()) {
      // Recurse into subdirectories
      const subDirAgents = await getAgentsFromDir(fullPath, moduleName, newRelativePath);
      agents.push(...subDirAgents);
    } else if (entry.name.endsWith('.md')) {
      // Skip README files and other non-agent files
      if (entry.name.toLowerCase() === 'readme.md' || entry.name.toLowerCase().startsWith('readme-')) {
        continue;
      }

      if (entry.name.includes('.customize.')) {
        continue;
      }

      const content = await fs.readFile(fullPath, 'utf8');

      if (content.includes('localskip="true"')) {
        continue;
      }

      // Only include files that have agent-specific content (compiled agents have <agent> tag)
      if (!content.includes('<agent')) {
        continue;
      }

      agents.push({
        path: fullPath,
        name: entry.name.replace('.md', ''),
        module: moduleName,
        relativePath: newRelativePath, // Keep the .md extension for the full path
        canonicalId: getCanonicalId(skillManifest, entry.name),
      });
    }
  }

  return agents;
}

async function getTasksFromDir(dirPath, moduleName) {
  const tasks = [];

  if (!(await fs.pathExists(dirPath))) {
    return tasks;
  }

  const files = await fs.readdir(dirPath);
  const skillManifest = await loadSkillManifest(dirPath);

  for (const file of files) {
    // Include both .md and .xml task files
    if (!file.endsWith('.md') && !file.endsWith('.xml')) {
      continue;
    }

    const filePath = path.join(dirPath, file);
    const content = await fs.readFile(filePath, 'utf8');

    // Skip internal/engine files (not user-facing tasks)
    if (content.includes('internal="true"')) {
      continue;
    }

    // Remove extension to get task name
    const ext = file.endsWith('.xml') ? '.xml' : '.md';
    tasks.push({
      path: filePath,
      name: file.replace(ext, ''),
      module: moduleName,
      canonicalId: getCanonicalId(skillManifest, file),
    });
  }

  return tasks;
}

module.exports = {
  getAgentsFromBmad,
  getTasksFromBmad,
  getAgentsFromDir,
  getTasksFromDir,
};
