<script lang="ts">
	import { mediaListCollection, Type, type Media } from '$lib/AniList/media';
	import type { UserIdentity, AniListAuthorisation } from '$lib/AniList/identity';
	import { onDestroy, onMount } from 'svelte';
	import { chapterCount, pruneAllManga } from '$lib/Media/manga';
	import manga from '../../../stores/manga';
	import { chapterDatabase } from '$lib/Media/chapters';
	import settings from '../../../stores/settings';
	import lastPruneTimes from '../../../stores/lastPruneTimes';
	import ListTitle from '../ListTitle.svelte';
	import Error from '$lib/Error.svelte';
	import CleanMangaList from '../CleanMangaList.svelte';

	export let user: AniListAuthorisation;
	export let identity: UserIdentity;
	export let displayUnresolved: boolean;
	export let due: boolean;

	let mangaLists: Promise<Media[]>;
	let startTime: number;
	let endTime: number;
	let lastUpdatedMedia = -1;
	let previousMangaList: Media[];
	let pendingUpdate: number | null = null;

	const keyCacher = setInterval(() => {
		startTime = performance.now();
		endTime = -1;
		mangaLists = mediaListCollection(user, identity, Type.Manga, $manga, $lastPruneTimes.manga);
	}, $settings.cacheMinutes * 1000 * 60);

	onMount(async () => {
		startTime = performance.now();
		mangaLists = mediaListCollection(user, identity, Type.Manga, $manga, $lastPruneTimes.manga);
	});

	onDestroy(() => clearInterval(keyCacher));

	const cleanMedia = async (media: Media[], displayUnresolved: boolean) => {
		if (media === undefined) {
			return [];
		}

		if ($lastPruneTimes.chapters === 1) {
			lastPruneTimes.setKey('chapters', new Date().getTime());
		} else {
			const currentDate = new Date();

			if (
				(currentDate.getTime() - $lastPruneTimes.chapters) / 1000 / 60 >
				$settings.cacheMangaMinutes
			) {
				const unresolved = await chapterDatabase.chapters.where('chapters').equals(-1).toArray();
				const ids = unresolved.map((m) => m.id);

				lastPruneTimes.setKey('chapters', currentDate.getTime());
				await chapterDatabase.chapters.bulkDelete(ids);
			}
		}

		const releasingMedia = media.filter(
			(media: Media) =>
				(due ? media.status === 'RELEASING' : media.status === 'FINISHED') &&
				(media.mediaListEntry || { status: 'DROPPED' }).status !==
					($settings.displayPausedMedia ? '' : 'PAUSED') &&
				(media.mediaListEntry || { progress: 0 }).progress >=
					($settings.displayNotStarted === true ? 0 : 1)
		);
		let finalMedia = releasingMedia;
		const chapterPromises = finalMedia.map((m: Media) => chapterCount(identity, m));
		const chapterCounts = await Promise.all(chapterPromises);

		finalMedia.forEach((m: Media, i) => {
			m.episodes = chapterCounts[i] || -1337;
		});

		if (!displayUnresolved) {
			finalMedia = finalMedia.filter((m: Media) => m.episodes !== -1337);
		}

		finalMedia.sort((a: Media, b: Media) => {
			return (
				(a.episodes || 9999) -
				(a.mediaListEntry || { progress: 0 }).progress -
				((b.episodes || 9999) - (b.mediaListEntry || { progress: 0 }).progress)
			);
		});

		finalMedia = finalMedia.filter((item, index, array) => {
			return (
				array.findIndex((i) => {
					return i.id === item.id;
				}) === index &&
				(item.episodes === -1337 && displayUnresolved
					? true
					: (item.mediaListEntry?.progress || 0) <
					  ($settings.roundDownChapters === true ? Math.floor(item.episodes) : item.episodes))
			);
		});

		if (!endTime || endTime === -1) {
			endTime = performance.now() - startTime;
		}

		return finalMedia;
	};

	const updateMedia = async (id: number, progress: number | undefined, media: Media[]) => {
		pendingUpdate = id;

		await chapterDatabase.chapters.delete(id);
		await fetch(`/api/anilist-increment?id=${id}&progress=${(progress || 0) + 1}`).then(() => {
			previousMangaList = media;
			media.find((m) => m.id === id)!.mediaListEntry!.progress = (progress || 0) + 1;
			mangaLists = mediaListCollection(
				user,
				identity,
				Type.Manga,
				$manga,
				$lastPruneTimes.manga,
				true
			);
			lastUpdatedMedia = id;
			pendingUpdate = null;
		});
	};

	const cleanCache = async () => {
		endTime = -1;

		await pruneAllManga();

		mangaLists = mediaListCollection(
			user,
			identity,
			Type.Manga,
			$manga,
			$lastPruneTimes.manga,
			true
		);
	};
</script>

{#await mangaLists}
	{#if previousMangaList}
		<CleanMangaList
			media={previousMangaList}
			{cleanCache}
			{endTime}
			{lastUpdatedMedia}
			{updateMedia}
			disableIncrement
			{pendingUpdate}
		/>
	{:else}
		<ListTitle />

		<ul><li>Loading ...</li></ul>
	{/if}
{:then media}
	{#await cleanMedia(media, displayUnresolved)}
		{#if previousMangaList}
			<CleanMangaList
				media={previousMangaList}
				{cleanCache}
				{endTime}
				{lastUpdatedMedia}
				{updateMedia}
				disableIncrement
				{pendingUpdate}
			/>
		{:else}
			<ListTitle />

			<ul><li>Loading ...</li></ul>
		{/if}
	{:then cleanedMedia}
		<CleanMangaList
			media={cleanedMedia}
			{cleanCache}
			{endTime}
			{lastUpdatedMedia}
			{updateMedia}
			{pendingUpdate}
		/>
	{:catch}
		<ListTitle count={-1337} time={0} />

		<Error />
	{/await}
{/await}
