/**
 * PluginImporter Service
 *
 * Composes S01-S04 modules into a staged discover → select → validate → commit pipeline.
 * Each stage is independently testable. The service owns no UI — it produces data structures
 * that the command layer (T02) consumes.
 *
 * Pipeline stages:
 * 1. discover(marketplacePaths) - Read marketplace manifests, populate registry
 * 2. selectComponents(filter) - Filter to user-chosen components
 * 3. validateImport(selected) - Check for collisions, return diagnostics
 * 4. getImportManifest(selected) - Produce serializable config structure
 *
 * This service implements R012 (discover/select/import flow) and R013 (canonical name preservation).
 */
import { analyzeCollisions } from "./collision-diagnostics.js";
import { SF_STALE_STATE, SFError } from "./errors.js";
import { discoverMarketplace } from "./marketplace-discovery.js";
import {
	componentsFromDiscovery,
	NamespacedRegistry,
} from "./namespaced-registry.js";
import { NamespacedResolver } from "./namespaced-resolver.js";
// ============================================================================
// PluginImporter Class
// ============================================================================
/**
 * Service for discovering, selecting, validating, and importing plugin components.
 *
 * Usage:
 * ```typescript
 * const importer = new PluginImporter();
 *
 * // Stage 1: Discover
 * const discovery = importer.discover(['../claude-plugins']);
 *
 * // Stage 2: Select
 * const selected = importer.selectComponents(c => c.namespace === 'my-plugin');
 *
 * // Stage 3: Validate
 * const validation = importer.validateImport(selected);
 * if (!validation.canProceed) {
 *   console.error('Cannot import:', validation.diagnostics);
 *   return;
 * }
 *
 * // Stage 4: Get manifest for persistence
 * const manifest = importer.getImportManifest(selected);
 * ```
 */
