import { IMovieSearchInfo, ITorrentLink } from "@autoplex-api/torrent-search/dist/typings";
import { InternalService } from "@autoplex/microservice";
import { MediaType, Provider, providers } from "../torrents/providers";
import { rankTorrents } from "../torrents/ranking";
import Torrent from "../torrents/Torrent";

export default class TorrentSearch extends InternalService
{
	/**
	 * The name of the service
	 */
	public readonly NAME = "Torrent Search";

	/**
	 * Store all providers
	 */
	protected providers!: Provider[];

	/**
	 * Store a list of movie prodivers
	 */
	protected movieProviders!: Provider[];

	/**
	 * Store a list of TV providers
	 */
	protected tvProviders!: Provider[];

	/**
	 * Boot the torrent search sorvice
	 */
	public async boot() {
		let providerClasses = Object.values(providers);
		this.providers = providerClasses.map(ProviderClass => new ProviderClass());
		this.movieProviders = this.providers.filter(provider => provider.PROVIDES & MediaType.Movies);
		this.tvProviders = this.providers.filter(provider => provider.PROVIDES & MediaType.TvShows);
	}

	/**
	 * Filter duplicate and blacklisted torrents
	 */
	protected filterTorrents(torrents: Torrent[], blacklist: string[]) {
		let toRemove = new Set(blacklist);
		return torrents.filter(torrent => {
			let infoHash = torrent.infoHash();
			if (infoHash === null) {
				return true;
			}
			if (toRemove.has(infoHash)) {
				return false;
			}
			toRemove.add(infoHash);
			return true;
		});
	}

	/**
	 * Search for a movie
	 */
	public async searchMovie(movie: IMovieSearchInfo) {
		let results = await Promise.all(this.movieProviders.map(provider => provider.searchMovie(movie)));
		let torrents = (<Torrent[]>[]).concat(...results);

		torrents = this.filterTorrents(torrents, movie.torrentBlacklist);
		if (torrents.length == 0) {
			return null;
		}
		// Determine the preferred torrents
		let preferredTorrents = rankTorrents(torrents);
		if (preferredTorrents.length == 0) {
			preferredTorrents = torrents;
		}
		// Return the selected torrent
		this.log("Found movie torrent for", movie.title);
		let link = await preferredTorrents[0].downloadLink();
		return <ITorrentLink>{
			link,
			type: link.toLowerCase().startsWith("magnet:?xt=urn:btih:") ? "magnet" : "file"
		};
	}
}
