/**
 * Stage registry.
 * Resolves stage names to handlers. Built-in stages are always available.
 * Custom stages can be loaded from ~/.mcpctl/stages/ at runtime.
 */
import type { StageHandler } from './types.js';
import { BUILT_IN_STAGES } from './stages/index.js';

const customStages = new Map<string, StageHandler>();

/** Counter for cache-busting dynamic imports on reload. */
let loadGeneration = 0;

/**
 * Load custom stages from a directory.
 * Each .js file exports a default StageHandler.
 * Uses a generation counter to bust Node's module cache on reload.
 */
export async function loadCustomStages(dir: string): Promise<void> {
  const { readdir } = await import('node:fs/promises');
  const { join } = await import('node:path');
  const { pathToFileURL } = await import('node:url');

  customStages.clear();
  loadGeneration++;
  try {
    const files = await readdir(dir);
    for (const file of files) {
      if (!file.endsWith('.js') && !file.endsWith('.mjs')) continue;
      const name = file.replace(/\.(m?js)$/, '');
      try {
        // Append generation query to bust Node's import cache
        const url = `${pathToFileURL(join(dir, file)).href}?v=${loadGeneration}`;
        const mod = await import(url) as { default?: StageHandler };
        if (typeof mod.default === 'function') {
          customStages.set(name, mod.default);
        } else {
          console.warn(`[stage-registry] ${file} does not export a default function, skipping`);
        }
      } catch (err) {
        console.warn(`[stage-registry] Failed to load ${file}: ${(err as Error).message}`);
      }
    }
  } catch {
    // Directory doesn't exist — no custom stages
  }
}

/** Get a stage handler by name. Custom stages override built-ins. */
export function getStage(name: string): StageHandler | null {
  return customStages.get(name) ?? BUILT_IN_STAGES.get(name) ?? null;
}

/** List all available stages with their source. */
export function listStages(): { name: string; source: 'built-in' | 'local' }[] {
  const result: { name: string; source: 'built-in' | 'local' }[] = [];

  for (const name of BUILT_IN_STAGES.keys()) {
    result.push({
      name,
      source: customStages.has(name) ? 'local' : 'built-in',
    });
  }

  for (const name of customStages.keys()) {
    if (!BUILT_IN_STAGES.has(name)) {
      result.push({ name, source: 'local' });
    }
  }

  return result;
}

/** Clear all custom stages (for testing). */
export function clearCustomStages(): void {
  customStages.clear();
}
