import { createLogger } from "../utils/logger/index.js";
import { init_logger } from "../utils/logger.js";
import { init_agent_scope, resolveDefaultAgentId } from "../agent/agent-scope.js";
import { init_paths, resolveBundledExtensionsDir, resolveExtensionsDir, resolveWorkspaceExtensionsDir } from "../config/paths.js";
import { init_loader, loadConfig } from "../config/loader.js";
import { normalizeExtensionManifest } from "./normalize-manifest.js";
import { join } from "path";
import { existsSync, readFileSync, readdirSync } from "fs";
//#region src/extensions/discover-extensions.ts
/**
* Filesystem-only extension discovery (manifest parse, no module load).
*/
init_agent_scope();
init_loader();
init_paths();
init_logger();
function asSchemaConfig(config) {
	return config;
}
const EXTENSION_MANIFEST_FILE = "xopc.extension.json";
const log = createLogger("ExtensionDiscover");
function isRecord(x) {
	return typeof x === "object" && x !== null && !Array.isArray(x);
}
function loadManifest(extensionPath) {
	const manifestPath = join(extensionPath, EXTENSION_MANIFEST_FILE);
	if (existsSync(manifestPath)) try {
		const raw = JSON.parse(readFileSync(manifestPath, "utf-8"));
		if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
			log.error({ manifestPath }, "Manifest root must be a JSON object");
			return null;
		}
		return normalizeExtensionManifest(raw);
	} catch (error) {
		log.error({
			err: error,
			manifestPath
		}, "Failed to parse manifest");
		return null;
	}
	const packagePath = join(extensionPath, "package.json");
	if (existsSync(packagePath)) try {
		const packageJson = JSON.parse(readFileSync(packagePath, "utf-8"));
		if (packageJson.xopc?.extension) {
			const xopcConfig = packageJson.xopc;
			return normalizeExtensionManifest({
				id: xopcConfig.id || packageJson.name,
				name: xopcConfig.name || packageJson.name,
				description: xopcConfig.description || packageJson.description,
				version: xopcConfig.version || packageJson.version || "1.0.0",
				kind: xopcConfig.kind || "utility",
				main: xopcConfig.main || packageJson.main || "index.js",
				configSchema: xopcConfig.configSchema
			});
		}
		if (packageJson.name?.startsWith("xopc-extension-")) return normalizeExtensionManifest({
			id: packageJson.name.replace("xopc-extension-", ""),
			name: packageJson.name,
			description: packageJson.description,
			version: packageJson.version || "1.0.0",
			kind: "utility",
			main: packageJson.main || "index.js"
		});
	} catch (error) {
		log.error({
			err: error,
			packagePath
		}, "Failed to parse package.json");
	}
	return null;
}
function discoverInDirectory(dir, source, discovered) {
	if (!existsSync(dir)) return;
	let entries;
	try {
		entries = readdirSync(dir);
	} catch {
		return;
	}
	for (const entry of entries) {
		const extensionPath = join(dir, entry);
		try {
			if (!existsSync(extensionPath)) continue;
		} catch {
			continue;
		}
		const manifest = loadManifest(extensionPath);
		if (!manifest) continue;
		const extensionId = manifest.id || entry;
		const existing = discovered.get(extensionId);
		if (existing) {
			const priority = {
				workspace: 3,
				global: 2,
				bundled: 1,
				config: 0
			};
			if (priority[source] <= priority[existing.source]) {
				log.debug({
					extensionId,
					from: source,
					existing: existing.source
				}, "Skipping lower priority extension");
				continue;
			}
			log.info({
				extensionId,
				from: source,
				overriding: existing.source
			}, "Extension override by higher priority source");
		}
		discovered.set(extensionId, {
			id: extensionId,
			path: extensionPath,
			source,
			manifest
		});
	}
}
function resolveDiscoveryPaths(options, config) {
	const cfg = asSchemaConfig(config ?? loadConfig());
	const aid = resolveDefaultAgentId(cfg);
	return {
		bundledDir: resolveBundledExtensionsDir(),
		globalDir: options.extensionsDir ?? resolveExtensionsDir(),
		workspaceExtensionsDir: options.workspaceExtensionsDir ?? resolveWorkspaceExtensionsDir(cfg, aid)
	};
}
/**
* Discover extensions from workspace, global, and bundled tiers without loading code.
*/
function discoverExtensionsFromDisk(options = {}, config) {
	const discovered = /* @__PURE__ */ new Map();
	const paths = resolveDiscoveryPaths(options, config);
	if (paths.bundledDir) discoverInDirectory(paths.bundledDir, "bundled", discovered);
	discoverInDirectory(paths.globalDir, "global", discovered);
	discoverInDirectory(paths.workspaceExtensionsDir, "workspace", discovered);
	return Array.from(discovered.values());
}
/** True when extension discovery/load should be skipped entirely. */
function areExtensionsGloballyDisabled(config) {
	if (process.env.XOPC_SKIP_EXTENSIONS === "1" || process.env.XOPC_SKIP_EXTENSIONS === "true") return true;
	return (config && isRecord(config) && isRecord(config.extensions) ? config.extensions : void 0)?.enabled === false;
}
//#endregion
export { areExtensionsGloballyDisabled, discoverExtensionsFromDisk };

//# sourceMappingURL=discover-extensions.js.map