import faker from '@faker-js/faker';
import scraper from '~/modules/scraper';
import {
	frontPage,
	search,
	searchMovies,
	searchTV
} from '~/services/rt.service';
import type {
	MediaSet,
	Movie,
	SearchResults,
	TVSeries
} from '@rt_lite/common/models';

jest.mock('~/modules/scraper', () => ({
	findMedia: jest.fn(),
	findMovies: jest.fn(),
	findTVSeries: jest.fn(),
	getFrontPageSets: jest.fn()
}));

jest.mock('~/modules/logger', () => ({
	error: jest.fn(),
	info: jest.fn(),
	log: jest.fn(),
	success: jest.fn(),
	warn: jest.fn()
}));

const getMockArr = <T> (): T[] => new Array(10)
	.fill(null)
	.map(() => JSON.parse(faker.datatype.json()) as unknown as T);

describe('rt.service', () => {
	afterEach(() => {
		jest.clearAllMocks();
	});

	test('search', async () => {
		expect.assertions(3);

		const mockResults: SearchResults = {
			movies: getMockArr<Movie>(),
			tvSeries: getMockArr<TVSeries>()
		};

		(scraper.findMedia as jest.Mock)
			.mockImplementationOnce(async () => Promise.resolve(mockResults));

		const terms = faker.lorem.words(3);

		const firstResult = await search(terms);

		expect(firstResult).toStrictEqual(mockResults);
		expect(scraper.findMedia).toHaveBeenCalledTimes(1);
		expect(scraper.findMedia).toHaveBeenCalledWith(terms);
	});

	test('searchMovies', async () => {
		expect.assertions(3);

		const mockMovies = getMockArr<Movie>();

		(scraper.findMovies as jest.Mock)
			.mockImplementationOnce(async () => Promise.resolve(mockMovies));

		const terms = faker.lorem.words(3);

		const firstResult = await searchMovies(terms);

		expect(firstResult).toStrictEqual(mockMovies);
		expect(scraper.findMovies).toHaveBeenCalledTimes(1);
		expect(scraper.findMovies).toHaveBeenCalledWith(terms);
	});

	test('searchTV', async () => {
		expect.assertions(3);

		const mockTVSeries = getMockArr<TVSeries>();

		(scraper.findTVSeries as jest.Mock)
			.mockImplementationOnce(async () => Promise.resolve(mockTVSeries));

		const terms = faker.lorem.words(3);

		const firstResult = await searchTV(terms);

		expect(firstResult).toStrictEqual(mockTVSeries);
		expect(scraper.findTVSeries).toHaveBeenCalledTimes(1);
		expect(scraper.findTVSeries).toHaveBeenCalledWith(terms);
	});

	test('frontPage', async () => {
		expect.assertions(2);

		const mockFrontPageSets = getMockArr<MediaSet>();

		(scraper.getFrontPageSets as jest.Mock)
			.mockImplementationOnce(async () => Promise.resolve(mockFrontPageSets));

		const firstResult = await frontPage();

		expect(firstResult).toStrictEqual(mockFrontPageSets);
		expect(scraper.getFrontPageSets).toHaveBeenCalledTimes(1);
	});
});
