<script lang="ts">
import { onMount } from "svelte";
import { hydrateMediaListCache } from "$lib/Data/AniList/cacheHydration";
import type { AniListAuthorisation } from "$lib/Data/AniList/identity";
import { type Media, mediaListCollection, Type } from "$lib/Data/AniList/media";
import Spacer from "$lib/Layout/Spacer.svelte";
import {
	hasDueEpisodes,
	hasNoAiredEpisodes,
} from "$lib/Media/Anime/Airing/classify";
import { injectAiringTime } from "$lib/Media/Anime/Airing/Subtitled/match";
import type { SubsPlease } from "$lib/Media/Anime/Airing/Subtitled/subsPlease";
import { addNotification } from "$lib/Notification/store";
import anime from "$stores/anime";
import identity from "$stores/identity";
import lastPruneTimes from "$stores/lastPruneTimes";
import locale from "$stores/locale";
import revalidateAnime from "$stores/revalidateAnime";
import settings from "$stores/settings";
import AnimeList from "./AnimeListTemplate.svelte";

export let user: AniListAuthorisation;
let animeLists: Promise<Media[]>;
let startTime: number;
let endTime: number;

onMount(async () => {
	await hydrateMediaListCache("anime");

	startTime = performance.now();
	animeLists = mediaListCollection(
		user,
		$identity,
		Type.Anime,
		$anime,
		$lastPruneTimes.anime,
		{
			addNotification,
			notificationType: "Upcoming Episodes",
		},
	);
});

const cleanMedia = (
	anime: Media[],
	displayUnresolved: boolean,
	subsPlease: SubsPlease | null,
	plannedOnly = true,
) => {
	if (anime === undefined) return [];

	const filterAnime = (status: "RELEASING" | "NOT_YET_RELEASED") =>
		anime
			.filter(
				(media: Media) =>
					media.status === status && media.nextAiringEpisode !== null,
			)
			.map((media) => injectAiringTime(media, subsPlease))
			.filter(
				(media: Media) =>
					// Outdated media
					($settings.displayPlannedAnime
						? media.mediaListEntry?.status === "PLANNING"
						: false) || !hasDueEpisodes(media),
			)
			.map((media: Media) =>
				// Adjust for planned anime
				($settings.displayPlannedAnime ? media.episodes !== 1 : true) &&
				hasNoAiredEpisodes(media)
					? {
							...media,
							nextAiringEpisode: {
								...(media.nextAiringEpisode || { episode: 0 }),
								episode: -1,
							},
						}
					: media,
			);
	let upcomingAnime = filterAnime(
		plannedOnly ? "NOT_YET_RELEASED" : "RELEASING",
	);

	if (!displayUnresolved)
		upcomingAnime = upcomingAnime.filter(
			(media: Media) => media.nextAiringEpisode?.episode !== -1,
		);

	upcomingAnime.sort(
		(a: Media, b: Media) =>
			(a.nextAiringEpisode?.airingAt || 9999) -
			(b.nextAiringEpisode?.airingAt || 9999),
	);

	if (!endTime) endTime = performance.now() - startTime;

	return upcomingAnime;
};

let lastAnimeRevalidation = 0;

$: if ($revalidateAnime > lastAnimeRevalidation) {
	lastAnimeRevalidation = $revalidateAnime;

	startTime = performance.now();
	endTime = -1;

	animeLists = mediaListCollection(
		user,
		$identity,
		Type.Anime,
		$anime,
		$lastPruneTimes.anime,
		{
			forcePrune: true,
			addNotification,
			notificationType: "Upcoming Episodes",
		},
	);
}
</script>

<AnimeList
  {endTime}
  {cleanMedia}
  bind:animeLists
  {user}
  title={$locale().lists.upcoming.episodes}
  upcoming
/>

{#if $settings.displayPlannedAnime}
  <Spacer />

  <AnimeList
    {endTime}
    {cleanMedia}
    bind:animeLists
    {user}
    title={$locale().lists.upcoming.notYetReleased}
    notYetReleased
    plannedOnly
  />
{/if}
