<script lang="ts">
import { density, composing, style, temperature, notesImage, notesTokens, audioBlob } from '$lib/stores';
import { styles } from './config.json';

const updateMetadata = () => {
  if ('mediaSession' in navigator) {
    navigator.mediaSession.metadata = new MediaMetadata({
      title: `${styles[$style]} Composition`,
      artist: 'AI Guru Composer',
      album: 'Hugging Face',
      artwork: [
        {
          src: 'static/hugging-face-headphones.png',
          sizes: '512x512',
          type: 'image/png',
        },
      ],
    });
  }
};

const createTask = async ({
  music_style,
  density,
  temperature,
}: {
  music_style: string;
  density: string;
  temperature: string;
}) => {
  const taskResponse = await fetch('task/create', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      music_style,
      density,
      temperature,
    }),
  });

  if (!taskResponse.ok || !taskResponse.headers.get('content-type')?.includes('application/json')) {
    throw new Error(`Unable to create composition: [${taskResponse.status}] ${await taskResponse.text()}`);
  }

  const task = await taskResponse.json();

  return task;
};

const pollTask = async (task: Record<string, any>) => {
  const taskResponse = await fetch(`task/poll?task_id=${task.task_id}`);

  if (!taskResponse.ok || !taskResponse.headers.get('content-type')?.includes('application/json')) {
    throw new Error(`Unable to create composition: [${taskResponse.status}] ${await taskResponse.text()}`);
  }

  return await taskResponse.json();
};

const longPollTask = async (task: Record<string, any>, interval = 1_000, max = 100): Promise<Record<string, any>> => {
  task = await pollTask(task);

  if (task.status === 'completed' || task.status === 'failed' || (max && task.poll_count > max)) {
    return task;
  }

  await new Promise((resolve) => setTimeout(resolve, interval));

  return await longPollTask(task, interval, max);
};

const compose = async () => {
  $composing = true;
  try {
    const task = await createTask({
      music_style: $style,
      density: $density,
      temperature: $temperature,
    });

    const completedTask = await longPollTask(task);
    const { audio, image, tokens } = completedTask.output;
    $audioBlob = audio;
    $notesImage = image;
    $notesTokens = tokens;

    updateMetadata();
  } catch (err) {
    console.error(err);
  } finally {
    $composing = false;
  }
};
</script>

<button disabled={$composing} on:click={compose}>
  {#if $composing}
    Composing...
  {:else}
    Compose <img src="static/wand.svg" alt="Magic wand" />
  {/if}
</button>

<style>
button {
  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 2rem;
}

button[disabled] {
  border-color: hsl(0 0% 50%);
  color: hsl(0 0% 50%);
  cursor: initial;
}

img {
  height: 1.2rem;
  aspect-ratio: 1 / 1;
  vertical-align: bottom;
}

@media (min-width: 900px) {
  button {
    margin-top: 0;
  }
}
</style>
