<script lang="ts">
	import userIdentity from '../../stores/userIdentity.js';
	import {
		userIdentity as getUserIdentity,
		type AniListAuthorisation
	} from '$lib/AniList/identity';
	import { onMount } from 'svelte';
	import { wrapped } from '$lib/AniList/wrapped.js';
	import { activityHistory, fillMissingDays } from '$lib/AniList/activity.js';
	import { Type, mediaListCollection, type Media } from '$lib/AniList/media.js';
	import anime from '../../stores/anime.js';
	import lastPruneTimes from '../../stores/lastPruneTimes.js';
	import manga from '../../stores/manga.js';
	import Error from '$lib/Error.svelte';
	import { domToBlob } from 'modern-screenshot';
	import { browser, dev } from '$app/environment';
	import { page } from '$app/stores';
	import { clearAllParameters } from './tool.js';

	export let user: AniListAuthorisation;

	let currentUserIdentity = { name: '', id: -1 };
	let episodes = 0;
	let chapters = 0;
	let minutesWatched = 0;
	let animeList: Media[] | undefined = undefined;
	let mangaList: Media[] | undefined = undefined;
	let transparency = false;
	let lightTheme = true;
	let watermark = false;
	let includeMusic = false;
	let includeSpecials = false;
	let includeRepeats = false;
	let width = 980;
	let forceDark = false;
	let highestRatedCount = 5;
	let mounted = false;

	$: {
		if (browser && mounted) {
			$page.url.searchParams.set('transparency', transparency.toString());
			$page.url.searchParams.set('lightTheme', lightTheme.toString());
			$page.url.searchParams.set('watermark', watermark.toString());
			$page.url.searchParams.set('includeMusic', includeMusic.toString());
			$page.url.searchParams.set('includeSpecials', includeSpecials.toString());
			$page.url.searchParams.set('includeRepeats', includeRepeats.toString());
			$page.url.searchParams.set('width', width.toString());
			$page.url.searchParams.set('forceDark', forceDark.toString());
			$page.url.searchParams.set('highestRatedCount', highestRatedCount.toString());

			history.replaceState(null, '', `?${$page.url.searchParams.toString()}`);
		}
	}
	$: {
		includeMusic = includeMusic;
		includeSpecials = includeSpecials;
		includeRepeats = includeRepeats;

		update()
			.then(() => {})
			.catch(() => {});
	}
	$: {
		animeList = animeList;
		mangaList = mangaList;
		highestRatedCount = highestRatedCount;

		new Promise((resolve) => setTimeout(resolve, 1)).then(updateWidth);
	}

	const updateWidth = () => {
		const wrappedContainer = document.querySelector('#wrapped') as HTMLElement;

		if (!wrappedContainer) return;

		wrappedContainer.style.width = `1920px`;

		const reset = () => {
			let widths: number[] = [];

			wrappedContainer.querySelectorAll('.category').forEach((item) => {
				const category = item as HTMLElement;
				const style = window.getComputedStyle(category);

				widths.push(
					category.offsetWidth +
						parseFloat(style.marginLeft) +
						parseFloat(style.marginRight) +
						parseFloat(style.paddingLeft) +
						parseFloat(style.paddingRight) +
						parseFloat(style.borderLeftWidth) +
						parseFloat(style.borderRightWidth)
				);
			});

			widths.sort((a, b) => b - a);

			const requiredWidth = widths[0] + (widths[1] || 0);

			wrappedContainer.style.width = `${requiredWidth}px`;
			width = requiredWidth;
		};

		reset();
		reset();
	};

	onMount(async () => {
		clearAllParameters([
			'transparency',
			'lightTheme',
			'watermark',
			'includeMusic',
			'includeSpecials',
			'includeRepeats',
			'width',
			'forceDark',
			'highestRatedCount'
		]);
		if (browser) {
			transparency = $page.url.searchParams.get('transparency') === 'true';
			lightTheme = $page.url.searchParams.get('lightTheme') === 'true';
			watermark = $page.url.searchParams.get('watermark') === 'true';
			includeMusic = $page.url.searchParams.get('includeMusic') === 'true';
			includeSpecials = $page.url.searchParams.get('includeSpecials') === 'true';
			includeRepeats = $page.url.searchParams.get('includeRepeats') === 'true';
			width = parseInt($page.url.searchParams.get('width') || '980', 10);
			forceDark = $page.url.searchParams.get('forceDark') === 'true';
			highestRatedCount = parseInt($page.url.searchParams.get('highestRatedCount') || '5', 10);
		}

		if (user !== undefined) {
			if ($userIdentity === '') {
				userIdentity.set(JSON.stringify(await getUserIdentity(user)));
			}

			currentUserIdentity = JSON.parse($userIdentity);
			currentUserIdentity.name = currentUserIdentity.name;
		} else {
			currentUserIdentity.id = -2;
		}

		await update();

		mounted = true;
	});

	const update = async () => {
		const currentYear = new Date(Date.now()).getFullYear();

		animeList = (
			await mediaListCollection(
				user,
				currentUserIdentity,
				Type.Anime,
				$anime,
				$lastPruneTimes.anime,
				true,
				true
			)
		)
			.filter(
				(item, index, self) =>
					self.findIndex((itemToCompare) => itemToCompare.id === item.id) === index &&
					(includeMusic ? true : item.format !== 'MUSIC') &&
					(includeRepeats ? true : item.mediaListEntry?.repeat === 0) &&
					(item.mediaListEntry?.startedAt.year === currentYear ||
						item.mediaListEntry?.completedAt.year === currentYear)
			)
			.sort((a, b) => {
				if (a.mediaListEntry?.score === undefined) {
					return 1;
				} else if (b.mediaListEntry?.score === undefined) {
					return -1;
				} else {
					return b.mediaListEntry?.score - a.mediaListEntry?.score;
				}
			});
		mangaList = (
			await mediaListCollection(
				user,
				currentUserIdentity,
				Type.Manga,
				$manga,
				$lastPruneTimes.manga,
				true,
				true
			)
		)
			.filter(
				(item, index, self) =>
					self.findIndex((itemToCompare) => itemToCompare.id === item.id) === index &&
					(includeRepeats ? true : item.mediaListEntry?.repeat === 0) &&
					(item.mediaListEntry?.startedAt.year === currentYear ||
						item.mediaListEntry?.completedAt.year === currentYear)
			)
			.sort((a, b) => {
				if (a.mediaListEntry?.score === undefined) {
					return 1;
				} else if (b.mediaListEntry?.score === undefined) {
					return -1;
				} else {
					return b.mediaListEntry?.score - a.mediaListEntry?.score;
				}
			});

		episodes = 0;
		minutesWatched = 0;
		chapters = 0;

		for (const media of animeList) {
			episodes += media.mediaListEntry?.progress || 0;
			minutesWatched += (media.mediaListEntry?.progress || 0) * media.duration || 0;
		}

		for (const media of mangaList) {
			chapters += media.mediaListEntry?.progress || 0;
		}
	};

	/* eslint-disable @typescript-eslint/no-explicit-any */
	// const year = (statistic: { startYears: any }) =>
	// 	statistic.startYears.find((y: { startYear: number }) => y.startYear === 2023);

	const screenshot = async (dark = false) => {
		let element = document.querySelector('#wrapped') as HTMLElement;

		element.classList.add('invert');

		if (dark) {
			// element.classList.add('light-theme');
			lightTheme = false;
		}

		if (element !== null) {
			domToBlob(element, {
				style: {
					backgroundColor: transparency ? 'transparent' : dark ? '#0b1622' : '#edf1f5'
				},
				quality: 1,
				scale: 2,
				fetch: {
					requestInit: {
						mode: 'cors'
					},
					bypassingCache: true
				}
			}).then((blob) => {
				const downloadWrapper = document.createElement('a');
				// const wrappedImageButton = document.getElementById(
				// 	'wrapped-image-download'
				// ) as HTMLAnchorElement;
				const image = document.createElement('img');
				const object = (window.URL || window.webkitURL || window || {}).createObjectURL(blob);

				// downloadWrapper.download = `due_dot_moe_wrapped_${dark ? 'dark' : 'light'}.png`;
				downloadWrapper.href = object;
				downloadWrapper.target = '_blank';
				image.src = object;

				downloadWrapper.appendChild(image);

				// if (wrappedImageButton !== null) {
				// 	wrappedImageButton.href = object;
				// }

				const wrappedFinal = document.getElementById('wrapped-final');

				if (wrappedFinal !== null) {
					const blockquote = document.createElement('blockquote');

					wrappedFinal.innerHTML = '';
					blockquote.innerText =
						'Click on the image to download, or right click and select "Save Image As...".';

					wrappedFinal.appendChild(downloadWrapper);
					wrappedFinal.appendChild(document.createElement('br'));
					wrappedFinal.appendChild(blockquote);
				}

				downloadWrapper.click();
			});

			await new Promise((resolve) => setTimeout(resolve, 1000));

			element.classList.remove('invert');
			lightTheme = true;
			// element.classList.remove('light-theme');
		}
	};

	// const abbreviate = (string: string, maxLength = 40, enabled = true) => {
	// 	if (!enabled) {
	// 		return string;
	// 	}

	// 	if (string.length <= maxLength) {
	// 		return string;
	// 	}

	// 	return string.slice(0, maxLength - 3) + ' …';
	// };

	const proxy = (url: string) => (dev ? url : `/api/proxy?url=${encodeURIComponent(url)}`);
