import type {
	MovieInfo,
	PersonInfo,
	ResolvedMovieMetadataResult,
	ResolvedPersonResult,
	ResolvedSeriesMetadataResult,
	ResolvedTitleCreditsResult,
	SeriesInfo,
	TitleCreditsInfo,
} from "@/models";
import type { MetadataProviderRegistry } from "@/providers";
import { BaseService, ServiceError } from "../BaseService";
import { ExtensionService } from "../extensions";

export class MetadataService extends BaseService {
	public isRunning = false;

	private registry: MetadataProviderRegistry | null = null;

	constructor() {
		super("MetadataService");
	}

	private get extensions(): ExtensionService {
		return this.services.get(ExtensionService);
	}

	public async mount(): Promise<void> {
		this.logger.info("Mounting metadata service.");
		this.refreshProviders();
		await this.ensureReadyForScanning();
		this.isRunning = true;
	}

	public async dispose(): Promise<void> {
		this.logger.info("Disposing metadata service.");
		this.registry = null;
		this.isRunning = false;
	}

	public async ensureReadyForScanning(): Promise<void> {
		if (!this.registry || !this.registry.hasProviders()) {
			throw new ServiceError(
				"No metadata providers available. Ensure at least one extension with metadata capability is registered.",
			);
		}
		const counts = this.registry.getProviderCounts();
		this.logger.debug(
			`Preparing metadata indices using ${counts.total} provider(s) (${counts.movie} movie, ${counts.series} series, ${counts.person} person).`,
		);
	}

	public getProviderRegistry(): MetadataProviderRegistry | null {
		return this.registry;
	}

	public async resolveMovie(
		info: MovieInfo,
	): Promise<ResolvedMovieMetadataResult> {
		if (!this.registry) return null;

		const providers = this.registry.getMovieProviders();
		for (const provider of providers) {
			try {
				return await provider.resolve(info);
			} catch (error) {
				this.logger.warn("Movie provider failed to resolve metadata.", error);
			}
		}
		return null;
	}

	public async resolveSeries(
		info: SeriesInfo,
	): Promise<ResolvedSeriesMetadataResult> {
		if (!this.registry) return null;

		const providers = this.registry.getSeriesProviders();
		for (const provider of providers) {
			try {
				return await provider.resolve(info);
			} catch (error) {
				this.logger.warn("Series provider failed to resolve metadata.", error);
			}
		}
		return null;
	}

	public async resolveTitleCredits(
		info: TitleCreditsInfo,
	): Promise<ResolvedTitleCreditsResult> {
		if (!this.registry) return null;

		// Credits are integrated into movie/series providers
		if (info.titleType === "MOVIE") {
			const providers = this.registry.getMovieProviders();
			for (const provider of providers) {
				try {
					// Check if provider supports credits resolution
					if (provider.resolveCredits) {
						return await provider.resolveCredits({ movieId: info.providerId });
					}
				} catch (error) {
					this.logger.warn("Movie provider failed to resolve credits.", error);
				}
			}
		} else if (info.titleType === "SERIES") {
			const providers = this.registry.getSeriesProviders();
			for (const provider of providers) {
				try {
					switch (info.area) {
						case "SERIES":
							// Series-level credits (main cast/crew)
							if (provider.resolveCredits) {
								return await provider.resolveCredits({
									providerId: info.providerId,
								});
							}
							break;

						case "SEASON":
							// Season-level credits (future feature)
							// if (provider.resolveCreditsForSeason) {
							// 	return await provider.resolveCreditsForSeason({
							// 		seriesId: info.providerId,
							// 		seasonNumber: info.seasonNumber,
							// 	});
							// }
							this.logger.warn(
								"Season-level credits resolution not yet implemented",
							);
							break;

						case "EPISODE":
							// Episode-level credits (guest stars)
							if (provider.resolveCreditsForEpisode) {
								return await provider.resolveCreditsForEpisode({
									seriesId: info.providerId,
									seasonNumber: info.seasonNumber,
									episodeNumber: info.episodeNumber,
								});
							}
							break;
					}
				} catch (error) {
					this.logger.warn("Series provider failed to resolve credits.", error);
				}
			}
		}

		return null;
	}

	public async resolvePerson(info: PersonInfo): Promise<ResolvedPersonResult> {
		if (!this.registry) return null;

		const providers = this.registry.getPersonProviders();
		for (const provider of providers) {
			try {
				return await provider.resolve(info);
			} catch (error) {
				this.logger.warn("Person provider failed to resolve details.", error);
			}
		}
		return null;
	}

	private refreshProviders(): void {
		this.registry = this.extensions.getProviderRegistry();
	}
}
