<script lang="ts">
import { browser } from '$app/environment';
import { mediaListCollection, Type, type Media } from '$lib/Data/AniList/media';
import { findClosestMedia } from '$lib/Media/Anime/Airing/Subtitled/match';
import type { SubsPlease, SubsPleaseEpisode } from '$lib/Media/Anime/Airing/Subtitled/subsPlease';
import { outboundLink } from '$lib/Media/links';
import { parseOrDefault } from '$lib/Utility/parameters';
import settings from '$stores/settings';
import CoverBypass from './CoverBypass.svelte';
import '$lib/List/covers.css';
import ParallaxImage from '$lib/Image/ParallaxImage.svelte';
import LinkedTooltip from '$lib/Tooltip/LinkedTooltip.svelte';
import { onMount } from 'svelte';
import identity from '$stores/identity';
import anime from '$stores/anime';
import lastPruneTimes from '$stores/lastPruneTimes';
import Message from '$lib/Loading/Message.svelte';
import Skeleton from '$lib/Loading/Skeleton.svelte';
import RateLimitedError from '$lib/Error/RateLimited.svelte';

export let subsPlease: SubsPlease;
export let scheduledMedia: Partial<Media[]>;
export let forceListMode = false;
export let user;

const urlParameters = browser ? new URLSearchParams(window.location.search) : null;
let day: string | null = parseOrDefault(urlParameters, 'day', null);

let mediaListPromise: Promise<Media[]>;

onMount(async () => {
  if (user === undefined || $identity.id === -2) mediaListPromise = Promise.resolve([]);
  else
    mediaListPromise = mediaListCollection(
      user,
      $identity,
      Type.Anime,
      $anime,
      $lastPruneTimes.anime,
      {
        all: 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, mediaList: Media[]) => {
  const closestMedia = findClosestMedia(media as Media[], title);

  if ($settings.displayScheduleFilterList && closestMedia && mediaList)
    return mediaList.find((m) => m.id === closestMedia?.id) || null;

  return closestMedia;
};

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

  if (
    media.nextAiringEpisode?.airingAt &&
    weekday === new Date().toLocaleString('en-us', { weekday: 'long' }) &&
    new Date(media.nextAiringEpisode.airingAt * 1000).getTime() - new Date().getTime() >
      24 * 60 * 60 * 1000
  )
    return media.nextAiringEpisode?.episode - 1;

  return media.nextAiringEpisode?.episode || 1;
};
</script>

{#await mediaListPromise}
  <Message message="Loading media lists ..." />

  <Skeleton grid={true} count={7} height="15em" width="49.5%" />
{:then mediaList}
  {#each Object.entries(shiftSubsPleaseSchedule(subsPlease.schedule)) as [day, scheduleEntry], dayIndex}
    <details
      open
      class="list"
      class:today={day === new Date().toLocaleString('en-us', { weekday: 'long' })}
    >
      <summary>{day}</summary>

      {#if !$settings.displayScheduleListMode && !forceListMode}
        <div
          class="covers"
          style={`grid-template-columns: repeat(auto-fill, minmax(${$settings.displayCoverWidth}px, 1fr))`}
        >
          {#each Object.values(scheduleEntry) as entry, entryIndex}
            {@const media = associateMedia(scheduledMedia, entry.title, mediaList)}

            {#if ($settings.displayScheduleFilterList && media) || !$settings.displayScheduleFilterList}
              <div class="cover-card" id={`cover-${dayIndex}-${entryIndex}`}>
                <LinkedTooltip
                  content={media ? media.title.english || media.title.romaji : entry.title}
                  pin={`cover-${dayIndex}-${entryIndex}`}
                >
                  <a
                    href={outboundLink(
                      media ? media : null,
                      'anime',
                      $settings.displayOutboundLinksTo,
                      media === null,
                      entry.title
                    )}
                    target="_blank"
                  >
                    <div class="cover-card-image">
                      <ParallaxImage
                        source={media
                          ? $settings.displayDataSaver
                            ? media.coverImage.medium
                            : media.coverImage.extraLarge
                          : `https://subsplease.org${entry.image_url}`}
                        limit={12.5}
                        alternativeText="Cover"
                      />
                    </div>
                  </a>

                  <div class="cover-title">
                    <div class="cover-title-element">
                      <CoverBypass {media} {entry} cover={false} showTooltip={false} />
                    </div>

                    <span class:countdown={$settings.displayCountdownRightAligned}>
                      {#if media && media.nextAiringEpisode}
                        <span class="opaque">
                          {episode(media, day)}{media.episodes ? `/${media.episodes}` : ''} at
                        </span>
                      {/if}
                      {entry.time}
                    </span>
                  </div>
                </LinkedTooltip>
              </div>
            {/if}
          {/each}
        </div>
      {:else}
        <ol>
          {#each Object.values(scheduleEntry) as entry}
            {@const media = associateMedia(scheduledMedia, entry.title, mediaList)}

            {#if ($settings.displayScheduleFilterList && media) || !$settings.displayScheduleFilterList}
              <li class="entry">
                <CoverBypass {media} {entry} />
                {#if !$settings.displayCountdownRightAligned}
                  <span class="opaque">|</span>
                {/if}
                <span class:countdown={$settings.displayCountdownRightAligned}>
                  {#if media && media.nextAiringEpisode}
                    <span class="opaque">
                      {episode(media, day)}{media.episodes ? `/${media.episodes}` : ''} at
                    </span>
                  {/if}
                  {entry.time}
                </span>
              </li>
            {/if}
          {/each}
        </ol>
      {/if}
    </details>
  {/each}
{:catch}
  <RateLimitedError type="Media lists" loginSessionError={false} card list={false} />
{/await}

<style>
  .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;
  }

  @media (max-width: 800px) {
    .cover-title-element {
      display: none;
    }

    .cover-card-image {
      margin-bottom: 0em;
    }
  }

  @media (max-width: 1600px) {
    .cover-title-element {
      display: none;
    }
  }
</style>