export class PluginImporter {
	/** The internal registry populated during discovery */
	registry = null;
	/** All discovered plugins from the last discovery run */
	discoveredPlugins = [];
	/** Last discovery result for inspection */
	lastDiscoveryResult = null;
	/** Last validation result for inspection */
	lastValidationResult = null;
	/**
	 * Stage 1: Discover plugins from marketplace paths.
	 *
	 * Calls `discoverMarketplace()` for each path and populates a `NamespacedRegistry`
	 * via `componentsFromDiscovery()`.
	 *
	 * @param marketplacePaths - Array of paths to marketplace directories
	 * @returns Discovery result with registry and summary
	 */
	discover(marketplacePaths) {
		// Reset state for fresh discovery
		this.registry = new NamespacedRegistry();
		this.discoveredPlugins = [];
		this.lastValidationResult = null;
		const marketplaceResults = [];
		let marketplacesWithErrors = 0;
		let pluginsWithErrors = 0;
		// Process each marketplace path
		for (const marketplacePath of marketplacePaths) {
			const result = discoverMarketplace(marketplacePath);
			marketplaceResults.push(result);
			if (result.status === "error") {
				marketplacesWithErrors++;
			}
			// Collect all plugins
			for (const plugin of result.plugins) {
				this.discoveredPlugins.push(plugin);
				if (plugin.status === "error") {
					pluginsWithErrors++;
				}
				// Convert plugin inventory to components and register
				const components = componentsFromDiscovery(plugin);
				for (const component of components) {
					this.registry.register(component);
				}
			}
		}
		// Build summary
		const summary = {
			marketplacesProcessed: marketplacePaths.length,
			marketplacesWithErrors,
			totalPlugins: this.discoveredPlugins.length,
			pluginsWithErrors,
			totalComponents: this.registry.size,
		};
		this.lastDiscoveryResult = {
			marketplaceResults,
			plugins: this.discoveredPlugins,
			registry: this.registry,
			summary,
		};
		return this.lastDiscoveryResult;
	}
	/**
	 * Stage 2: Select components by filter function.
	 *
	 * Returns a filtered subset of registered components.
	 * Must be called after discover().
	 *
	 * @param componentFilter - Filter function returning true for selected components
	 * @returns Array of selected components
	 */
	selectComponents(componentFilter) {
		if (!this.registry) {
			throw new SFError(
				SF_STALE_STATE,
				"Must call discover() before selectComponents()",
			);
		}
		return this.registry.getAll().filter(componentFilter);
	}
	/**
	 * Stage 3: Validate selected components for import.
	 *
	 * Builds a `NamespacedResolver`, runs `analyzeCollisions()`, and returns
	 * `{ diagnostics, canProceed }` where `canProceed` is false if any
	 * error-severity diagnostics exist.
	 *
	 * @param selected - Array of components to validate
	 * @returns Validation result with diagnostics and proceed flag
	 */
	validateImport(selected) {
		if (!this.registry) {
			throw new SFError(
				SF_STALE_STATE,
				"Must call discover() before validateImport()",
			);
		}
		// Create a temporary resolver for the selected components
		const tempRegistry = new NamespacedRegistry();
		// Register only selected components into temp registry
		for (const component of selected) {
			tempRegistry.register({
				name: component.name,
				namespace: component.namespace,
				type: component.type,
				filePath: component.filePath,
				source: component.source,
				description: component.description,
				metadata: component.metadata,
			});
		}
		// Create resolver and analyze collisions
		const resolver = new NamespacedResolver(tempRegistry);
		const diagnostics = analyzeCollisions(tempRegistry, resolver);
		// Count by severity
		const errors = diagnostics.filter((d) => d.severity === "error").length;
		const warnings = diagnostics.filter((d) => d.severity === "warning").length;
		const summary = {
			total: diagnostics.length,
			errors,
			warnings,
		};
		// canProceed is false if any error-severity diagnostics exist
		const canProceed = errors === 0;
		this.lastValidationResult = {
			diagnostics,
			canProceed,
			summary,
		};
		return this.lastValidationResult;
	}
	/**
	 * Stage 4: Generate import manifest for selected components.
	 *
	 * Produces a serializable config structure with canonical names preserved.
	 * The manifest can be persisted to config files.
	 *
	 * @param selected - Array of components to include in manifest
	 * @returns Import manifest with all entries and metadata
	 */
	getImportManifest(selected) {
		const entries = selected.map((component) => ({
			canonicalName: component.canonicalName,
			type: component.type,
			name: component.name,
			namespace: component.namespace,
			filePath: component.filePath,
			source: component.source,
			description: component.description,
			metadata: {
				pluginVersion: component.metadata.pluginVersion,
				pluginAuthor: component.metadata.pluginAuthor,
				pluginHomepage: component.metadata.pluginHomepage,
				pluginCategory: component.metadata.pluginCategory,
			},
		}));
		// Count by type
		const skills = entries.filter((e) => e.type === "skill").length;
		const agents = entries.filter((e) => e.type === "agent").length;
		// Collect unique namespaces
		const namespaces = Array.from(
			new Set(entries.map((e) => e.namespace).filter((n) => n !== undefined)),
		).sort();
		return {
			schemaVersion: "1.0",
			generatedAt: new Date().toISOString(),
			entries,
			summary: {
				total: entries.length,
				skills,
				agents,
				namespaces,
			},
		};
	}
	/**
	 * Get the internal registry for inspection.
	 * Useful for debugging or advanced filtering.
	 *
	 * @returns The registry or null if discover() hasn't been called
	 */
	getRegistry() {
		return this.registry;
	}
	/**
	 * Get all discovered plugins.
	 *
	 * @returns Array of discovered plugins
	 */
	getDiscoveredPlugins() {
		return this.discoveredPlugins;
	}
	/**
	 * Get the last validation result.
	 * Useful for re-inspecting validation without re-running.
	 *
	 * @returns Last validation result or null
	 */
	getLastValidation() {
		return this.lastValidationResult;
	}
	/**
	 * Get the last discovery result.
	 * Useful for re-inspecting discovery without re-running.
	 *
	 * @returns Last discovery result or null
	 */
	getLastDiscovery() {
		return this.lastDiscoveryResult;
	}
}
// ============================================================================
// Exports
// ============================================================================
export default PluginImporter;
