<script setup lang="ts">
  import type { MovieMainCrew } from "@/libs/apis/tmdb/schemas/credits.ts";
  import type { TmdbGenreName } from "@/libs/apis/tmdb/schemas/genres.ts";
  import type { ArtWorkTitle } from "@/libs/apis/tmdb/schemas/works.ts";

  import { getMainMovieCrew } from "@/libs/apis/tmdb/crew.ts";
  import { TmdbGenre } from "@/libs/apis/tmdb/schemas/genres.ts";
  import { generateDitheredBufferFromUrl } from "@/libs/utils/images.ts";
  import { convertToMillions } from "@/libs/utils/numbers.ts";
  import { PrettyLogger } from "@/services/logger.ts";
  import { RuntimeClient } from "@/services/runtime-client.ts";
  import { useEntryStore } from "@/stores/entry.ts";
  import { canvasFromPixelBuffer } from "@thi.ng/pixel";
  import { Array as Arr, Effect, pipe, String as Str } from "effect";
  import { ref, type Ref, type ShallowRef, useTemplateRef, watch } from "vue";
  import { useRouter } from "vue-router";

  // Types
  interface AddEntryDisplayData {
    budget: string;
    genres: TmdbGenreName[];
    hasUniqueOriginalTitle: boolean;
    mainCrew: MovieMainCrew;
    originalLanguage: string;
    originalTitle: ArtWorkTitle;
    overview: string;
    popularity: number;
    releaseDate: string;
    revenue: string;
    runtime: string;
    tagline: string;
    title: ArtWorkTitle;
  }

  // Magasins et routeur
  const router = useRouter();
  const entryStore = useEntryStore();

  // Données
  /** Ensemble des données affichées à l'Utilisateur au sein  */
  const displayData: Ref<AddEntryDisplayData | undefined> = ref<AddEntryDisplayData | undefined>();
  /** Conteneur du canvas du poster de l'oeuvre courante avec tramage. */
  const imageContainer: Readonly<ShallowRef<HTMLDivElement | null>> = useTemplateRef("imageContainer");
  /** Canvas dans lequel est inséré le poster de l'oeuvre courante avec tramage. */
  const ditheredPoster: Ref<HTMLCanvasElement | undefined> = ref<HTMLCanvasElement>();

  // Cycles
  watch(() => entryStore.diaryEntry, async (): Promise<void> => {
    if (!entryStore.diaryEntry || !entryStore.tmdbData) {
      console.error("AddEntryPage - Pas d'entrée dans le magasin !");
      await router.push("/");
      return;
    }

    // Récupère les données à afficher.
    displayData.value = {
      budget: entryStore.tmdbData.budget ? `${String(convertToMillions(entryStore.tmdbData.budget))} M$` : "?",
      genres: Arr.map(entryStore.tmdbData.genres, (genre: TmdbGenre) => genre.name),
      hasUniqueOriginalTitle:
        Str.toLowerCase(entryStore.diaryEntry.originalTitle) !== Str.toLowerCase(entryStore.diaryEntry.title),
      mainCrew: getMainMovieCrew(entryStore.tmdbData.credits.crew),
      originalLanguage: entryStore.tmdbData.original_language,
      originalTitle: entryStore.diaryEntry.originalTitle,
      overview: entryStore.diaryEntry.overview,
      popularity: entryStore.diaryEntry.popularity,
      releaseDate: entryStore.diaryEntry.releaseDate,
      revenue: entryStore.tmdbData.revenue ? `${String(convertToMillions(entryStore.tmdbData.revenue))} M$` : "?",
      runtime: `${String(entryStore.tmdbData.runtime)} min`,
      tagline: entryStore.tmdbData.tagline,
      title: entryStore.diaryEntry.title,
    };

    // Applique le tramage à l'affiche de l'oeuvre.
    await RuntimeClient.runPromise(Effect.gen(function*() {
      if (!entryStore.diaryEntry?.posterUrl) return;

      yield* pipe(
        generateDitheredBufferFromUrl(`https://image.tmdb.org/t/p/w500${entryStore.diaryEntry.posterUrl}`),
        Effect.tapError(Effect.logError),
        Effect.tap(ditheredBuffer => {
          const canvas = canvasFromPixelBuffer(ditheredBuffer, imageContainer.value, { pixelated: true });
          ditheredPoster.value = canvas;
        }),
        Effect.provide(PrettyLogger),
      );
    }));
  }, { immediate: true });
