import { existsSync, readdirSync, readFileSync, statSync } from "node:fs";
import { join } from "node:path";
import { pathToFileURL } from "node:url";
import { getConfig } from "../config.js";
import { createLogger } from "../logger.js";
import { validatePluginExports } from "./validate.js";
const log = createLogger("server");
function readPluginPackageJson(pluginDir) {
  const pkgPath = join(pluginDir, "package.json");
  if (!existsSync(pkgPath)) {
    return null;
  }
  try {
    const raw = readFileSync(pkgPath, "utf-8");
    return JSON.parse(raw);
  } catch {
    return null;
  }
}
async function loadPlugins() {
  const config = getConfig();
  const pluginsDir = config.pluginsDir;
  const result = {
    extractors: [],
    searchEngines: [],
    loaded: [],
    errors: []
  };
  if (!existsSync(pluginsDir)) {
    log.debug("plugins directory does not exist, skipping", { path: pluginsDir });
    return result;
  }
  let entries;
  try {
    entries = readdirSync(pluginsDir);
  } catch (err) {
    log.warn("failed to read plugins directory", {
      path: pluginsDir,
      error: String(err)
    });
    return result;
  }
  const seenExtractorNames = /* @__PURE__ */ new Set();
  const seenEngineNames = /* @__PURE__ */ new Set();
  for (const entry of entries) {
    const pluginDir = join(pluginsDir, entry);
    let stat;
    try {
      stat = statSync(pluginDir);
    } catch {
      continue;
    }
    if (!stat.isDirectory()) {
      continue;
    }
    const pkgJson = readPluginPackageJson(pluginDir);
    const pluginName = pkgJson?.name ?? entry;
    if (pkgJson === null) {
      if (existsSync(join(pluginDir, "package.json"))) {
        result.errors.push({
          pluginName: entry,
          message: `failed to parse package.json in ${pluginDir}`
        });
      }
      continue;
    }
    if (!pkgJson.main) {
      result.errors.push({
        pluginName,
        message: `plugin ${pluginName} has no main field in package.json`
      });
      continue;
    }
    const entryPath = join(pluginDir, pkgJson.main);
    if (!existsSync(entryPath)) {
      result.errors.push({
        pluginName,
        message: `entry point not found: ${entryPath}`
      });
      continue;
    }
    let mod;
    try {
      const fileUrl = pathToFileURL(entryPath).href;
      mod = await import(fileUrl);
    } catch (err) {
      const message = err instanceof Error ? err.message : String(err);
      result.errors.push({
        pluginName,
        message: `failed to load plugin ${pluginName}: ${message}`
      });
      log.warn("plugin import failed", { plugin: pluginName, error: message });
      continue;
    }
    const validation = validatePluginExports(mod);
    if (validation.errors.length > 0) {
      for (const errMsg of validation.errors) {
        result.errors.push({ pluginName, message: errMsg });
      }
      log.warn("plugin validation failed", { plugin: pluginName, errors: validation.errors });
    }
    let registered = false;
    if (validation.hasExtractor) {
      const extractor = mod.extractor;
      if (seenExtractorNames.has(extractor.name)) {
        log.warn("duplicate extractor name, skipping", {
          plugin: pluginName,
          extractorName: extractor.name
        });
      } else {
        seenExtractorNames.add(extractor.name);
        result.extractors.push(extractor);
        registered = true;
        log.info("loaded plugin extractor", {
          plugin: pluginName,
          extractorName: extractor.name
        });
      }
    }
    if (validation.hasSearchEngine) {
      const engine = mod.searchEngine;
      if (seenEngineNames.has(engine.name)) {
        log.warn("duplicate search engine name, skipping", {
          plugin: pluginName,
          engineName: engine.name
        });
      } else {
        seenEngineNames.add(engine.name);
        result.searchEngines.push(engine);
        registered = true;
        log.info("loaded plugin search engine", {
          plugin: pluginName,
          engineName: engine.name
        });
      }
    }
    if (registered) {
      result.loaded.push({
        name: pluginName,
        version: pkgJson.version ?? "0.0.0",
        path: pluginDir,
        hasExtractor: validation.hasExtractor,
        hasSearchEngine: validation.hasSearchEngine
      });
    }
  }
  log.info("plugin loading complete", {
    extractors: result.extractors.length,
    searchEngines: result.searchEngines.length,
    errors: result.errors.length
  });
  return result;
}
export {
  loadPlugins
};
//# sourceMappingURL=loader.js.map