import type { ConsolaInstance } from "consola";
import type { AnyProvider, ExtensionManifest, ProviderType } from "@/providers";
import { createLogger } from "@/utils/logger";

/**
 * Extension error class for extension-related errors
 */
export class ExtensionError extends Error {
	constructor(message: string, options?: ErrorOptions) {
		super(message, options);
		this.name = "ExtensionError";
	}
}

/**
 * Abstract base class for manifest-based extensions
 * Provides common functionality for extensions that use the manifest system
 */
export abstract class BaseExtension {
	protected providers = new Map<ProviderType, AnyProvider>();
	protected manifest: ExtensionManifest;
	protected logger: ConsolaInstance;

	constructor(manifest: ExtensionManifest) {
		this.manifest = manifest;
		this.logger = createLogger(this.manifest.name);
	}

	/**
	 * Initialize extension resources
	 * Subclasses should implement this to set up any resources needed
	 * Note: Provider instantiation is handled by the server
	 */
	abstract initialize(): Promise<void>;

	/**
	 * Cleanup and dispose resources
	 * Subclasses can override this to add custom cleanup logic
	 */
	async dispose(): Promise<void> {
		this.logger.debug("Disposing extension...");

		// Cleanup providers - they all implement IProviderLifecycle
		for (const [type, provider] of this.providers) {
			try {
				await provider.dispose();
			} catch (error) {
				this.logger.error(`Failed to dispose provider ${type}:`, error);
			}
		}

		this.providers.clear();
		this.logger.info("Extension disposed");
	}

	/**
	 * Get extension manifest
	 */
	getManifest(): ExtensionManifest {
		return this.manifest;
	}

	/**
	 * Get specific provider by type
	 */
	getProvider(type: ProviderType): AnyProvider | undefined {
		return this.providers.get(type);
	}

	/**
	 * Get all active providers
	 */
	getProviders(): Map<ProviderType, AnyProvider> {
		return new Map(this.providers);
	}

	/**
	 * Check if extension supports provider type
	 */
	supportsProvider(type: ProviderType): boolean {
		return this.providers.has(type);
	}

	/**
	 * Get list of supported provider types
	 */
	getSupportedTypes(): ProviderType[] {
		return Array.from(this.providers.keys());
	}

	/**
	 * Add a provider to the internal provider map
	 * This method is called by the server after instantiating providers
	 * @param type - Provider type
	 * @param provider - Provider instance
	 * @internal This method should only be called by ExtensionService
	 */
	addProvider(type: ProviderType, provider: AnyProvider): void {
		this.providers.set(type, provider);
	}

	/**
	 * Get provider count
	 */
	getProviderCount(): number {
		return this.providers.size;
	}
}
