<script lang="ts">
  import Dither from 'canvas-dither'
    import ErrorMessage from './ErrorMessage.svelte';
    import { onMount } from 'svelte';
  
  const DITHERING_ALGORITHMS = {
    atkinson: (imageData: ImageData) => Dither.atkinson(imageData),
    bayer: (imageData: ImageData) => Dither.bayer(imageData, 170),
    floydSteinberg: (imageData: ImageData) => Dither.floydsteinberg(imageData),
    threshold: (imageData: ImageData) => Dither.threshold(imageData, 2),
  }

  let canvas: HTMLCanvasElement;
  let offscreenCanvas: OffscreenCanvas;
  let ctx = $derived(canvas.getContext('2d'))
  let offscreenCtx: OffscreenCanvasRenderingContext2D;
  let selectedImage: HTMLImageElement | null = $state(null)
  let errorMessage = $state('')
  let selectedAlgorithm = $state('atkinson')

  let maxImageWidth = $state(0)
  let imageHeightRatio = $state(0)
  let imageWidthPc = $state(100)

  onMount(() => {
   offscreenCanvas = new OffscreenCanvas(1000, 1000)
   offscreenCtx = offscreenCanvas.getContext('2d')
  })

  $effect(() => {
    if (!selectedImage) {
      console.log(`Selected Image is null, terminating effect...`)
      return;
    }

    maxImageWidth = selectedImage.width 
    imageHeightRatio = selectedImage.height / selectedImage.width

    ctx.clearRect(0, 0, canvas.width, canvas.height)

    canvas.width = maxImageWidth * (imageWidthPc/100)
    canvas.height = imageHeightRatio * canvas.width
    ctx.drawImage(selectedImage, 0, 0, canvas.width, canvas.height)

    const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height)
    ctx.putImageData(DITHERING_ALGORITHMS[selectedAlgorithm](imageData), 0, 0)
  })

  const handleImageChange = async (event: any) => {
    const file = event.target.files[0];
    if (!file) {
      errorMessage = "No file selected, try again"
      return
    }

    const imgObjectUrl = URL.createObjectURL(file);
    selectedImage = await createImage(imgObjectUrl);
  }

  async function createImage(objectUrl: string):  Promise<HTMLImageElement> {
    return new Promise<HTMLImageElement>((resolve) => {
      const img = new Image();
      img.onload = () => {
        if (!ctx) return;
        resolve(img);
      }
      img.src = objectUrl;
    });
  }

  function saveImage() {
    const link = document.createElement('a');
    link.download = 'dithered-image.png';
    link.href = canvas.toDataURL();
    link.click();
  }

</script>

<ErrorMessage errorMessage={errorMessage} />

<h2 class="page-dither__subtitle">1: Select a file</h2>

<form class="file-form">
  <label for="file"> Select a file<br />
    <input type="file" name="file" id="file" onchange={handleImageChange} accept="image/*" >
  </label>
</form>

<h2 class="page-dither__subtitle">2: Select a dithering algorithm</h2>

<ul class="algorithms">
  {#each Object.keys(DITHERING_ALGORITHMS) as key}
    <li class="algorithms__item">
      <button class="algorithms__button" onclick={() => selectedAlgorithm = key}>{key}</button>
    </li>
  {/each}
</ul>


<div class="canvas-container">
  <canvas id="photo-canvas" height="250" bind:this={canvas} onload={() => ctx = canvas.getContext('2d')}></canvas>
</div>

<h2 class="page-dither__subtitle">
  3: Remix 
</h2>

<form>
  <label for="resolution">
    Image Ratio
    <input type="range" min="1" max="100" step="5" bind:value={imageWidthPc} width="100%"/>
  </label>
  <p>{maxImageWidth * imageWidthPc / 100}</p>
</form>

<h2 class="page-dither__subtitle">
  4: Save the file
</h2>
<button onclick={saveImage}>Save Image</button>


<style>
  .algorithms {
    list-style: none;
    display: grid;
    grid-template-columns: auto;
    gap: 4px;
  }

  .algorithms__button {
    box-shadow: 5px 2px blue;

      &:hover {
        background: var()
      }
  }

  .canvas-container {
    display: flex;
    width: auto;
    padding: 14px;
    height: min-content
  }

  #photo-canvas {
    width: 100%;
  }


</style>
