<script lang="ts">
import { afterUpdate, onMount } from 'svelte';
import { fade } from 'svelte/transition';
import { audioBlob, notesImage, style } from './stores';
import { styles } from './config.json';

let section: HTMLElement;

let currentTime: number;
let duration: number;
let paused = true;

let player: HTMLDivElement;
let visualisation: HTMLImageElement;
let imageWidth: number;
let imageHeight: number;

const updateDimensions = (): void => {
  imageWidth = visualisation && visualisation.clientWidth;
  imageHeight = visualisation && visualisation.clientHeight;
};

onMount(() => {
  updateDimensions();

  if ('mediaSession' in navigator) {
    navigator.mediaSession.setActionHandler('play', () => (paused = false));
    navigator.mediaSession.setActionHandler('pause', () => (paused = true));
    navigator.mediaSession.setActionHandler('stop', () => {
      paused = true;
      currentTime = 0;
    });
  }

  window.scrollTo({ top: section.offsetTop, behavior: 'smooth' });
});

afterUpdate((): void => {
  updateDimensions();
});

const mouseMove = (event: MouseEvent): void => {
  if (!duration) {
    return;
  }

  if (!event.buttons) {
    return;
  }

  const { left, right } = player.getBoundingClientRect();
  currentTime = (duration * (event.clientX - left)) / (right - left);
};

const touchMove = (event: TouchEvent): void => {
  if (!duration) {
    return;
  }

  const { left, right } = player.getBoundingClientRect();
  currentTime = (duration * (event.touches[0].clientX - left)) / (right - left);
};

const keyDown = (event: KeyboardEvent): void => {
  event.preventDefault();

  if (event.code === 'Space') {
    paused = !paused;
  }
  if (event.code === 'ArrowLeft') {
    currentTime = currentTime >= 1 ? currentTime - 1 : 0;
  }
  if (event.code === 'ArrowRight') {
    currentTime = currentTime <= duration - 1 ? currentTime + 1 : duration;
  }
};
</script>

<section bind:this={section} transition:fade>
  <img class="notes" src={$notesImage} alt="" bind:this={visualisation} />
  <div
    bind:this={player}
    class="player"
    style:width={imageWidth + 'px'}
    style:height={imageHeight + 'px'}
    on:mousemove={mouseMove}
    on:touchmove|preventDefault={touchMove}
    on:keydown={keyDown}
    on:click={() => (paused = !paused)}
    tabindex="0"
  >
    <audio bind:currentTime bind:duration bind:paused src={$audioBlob} />
    <div
      class="handle"
      style:transform="translate({Math.min(imageWidth * (currentTime / (duration - 0.9)), imageWidth)}px, -2%)"
    />
    {#if paused}
      <img
        class="play-button"
        src="static/play.svg"
        alt="Play button"
        draggable="false"
        transition:fade
        style:width={imageHeight > 100 ? '20%' : '7.5%'}
      />
    {/if}
  </div>
  <a href={$audioBlob} download={`${styles[$style]} Composition - AI Guru ft. Hugging Face.wav`} class="download"
    >Download</a
  >
</section>

<style>
section {
  display: flex;
  flex-direction: column;
  position: relative;
  border: 2px solid hsl(0 0% 80%);
  border-radius: 0.375rem;
  padding: 1rem;
}

.player {
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  cursor: pointer;
}
.notes {
  width: min(100%, 512px);
  margin: auto;
  box-shadow: 0 0 5px 0.1px hsl(210, 10%, 20%);
}

audio {
  width: 100%;
  margin: 1rem auto;
}
.play-button {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 20%;
  aspect-ratio: 1 / 1;
  transform: translate(-50%, -50%);
  filter: drop-shadow(0 0 5px black);
  pointer-events: none;
  cursor: pointer;
}
.handle {
  position: absolute;
  left: 0;
  top: 0;
  height: 104%;
  width: 0.2rem;
  border-radius: 0.1rem;
  background-color: white;
  cursor: pointer;
  transform: translate(0, -2%);
}

a.download {
  display: block;
  font-size: 1.2rem;
  font-family: 'Lato', sans-serif;
  font-weight: 700;
  color: hsl(0 0% 97%);
  background: transparent;
  border: 3px solid hsl(0 0% 97%);
  border-radius: 0.375rem;
  padding: 0.5rem 1rem;
  cursor: pointer;
  margin: 1rem auto auto;
}

@media (min-width: 600px) {
  section {
    padding: 2rem;
  }
}
</style>