import type { BaseMovieProvider } from "./interfaces/movie";
import type { BasePersonProvider } from "./interfaces/person";
import type { BaseSeriesProvider } from "./interfaces/series";

/**
 * Provider types supported by the extension system
 */
export type ProviderType = "MOVIE" | "SERIES" | "PERSON";

/**
 * Union type of all provider interfaces
 */
export type AnyProvider =
	| BaseMovieProvider
	| BaseSeriesProvider
	| BasePersonProvider;

/**
 * Manifest definition for a single provider within an extension
 * Describes the type, class, and configuration for one provider
 */
export interface ProviderManifest<T extends AnyProvider = AnyProvider> {
	/** Type of provider: MOVIE, SERIES, or PERSON */
	type: ProviderType;

	/**
	 * Class constructor for the provider
	 * Accepts variable arguments to support different provider constructor signatures
	 */
	class: new (
		...args: any[]
	) => T;

	/** Unique name for this provider */
	name: string;

	/** Optional description of provider functionality */
	description?: string;

	/** Optional version string for this provider */
	version?: string;

	/** Whether provider is enabled (default: true) */
	enabled?: boolean;

	/** Optional configuration object for provider initialization */
	config?: Record<string, unknown>;
}

/**
 * Extension metadata containing author, homepage, etc.
 */
export interface ExtensionMetadata {
	/** Extension author name or organization */
	author?: string;

	/** Homepage URL for the extension */
	homepage?: string;

	/** Repository URL (e.g., GitHub) */
	repository?: string;

	/** Documentation URL */
	documentation?: string;
}

/**
 * Main manifest interface for an extension
 * Declares all providers and metadata for an extension
 */
export interface ExtensionManifest {
	/** Unique name for this extension */
	name: string;

	/** Semantic version string (e.g., "1.0.0") */
	version: string;

	/** Optional description of extension purpose */
	description?: string;

	/** Array of provider manifests this extension provides */
	providers: ProviderManifest[];

	/** Optional metadata about the extension */
	metadata?: ExtensionMetadata;
}

/**
 * Type guard to check if a provider is a movie provider
 */
export function isMovieProvider(
	provider: AnyProvider,
): provider is BaseMovieProvider {
	return "search" in provider && "resolve" in provider;
}

/**
 * Type guard to check if a provider is a series provider
 */
export function isSeriesProvider(
	provider: AnyProvider,
): provider is BaseSeriesProvider {
	return "search" in provider && "resolve" in provider;
}

/**
 * Type guard to check if a provider is a person provider
 */
export function isPersonProvider(
	provider: AnyProvider,
): provider is BasePersonProvider {
	return "search" in provider && "resolve" in provider;
}

/**
 * Validates an extension manifest structure
 * @param manifest - The manifest to validate
 * @returns True if valid, throws error if invalid
 */
export function validateExtensionManifest(
	manifest: unknown,
): manifest is ExtensionManifest {
	if (!manifest || typeof manifest !== "object") {
		throw new Error("Manifest must be an object");
	}

	const m = manifest as Partial<ExtensionManifest>;

	if (!m.name || typeof m.name !== "string") {
		throw new Error("Manifest must have a name string");
	}

	if (!m.version || typeof m.version !== "string") {
		throw new Error("Manifest must have a version string");
	}

	if (!Array.isArray(m.providers)) {
		throw new Error("Manifest must have a providers array");
	}

	for (const provider of m.providers) {
		if (
			!provider.type ||
			!["MOVIE", "SERIES", "PERSON"].includes(provider.type)
		) {
			throw new Error(
				`Provider must have a valid type (MOVIE, SERIES, or PERSON). Got: ${provider.type}`,
			);
		}

		if (!provider.class || typeof provider.class !== "function") {
			throw new Error("Provider must have a class constructor");
		}

		if (!provider.name || typeof provider.name !== "string") {
			throw new Error("Provider must have a name string");
		}
	}

	return true;
}
