<script lang="ts">
	import Error from '$lib/Error/RateLimited.svelte';
	import type { SubsPlease, SubsPleaseEpisode } from '$lib/Media/Anime/Airing/Subtitled/subsPlease';
	import { onMount } from 'svelte';
	import settings from '$stores/settings';
	import { parseOrDefault } from '$lib/Utility/parameters';
	import { browser } from '$app/environment';
	import type { Media } from '$lib/AniList/media';
	import { scheduleMediaListCollection } from '$lib/AniList/schedule';
	import { season } from '$lib/Media/Anime/season';
	import { findClosestMedia } from '$lib/Media/Anime/Airing/Subtitled/match';
	import HeadTitle from '$lib/Home/HeadTitle.svelte';
	import Crunchyroll from '$lib/Tools/Schedule/Crunchyroll.svelte';
	import Loading from '$lib/Utility/Loading.svelte';
	import './container.css';
	import CoverBypass from './CoverBypass.svelte';

	let subsPleasePromise: Promise<SubsPlease>;
	let scheduledMediaPromise: Promise<Partial<Media[]>>;
	const urlParameters = browser ? new URLSearchParams(window.location.search) : null;
	let timeZone = parseOrDefault(
		urlParameters,
		'tz',
		Intl.DateTimeFormat().resolvedOptions().timeZone
	);
	let day: string | null = parseOrDefault(urlParameters, 'day', null);
	let crunchyrollExpanded = false;

	onMount(async () => {
		subsPleasePromise = fetch(`/api/subsplease?tz=${timeZone}`).then((r) => r.json());
		scheduledMediaPromise = scheduleMediaListCollection(new Date().getFullYear(), season(), true);
	});

	const shiftSubsPleaseSchedule = (schedule: SubsPlease['schedule']) => {
		const shiftedSchedule: { [key: string]: SubsPleaseEpisode[] } = {};

		if (day && Object.keys(schedule).includes(day)) {
			shiftedSchedule[day] = schedule[
				day as keyof typeof schedule
			] as unknown as SubsPleaseEpisode[];

			return shiftedSchedule;
		}

		const days = Object.keys(schedule);
		const currentDayIndex = days.indexOf(new Date().toLocaleString('en-us', { weekday: 'long' }));

		days
			.slice(currentDayIndex)
			.concat(days.slice(0, currentDayIndex))
			.forEach((day) => {
				const scheduleEntry = schedule[day as keyof typeof schedule];

				shiftedSchedule[day] = Array.isArray(scheduleEntry)
					? scheduleEntry
					: ([scheduleEntry] as unknown as SubsPleaseEpisode[]);
			});

		Object.entries(shiftedSchedule).forEach(([day, scheduleEntry]) => {
			if (scheduleEntry.length === 0) {
				delete shiftedSchedule[day];
			}
		});

		return shiftedSchedule;
	};

	const associateMedia = (media: (Media | undefined)[], title: string) =>
		findClosestMedia(media as Media[], title);

	const episode = (media: Media, weekday: string) => {
		if (media.nextAiringEpisode?.episode === 1) return 1;

		if (
			new Date((media.nextAiringEpisode?.airingAt || 0) * 1000) > new Date() &&
			weekday === new Date().toLocaleString('en-us', { weekday: 'long' })
		) {
			return (media.nextAiringEpisode?.episode || 1) - 1;
		} else {
			return media.nextAiringEpisode?.episode || 0;
		}
	};
</script>

<HeadTitle route="Schedule" path="/schedule" />

<blockquote>
	<select
		bind:value={timeZone}
		on:change={() =>
			(subsPleasePromise = fetch(`/api/subsplease?tz=${timeZone}`).then((r) => r.json()))}
	>
		{#each Intl.supportedValuesOf('timeZone') as zone}
			<option value={zone}>
				{zone.split('/').reverse().join(', ').replace(/_/g, ' ')}
			</option>
		{/each}
	</select>
</blockquote>

<details bind:open={crunchyrollExpanded}>
	<summary
		>Crunchyroll Release Calender (Click to {crunchyrollExpanded ? 'collapse' : 'expand'})</summary
	>

	<p />

	<Crunchyroll />
</details>

<p />

{#await subsPleasePromise}
	<Loading type="subtitle release data" percent={49.5} />
{:then subsPlease}
	{#if subsPlease}
		{#await scheduledMediaPromise}
			<Loading type="anime schedule" percent={82.5} />
		{:then scheduledMedia}
			{#if scheduledMedia}
				{@const columnCount = Math.ceil(Object.keys(subsPlease.schedule).length / 2)}

				<div class="list-container" id="schedule" style={`column-count: ${columnCount}`}>
					{#each Object.entries(shiftSubsPleaseSchedule(subsPlease.schedule)) as [day, scheduleEntry]}
						<details
							open
							class="list"
							class:today={day === new Date().toLocaleString('en-us', { weekday: 'long' })}
						>
							<summary>{day}</summary>

							<ol>
								{#each Object.values(scheduleEntry) as entry}
									{@const media = associateMedia(scheduledMedia, entry.title)}

									<li class="entry">
										<CoverBypass {media} {entry} />
										{#if !$settings.displayCountdownRightAligned}
											<span style="opacity: 50%;">|</span>
										{/if}
										<span class:countdown={$settings.displayCountdownRightAligned}>
											{#if media && media.nextAiringEpisode}
												<span style="opacity: 50%;">
													{episode(media, day)}{media.episodes ? `/${media.episodes}` : ''} at
												</span>
											{/if}
											{entry.time}
										</span>
									</li>
								{/each}
							</ol>
						</details>

						<p />
					{/each}
				</div>
			{:else}
				<Loading type="anime schedule" percent={66} />
			{/if}
		{:catch}
			<Error type="Media" loginSessionError={false} card />
		{/await}
	{:else}
		<Loading type="subtitle release data" percent={33} />
	{/if}
{:catch}
	<Error type="Schedule" loginSessionError={false} card />
{/await}

<style>
	.entry::after {
		content: '';
		display: table;
		clear: both;
	}

	.countdown {
		white-space: nowrap;
		float: right;
	}

	.today {
		box-shadow: 0 2.5px 10px var(--base01), 0 0 0 5px var(--base0E), 0 4px 30px var(--base01);
	}

	.list {
		overflow-y: auto;
		break-inside: avoid-column;
		page-break-inside: avoid;
	}
</style>
