<!-- Small test for making copy-pasting images harder (without putting any major technical restrictions in there, and keeping the site itself working if it errors) -->

<script lang="ts">
  import { onDestroy, tick } from 'svelte';
  import { canvascopy, shuffleInPlace } from './CanvasCopyLib';

  let {
    src,
    alt,
    loading = 'lazy',
    width,
    height,
    artifacts = 'fix',
    useBg = false,
  }: {
    src: string;
    alt: string;
    width?: number;
    height?: number;
    loading?: 'eager' | 'lazy' | undefined | null;
    artifacts?: 'fix' | 'keep';
    useBg?: boolean;
  } = $props();
  let blobUrl = $state(undefined as undefined | string);
  let additionalOverlayedBlobs = $state([] as string[]);
  let additionalOverlayedBlobsDone = $state(false);
  // svelte-ignore state_referenced_locally
  let lastLoadedSrc = $state(src);

  const blobify = (
    image: HTMLImageElement,
    artifacts: 'fix' | 'keep' = 'fix',
  ) => {
    firstLoad = false;
    if (image.src.startsWith('blob:') || image.src === blobUrl) {
      // The image is likely a partial of the image. Tell the browser to reload the original
      lastLoadedSrc = '';
    } else {
      console.debug('[blobify] Entering blobify');
      if (blobUrl) URL.revokeObjectURL(blobUrl);
      if (additionalOverlayedBlobs.length) {
        for (const blobUrl of additionalOverlayedBlobs)
          URL.revokeObjectURL(blobUrl);
        additionalOverlayedBlobs.length = 0;
      }
      additionalOverlayedBlobsDone = false;

      // Need to update lastLoaded to prevent unneeded refreshes
      console.debug('[blobify] Set lastload to', src);
      const lastLoad = lastLoadedSrc;
      lastLoadedSrc = src;

      let nextPerf = 0;
      canvascopy(
        image,
        artifacts,
        () => blobUrl,
        (blob) => (blobUrl = blob),
        tick,
        (blob) => additionalOverlayedBlobs.push(blob),
        () => shuffleInPlace(additionalOverlayedBlobs).shift()!,
        () => {
          const p = performance.now();
          if (p >= nextPerf) {
            nextPerf = p + 10;
            return new Promise((rs) => requestAnimationFrame(() => rs(void 0)));
          }
        },
      )
        .then(() => {
          additionalOverlayedBlobsDone = true;
        })
        .catch((e) => {
          lastLoadedSrc = lastLoad;
          throw e;
        });
    }
  };

  let imgloaded = $state(false);
  let image = $state(null as null | HTMLImageElement);

  $effect(() => {
    if (lastLoadedSrc !== src && blobUrl) {
      URL.revokeObjectURL(blobUrl);
      blobUrl = undefined;
      imgloaded = false;
      console.debug('[effect] Revoking blobURL due to src change');
    }
  });
  let firstLoad = true;
  $effect(() => {
    if (imgloaded && image) {
      console.debug('[effect][imgload] Calling blobify. State:', {
        imgloaded,
        image,
        artifacts,
      });
      if (firstLoad) {
        requestIdleCallback(() => blobify(image!, artifacts));
        firstLoad = false;
      } else requestAnimationFrame(() => blobify(image!, artifacts));
    }
  });

  onDestroy(() => {
    if (blobUrl) URL.revokeObjectURL(blobUrl);
  });
</script>

<div
  class="relative max-w-max max-h-max block"
  aria-label={additionalOverlayedBlobsDone ? alt : undefined}
  role={additionalOverlayedBlobsDone ? 'img' : undefined}
>
  <img
    class="select-none"
    {loading}
    src={blobUrl ?? src}
    alt={additionalOverlayedBlobsDone ? undefined : alt}
    {width}
    {height}
    onload={() => (blobUrl !== undefined ? void 0 : (imgloaded = true))}
    onloadstart={() => (blobUrl !== undefined ? void 0 : (imgloaded = false))}
    bind:this={image}
  />
  {#if additionalOverlayedBlobsDone}
    {#each additionalOverlayedBlobs
      .map( (v, i, a) => (useBg ? (i % 2 === 0 ? ([v, a[i + 1]] as [string, string | undefined]) : undefined!) : ([v] as const)), )
      .filter((v) => v !== undefined) as [blob1, blob2]}
      <img
        src={blob1}
        {loading}
        alt=""
        class="blob-img"
        style={blob2 ? `background-image: url(${JSON.stringify(blob2)});}` : ''}
      />
    {/each}
  {/if}
</div>

<style lang="postcss">
  @reference "tailwindcss";

  .blob-img {
    @apply absolute top-0 left-0 h-full w-full bg-contain select-none;
  }
</style>
