<script lang="ts">
  import { onDestroy, onMount } from "svelte"
  import { writable } from "svelte/store"
  import type { Writable } from "svelte/store"

  const BREAK_INTERVAL = 20 * 60 * 1000 // 20 minutes
  const MINI_BREAK_DURATION = 20 * 1000 // 20 seconds
  const LONG_BREAK_DURATION = 5 * 60 * 1000 // 5 minutes

  let timer: number | null = null
  let miniBreakCount = 0

  let audio: HTMLAudioElement | null = null

  const playSound = () => {
    if (audio) {
      audio.pause()
      audio.src = "/sounds/Bells.mp3"
      audio.volume = 0.4
      audio.play()
    }
  }

  const showNotification = (title: string, options: NotificationOptions) => {
    if (Notification.permission === "granted") {
      new Notification(title, options)
    } else if (Notification.permission !== "denied") {
      Notification.requestPermission().then((permission) => {
        if (permission === "granted") {
          new Notification(title, options)
        }
      })
    }
  }

  const state: Writable<string> = writable("Ready")
  const timeLeftDisplay: Writable<string> = writable("")
  const timeLeft: Writable<number> = writable(BREAK_INTERVAL)

  const startTimer = () => {
    if (timer) clearInterval(timer)

    timer = setInterval(() => {
      timeLeft.update((currentTimeLeft) => {
        const newTimeLeft = currentTimeLeft - 1000
        if (newTimeLeft <= 0) {
          if ($state !== "Ready") {
            state.set("Ready")
            miniBreakCount++
            timeLeftDisplay.set(formatTime(BREAK_INTERVAL))
            showNotification("Ready", { body: "Continue working!" })
            playSound()
            return BREAK_INTERVAL
          }
          if (miniBreakCount === 3) {
            state.set("Long Break")
            miniBreakCount = 0
            timeLeftDisplay.set(formatTime(LONG_BREAK_DURATION))
            showNotification("Long Break", {
              body: "Take a 5-minute break now!",
            })
            playSound()
            return LONG_BREAK_DURATION
          } else {
            state.set("Mini Break")
            timeLeftDisplay.set(formatTime(MINI_BREAK_DURATION))
            showNotification("Mini Break", {
              body: "Take a 20-second break now!",
            })
            playSound()
            return MINI_BREAK_DURATION
          }
        }
        timeLeftDisplay.set(formatTime(newTimeLeft))
        return newTimeLeft
      })
    }, 1000)
  }

  onMount(() => {
    audio = document.createElement("audio")
    startTimer()
  })

  onDestroy(() => {
    if (timer) clearInterval(timer)
    if (audio) audio = null
  })

  const skipBreak = () => {
    if ($state === "Ready") {
      return
    }
    state.set("Ready")
    timeLeft.set(BREAK_INTERVAL)
    timeLeftDisplay.set(formatTime(BREAK_INTERVAL))
  }

  function formatTime(milliseconds: number) {
    const totalSeconds = Math.floor(milliseconds / 1000)
    const minutes = Math.floor(totalSeconds / 60)
    const seconds = totalSeconds % 60

    return `${String(minutes).padStart(2, "0")}:${String(seconds).padStart(2, "0")}`
  }
</script>

<main>
  <div>
    <h1>Prevent CVS</h1>
    {#if $state !== "Ready"}
      <p>{$state}</p>
      <p>Time left until end of break: {$timeLeftDisplay}</p>
    {:else}
      <p>Time left until break: {$timeLeftDisplay}</p>
    {/if}
    {#if $state !== "Ready"}
      <button on:click={skipBreak}>Skip Break</button>
    {/if}
  </div>
</main>

<style lang="postcss">
  main {
    @apply text-center;
    @apply mx-auto my-64;
  }

  h1 {
    @apply text-4xl mb-8;
  }

  p {
    @apply text-base mb-4;
  }

  button {
    @apply inline-block;
    @apply rounded px-4 py-2;
    @apply transition duration-300 ease-in-out;
    @apply bg-primary text-white;
  }

  button:hover {
    @apply bg-primaryLight text-white;
  }
</style>
