<script context="module" lang="ts">
import proxy from "$lib/Utility/proxy";

let mangadexServiceStatusResponse: Promise<Response> | undefined;

const getMangadexServiceStatus = () => {
	if (!mangadexServiceStatusResponse)
		mangadexServiceStatusResponse = fetch(
			proxy("https://api.mangadex.org/ping"),
		);

	return mangadexServiceStatusResponse;
};
</script>

<script lang="ts">
import Spacer from "$lib/Layout/Spacer.svelte";
import type { Media } from "$lib/Data/AniList/media";
import RateLimitedError from "$lib/Error/RateLimited.svelte";
import { volumeCount } from "$lib/Media/Manga/volumes";
import settings from "$stores/settings";
import ListTitle from "../ListTitle.svelte";
import { onMount } from "svelte";
import root from "$lib/Utility/root";
import locale from "$stores/locale";
import Skeleton from "$lib/Loading/Skeleton.svelte";
import { browser } from "$app/environment";
import "../covers.css";
import CleanGrid from "../CleanGrid.svelte";
import CleanList from "../CleanList.svelte";
import stateBin from "$stores/stateBin";
import localforage from "localforage";
import MediaRoulette from "../MediaRoulette.svelte";

export let media: Media[];
export let cleanCache: () => void;
export let endTime: number;
export let lastUpdatedMedia: number;
export let updateMedia: (
	id: number,
	progress: number | undefined,
	media: Media[],
) => Promise<void>;
export let pendingUpdate: number | null;
export let due: boolean;
export let rateLimited: boolean;
export let authorised: boolean;
export let dummy = false;
export let disableFilter = false;
export let limit: number | undefined = undefined;

let showRoulette = false;
let serviceStatusResponse: Promise<Response>;
let totalEpisodeDueCount = media
	.map((manga) => {
		if ($settings.displayTotalEpisodes && !$settings.displayTotalDueEpisodes)
			return 1;

		if (!due && !$settings.displayTotalEpisodes) return 1;

		return (manga.episodes || 1) - (manga.mediaListEntry?.progress || 0);
	})
	.reduce((a, b) => a + b, 0);
let lists: string[] = [];
const filterKind = due ? "due" : "completed";
const filterKey = `${filterKind}MangaListFilter`;
let selectedList = "All";

$: {
	const persistedList = disableFilter
		? "All"
		: ($stateBin[filterKey] as string) || "All";

	if (persistedList !== selectedList) selectedList = persistedList;
}

$: lists = Array.from(
	new Set(
		media
			.flatMap((m) => Object.entries(m.mediaListEntry?.customLists ?? {}))
			.filter(([_key, value]) => value)
			.map(([key]) => key),
	),
);

$: hasDistinguishingList = lists.some((list) =>
	media.some((m) => !m.mediaListEntry?.customLists?.[list]),
);

$: if (
	lists.length > 0 &&
	selectedList !== "All" &&
	!lists.includes(selectedList)
) {
	selectedList = "All";

	if (!disableFilter) $stateBin[filterKey] = "All";
}

$: filteredMedia =
	selectedList === "All" || !$settings.displayMediaListFilter
		? media
		: media.filter((m) => m.mediaListEntry?.customLists?.[selectedList]);

const updateSelectedList = (event: Event) => {
	const nextSelectedList = (event.currentTarget as HTMLSelectElement).value;

	selectedList = nextSelectedList;

	if (!disableFilter && $stateBin[filterKey] !== nextSelectedList)
		$stateBin[filterKey] = nextSelectedList;
};

onMount(async () => {
	if (rateLimited) serviceStatusResponse = getMangadexServiceStatus();

	if (browser)
		await localforage.setItem(
			`last${due ? "" : "Completed"}MangaListLength`,
			media.length.toString(),
		);
});

$: if (rateLimited && !serviceStatusResponse)
	serviceStatusResponse = getMangadexServiceStatus();

const increment = (manga: Media) => {
	if (!(pendingUpdate === manga.id || dummy))
		updateMedia(manga.id, manga.mediaListEntry?.progress, media);
};
</script>