</script>

{#if currentUserIdentity.id === -2}
	Please log in to view this page.
{:else if currentUserIdentity.id !== -1}
	{#await wrapped(user, currentUserIdentity)}
		Loading&nbsp;...
	{:then wrapped}
		<div id="wrapped" class:light-theme={lightTheme} style={`width: ${width}px;`}>
			<div class="categories-grid" style="padding-bottom: 0;">
				<div class="grid-item image-grid avatar-grid category">
					<a href={`https://anilist.co/user/${currentUserIdentity.name}`} target="_blank">
						<img src={proxy(wrapped.avatar.large)} alt="User Avatar" />
					</a>
					<div>
						<div>
							<a href={`https://anilist.co/user/${currentUserIdentity.name}`} target="_blank">
								<b>
									{currentUserIdentity.name}
								</b>
							</a>
						</div>
						<div>
							Status Posts: {wrapped.activities.statusCount}
						</div>
						<div>
							Messages: {wrapped.activities.messageCount}
						</div>
						<div>
							Days Active: {#await activityHistory(currentUserIdentity)}
								Loading&nbsp;...
							{:then activities}
								{#if activities === undefined}
									Loading&nbsp;...
								{:else}
									{fillMissingDays(activities, true).filter((a) => a.amount !== 0).length}/365
								{/if}
							{/await}
						</div>
					</div>
				</div>
				<div class="category-grid pure-category category">
					<div class="grid-item">
						<b>Anime</b>
					</div>
					<div class="grid-item">
						Time Watched: {((minutesWatched || 0) / 60 / 24).toFixed(2)} days
					</div>
					<div class="grid-item">
						Completed: {animeList?.length}
					</div>
					<div class="grid-item">Episodes: {episodes}</div>
				</div>
				<div class="category-grid pure-category category">
					<div class="grid-item">
						<b>Manga</b>
					</div>
					<div class="grid-item">
						Time Read: {((chapters * 8.58) / 60 / 24).toFixed(2)} days
					</div>
					<div class="grid-item">
						Completed: {mangaList?.length}
					</div>
					<div class="grid-item">
						Chapters: {chapters}
					</div>
				</div>
			</div>
			<div class="categories-grid">
				<div class="category-grid pure-category category">
					<div class="grid-item image-grid">
						{#if animeList !== undefined}
							<a href={`https://anilist.co/anime/${animeList[0].id}`} target="_blank">
								<img
									src={proxy(animeList[0].coverImage.extraLarge)}
									alt="Highest Rated Anime Cover"
									class="cover-image"
								/>
							</a>
							<div>
								<b>Highest Rated Anime</b>
								<ol>
									{#each animeList?.slice(0, highestRatedCount) as anime}
										<li>
											<a href={`https://anilist.co/anime/${anime.id}`} target="_blank">
												{anime.title.english || anime.title.romaji || anime.title.native}
											</a>
										</li>
									{/each}
								</ol>
							</div>
						{:else}
							Loading&nbsp;...
						{/if}
					</div>
				</div>
				<div class="category-grid pure-category category">
					<div class="grid-item image-grid">
						{#if mangaList !== undefined}
							<a href={`https://anilist.co/manga/${mangaList[0].id}`} target="_blank">
								<img
									src={proxy(mangaList[0].coverImage.extraLarge)}
									alt="Highest Rated Manga Cover"
									class="cover-image"
								/>
							</a>
							<div>
								<b>Highest Rated Manga</b>
								<ol>
									{#each mangaList?.slice(0, highestRatedCount) as manga}
										<li>
											<a href={`https://anilist.co/manga/${manga.id}`} target="_blank">
												{manga.title.english || manga.title.romaji || manga.title.native}
											</a>
										</li>
									{/each}
								</ol>
							</div>
						{:else}
							Loading&nbsp;...
						{/if}
					</div>
				</div>
			</div>
			{#if watermark}
				<div class="categories-grid" style="padding-top: 0;">
					<div class="category-grid pure-category" id="watermark">due.moe/wrapped</div>
				</div>
			{/if}
		</div>

		<p />

		<blockquote>
			This is a minimal, live preview. Generated images will be higher quality and themed properly.
		</blockquote>

		<p>
			<button on:click={() => (width -= 25)}>-25px</button>
			<button on:click={updateWidth}>Auto-calculate width</button>
			<button on:click={() => (width += 25)}>+25px</button>
		</p>

		<p>
			<a href={'#'} on:click={() => screenshot(!forceDark)}>Generate image</a>
		</p>

		<details>
			<summary>Options</summary>
			<div id="options">
				<input type="checkbox" bind:checked={watermark} /> Enable watermark<br />
				<input type="checkbox" bind:checked={transparency} /> Enable background transparency<br />
				<input type="checkbox" bind:checked={forceDark} />
				Enable light mode (dark by default)<br />
				<input type="checkbox" bind:checked={includeMusic} /> Include music<br />
				<input type="checkbox" bind:checked={includeRepeats} /> Include rewatches & rereads<br />
				<input type="checkbox" bind:checked={includeSpecials} /> Include specials and OVAs<br />
				<select bind:value={highestRatedCount}>
					{#each [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] as count}
						<option value={count}>{count}</option>
					{/each}
				</select>
				Highest rated media count
			</div>
		</details>

		<p />

		<div id="wrapped-final" />
	{:catch}
		<Error />
	{/await}
{:else}
	Loading&nbsp;...
{/if}

<style>
	@import url('https://fonts.googleapis.com/css?family=Roboto:300,400,500,700');
	@import url('https://fonts.googleapis.com/css?family=Overpass:400,600,700,800');

	.categories-grid {
		display: flex;
		flex-wrap: wrap;
		row-gap: 1.5em;
		column-gap: 1.5em;
		padding: 2%;
		justify-content: center;
		font-family: Roboto, -apple-system, BlinkMacSystemFont, Segoe UI, Oxygen, Ubuntu, Cantarell,
			Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
	}

	.categories-grid b {
		font-family: Overpass, -apple-system, BlinkMacSystemFont, Segoe UI, Oxygen, Ubuntu, Cantarell,
			Fira Sans, Droid Sans, Helvetica Neue, sans-serif !important;
		font-weight: 600 !important;
	}

	.category-grid,
	.image-grid {
		background-color: #151f2e;
		border-radius: 4px;
		color: rgb(159, 173, 189) !important;
	}

	.pure-category,
	.avatar-grid {
		padding: 1.5%;
	}

	.category-grid {
		display: grid;
	}

	.image-grid {
		display: flex;
		column-gap: 1em;
		flex-wrap: wrap;
	}

	.image-grid img {
		height: 6em;
		border-radius: 3px;
	}

	.cover-image {
		height: 8.75em !important;
	}

	.categories-grid a {
		text-decoration: none;
		color: unset;
	}

	.light-theme .categories-grid {
		background-color: #edf1f5 !important;
	}

	.light-theme .category-grid {
		background-color: #fafafa !important;
		color: rgb(92, 114, 138) !important;
	}

	.light-theme .image-grid {
		background-color: #fafafa !important;
		color: rgb(92, 114, 138) !important;
	}

	ol {
		margin: 0 !important;
	}

	#watermark {
		color: rgb(61, 180, 242) !important;
	}
</style>
