import { Cache } from '~/models/cache.model';
import type { Immutable } from '~/models/immutable.model';
import logger from '~/modules/logger';
import scraper from '~/modules/scraper';
import type { SearchResults } from '@rt_lite/scraper/dist/models/search-results';
import { time } from '~/utilities/time.utility';
import type {
	MediaSet,
	Movie,
	TVSeries
} from '@rt_lite/common/models';

/* eslint-disable @typescript-eslint/no-magic-numbers */
const DEFAULT_CACHE_ARGS = {
	maxSize: 100,
	ttl: time(6).hours
};
/* eslint-enable @typescript-eslint/no-magic-numbers */

let frontPageSets: MediaSet[] = [];
let frontPageSetsTimestamp = Infinity;

const searchCache = new Cache<SearchResults>({ ...DEFAULT_CACHE_ARGS });
const moviesCache = new Cache<Movie[]>({ ...DEFAULT_CACHE_ARGS });
const tvCache = new Cache<TVSeries[]>({ ...DEFAULT_CACHE_ARGS });

const refreshFrontPageSets = async (): Promise<void> => {
	logger.info('Refreshing front page sets');

	const sets = await scraper.getFrontPageSets();

	if (sets.length < 1) return;

	frontPageSets = [...sets];
	frontPageSetsTimestamp = Date.now();
};

const generateSearch = <T> (
	cache: Immutable<Cache<T>>,
	fetcher: (terms: string) => Promise<T>
): (terms: string) => Promise<T> => async (terms: string): Promise<T> => {
	const updateCache = async (): Promise<T> => {
		const fetchedResults = await fetcher(terms);

		cache.set(terms, fetchedResults);

		return fetchedResults;
	};

	if (cache.has(terms)) {
		const cachedResults = cache.get(terms);

		if (cachedResults !== null) {
			// eslint-disable-next-line @typescript-eslint/no-floating-promises
			updateCache();

			return cachedResults;
		}
	}

	const results = await updateCache();

	return results;
};

export const search = generateSearch(searchCache, scraper.findMedia.bind(scraper));

export const searchMovies = generateSearch(moviesCache, scraper.findMovies.bind(scraper));

export const searchTV = generateSearch(tvCache, scraper.findTVSeries.bind(scraper));

export const frontPage = async (): Promise<MediaSet[]> => {
	if (frontPageSets.length > 0) {
		// eslint-disable-next-line @typescript-eslint/no-floating-promises
		if (Date.now() - frontPageSetsTimestamp > DEFAULT_CACHE_ARGS.ttl) refreshFrontPageSets();

		return frontPageSets;
	}

	await refreshFrontPageSets();

	return frontPageSets;
};