</script>

<template>
  <div class="stack">
    <h2>Ajouter une entrée</h2>

    <aside class="go-back">
      <a class="link-with-iconography" href="javascript:void(0)" @click="router.back">
        <span class="iconography">←</span>
        <span class="text">Retour à la recherche</span></a>
    </aside>

    <div class="container switcher">
      <div ref="imageContainer" class="canvas-container"></div>
      <div class="stack">
        <h3>{{ entryStore.diaryEntry?.originalTitle }}</h3>

        <div class="original-metadata">
          <span v-if="displayData?.hasUniqueOriginalTitle">{{ displayData?.title }} | </span>
          {{ displayData?.releaseDate }} | {{ displayData?.runtime }} | {{ displayData?.originalLanguage }} | {{
            displayData?.popularity
          }} | {{ displayData?.budget }} -> {{ displayData?.revenue }}
        </div>

        <div class="main-movie-crew cluster">
          <div class="department">
            <strong>RÉALISATION </strong>
            <ul>
              <li v-for="director of displayData?.mainCrew.directors" :key="director.id">{{ director.name }}</li>
              <li v-if="displayData?.mainCrew.directors.length === 0">/</li>
            </ul>
          </div>
          <div class="department">
            <strong>ÉCRITURE </strong>
            <ul>
              <li v-for="writer of displayData?.mainCrew.writers" :key="writer.id">{{ writer.name }}</li>
              <li v-if="displayData?.mainCrew.writers.length === 0">/</li>
            </ul>
          </div>
          <div class="department">
            <strong>MONTAGE </strong>
            <ul>
              <li v-for="editor of displayData?.mainCrew.editors" :key="editor.id">{{ editor.name }}</li>
              <li v-if="displayData?.mainCrew.editors.length === 0">/</li>
            </ul>
          </div>
        </div>

        <hr>

        <p v-if="displayData?.tagline" class="tagline">{{ displayData?.tagline }}</p>
        <p class="overview">{{ displayData?.overview }}</p>

        <ul class="genres">
          <strong>Genres</strong>
          <li v-for="genre of displayData?.genres" :key="Str.toLowerCase(genre)">{{ genre }}</li>
        </ul>

        <hr>
      </div>
    </div>
  </div>
</template>

<style scoped lang="css">
  .go-back {
    margin-block-end: var(--s1);
    margin-inline-start: calc(var(--s1) * -1);
  }

  .container {
    --threshold: 51rem;

    gap: var(--s2);
    max-inline-size: 70rem;
  }

  .canvas-container {
    aspect-ratio: 0.6;
    width: 400px;
    max-width: 400px;
    height: 600px;
    max-height: 600px;
    border: 4px double var(--root-text-color);
    background: var(--bg25-tertiary);

    > * {
      width: 100%;
      height: 100%;
      object-fit: cover;
    }
  }

  .main-movie-crew {
    --layout-cluster-gap: 2ch;

    align-items: start;
  }

  hr {
    block-size: 1px;
    background: var(--root-text-color);
  }

  .overview {
    hyphens: auto;
    text-align: justify;
  }

  .tagline {
    text-transform: uppercase;
  }

  .genres {
    display: inline-flex;

    strong {
      margin-inline-end: 1ch;
      text-transform: uppercase;
    }

    li + li {
      padding-inline-start: 1ch;

      &::before {
        content: "·";
        padding-inline-end: 1ch;
      }
    }
  }
</style>