{#if authorised}
  <ListTitle
    count={$settings.displayTotalDueEpisodes || $settings.displayTotalEpisodes
      ? totalEpisodeDueCount
      : filteredMedia.length}
    time={endTime / 1000}
    title={due
      ? $locale().lists.due.mangaAndLightNovels
      : $locale().lists.completed.mangaAndLightNovels}
    hideTime={dummy}
    hideCount={dummy || media.length === 0}
  >
    {#if !dummy}
      <button
        class="small-button"
        title={$locale().lists.actions?.forceFullRefresh}
        onclick={cleanCache}
        data-umami-event="Force Refresh Manga">Refresh</button
      >
      {#if $settings.displayMediaRoulette && filteredMedia.length > 1}
        <button
          class="small-button"
          onclick={() => (showRoulette = true)}
          title={$locale().lists.actions?.pickRandomManga}
        >
          Roulette
        </button>
      {/if}
    {/if}
  </ListTitle>
{/if}

{#if rateLimited}
  {#await serviceStatusResponse}
    <Skeleton card={false} count={1} height="0.9rem" list />
  {:then status}
    {#if status}
      {#if status.status === 503}
        {$locale().lists.errors?.mangaDataDown?.split("due.moe's")[0]}<a href="https://due.moe"
          >due.moe</a
        >{$locale().lists.errors?.mangaDataDown?.split("due.moe")[1]}
      {:else if status.status !== 200}
        {$locale().lists.errors?.mangaDataUnavailable?.split("due.moe's")[0]}<a
          href="https://due.moe">due.moe</a
        >{$locale().lists.errors?.mangaDataUnavailable?.split("due.moe")[1]}
      {:else}
        <RateLimitedError />
      {/if}
    {:else}
      <Skeleton card={false} count={1} height="0.9rem" list />
    {/if}
  {:catch}
    {$locale().lists.errors?.mangaDataUnreachable?.split("due.moe's")[0]}<a href="https://due.moe"
      >due.moe</a
    >{$locale().lists.errors?.mangaDataUnreachable?.split("due.moe")[1]}
  {/await}
{/if}

{#if media.length === 0 && !rateLimited}
  {#if rateLimited}
    <Spacer />
  {/if}

  <p>
    {$locale().lists.empty?.manga}
    <button onclick={cleanCache} data-umami-event="Force Refresh No Manga"
      >{$locale().lists.actions?.forceRefresh}</button
    >
  </p>

  <span>
    {$locale().lists.dontReadMangaPrefix}
    <button onclick={() => ($settings.disableManga = true)} data-umami-event="Disable No Manga"
      >{$locale().lists.hideMangaPanel}</button
    >
    {$locale().lists.reenableInSettings?.split('Settings')[0]}<a href={root('/settings')}
      >{$locale().navigation.settings}</a
    >.
  </span>
{:else if $settings.displayMediaListFilter && !disableFilter && hasDistinguishingList}
  <select value={selectedList} onchange={updateSelectedList}>
    <option value="All">{$locale().lists.actions?.all}</option>

    {#each lists as list}
      <option value={list}>{list}</option>
    {/each}
  </select>

  <Spacer />
{/if}

{#if $settings.displayCoverModeManga || dummy}
  <CleanGrid media={filteredMedia} {dummy} type="manga" {limit}>
    <div slot="title" let:title={manga} let:progress>
      {pendingUpdate === manga.id ? progress + 1 : progress}{#if !due}
        <span class="opaque">/{manga.chapters || '?'}</span>
      {/if}
      <button
        class={`button-square button-action ${pendingUpdate === manga.id ? 'opaque' : ''}`}
        style={pendingUpdate === manga.id ? 'pointer-events: none;' : ''}
        onclick={() => increment(manga)}
      >
        +
      </button>
      {#if due || Math.floor(manga.episodes) < manga.chapters}
        [{manga.episodes || '?'}]
        {#await volumeCount(manga) then volumes}
          {@const volumeProgress = manga.mediaListEntry?.progressVolumes}

          {#if volumes !== null && (volumeProgress || 0) < volumes}
            <span style="color: lightcoral;">
              Vol. {volumeProgress} &#8594; {volumes}
            </span>
          {/if}
        {/await}
      {/if}
    </div>
  </CleanGrid>
{:else}
  <CleanList
    media={filteredMedia}
    type="manga"
    {lastUpdatedMedia}
    disableTitleTooltip={true}
  >
    <span slot="information" let:title={manga} let:progress>
      <span class="opaque">|</span>
      {pendingUpdate === manga.id ? progress + 1 : progress}{#if !due}
        <span class="opaque">/{manga.chapters || '?'}</span>
      {/if}
      <button
        class={`button-square button-action ${pendingUpdate === manga.id ? 'opaque' : ''}`}
        style={pendingUpdate === manga.id ? 'pointer-events: none;' : ''}
        onclick={() => increment(manga)}
      >
        +
      </button>
      {#if due || Math.floor(manga.episodes) < manga.chapters}
        [{manga.episodes || '?'}]
        {#await volumeCount(manga) then volumes}
          {@const volumeProgress = manga.mediaListEntry?.progressVolumes}

          {#if volumes !== null && (volumeProgress || 0) < volumes}
            <span style="color: lightcoral;">
              Vol. {volumeProgress} &#8594; {volumes}
            </span>
          {/if}
        {/await}
      {/if}
    </span>
  </CleanList>
{/if}

{#if showRoulette}
  <MediaRoulette media={filteredMedia} type="manga" onClose={() => (showRoulette = false)} />
{/if}
