<script lang="ts">
    import { onMount } from "svelte";

    interface Props {
        src: string;
        [key: string]: unknown;
    }

    const saveKey = "jeopardyAudioVolume";

    let { src }: Props = $props();

    let time = $state(0);
    let duration = $state(0);
    let paused = $state(true);
    let volume = $state(100);

    onMount(() => {
        let savedVolume = localStorage.getItem(saveKey);
        if (savedVolume != null) {
            let parsedVolume = parseFloat(savedVolume);
            if (!isNaN(parsedVolume)) {
                setVolume(parsedVolume);
            }
        }
    });

    function setVolume(vol: number): void {
        const audioPlayer = document.getElementById("AudioQuestionAudioPlayer") as HTMLMediaElement;
        volume = Math.round(vol * 100);
        if (audioPlayer) {
            audioPlayer.volume = vol;
        }
    }

    function format(time: number) {
        if (isNaN(time)) return "...";

        const minutes = Math.floor(time / 60);
        const seconds = Math.floor(time % 60);

        return `${minutes}:${seconds < 10 ? `0${seconds}` : seconds}`;
    }
</script>

<div class={["player", { paused }]}>
    <audio
        id="AudioQuestionAudioPlayer"
        {src}
        bind:currentTime={time}
        bind:duration
        bind:paused
        onended={() => {
            time = 0;
        }}
    ></audio>

    <button class="play" aria-label={paused ? "play" : "pause"} onclick={() => (paused = !paused)}
    ></button>

    <div class="info">
        <div class="time">
            <span>{format(time)}</span>
            <div
                class="slider"
                onpointerdown={(e) => {
                    const div = e.currentTarget;

                    function seek(e: PointerEvent) {
                        const { left, width } = div.getBoundingClientRect();

                        let p = (e.clientX - left) / width;
                        if (p < 0) p = 0;
                        if (p > 1) p = 1;

                        time = p * duration;
                    }

                    seek(e);

                    window.addEventListener("pointermove", seek);

                    window.addEventListener(
                        "pointerup",
                        () => {
                            window.removeEventListener("pointermove", seek);
                        },
                        {
                            once: true
                        }
                    );
                }}
            >
                <div class="progress" style="--progress: {time / duration}%"></div>
            </div>
            <span>{duration ? format(duration) : "--:--"}</span>
        </div>
    </div>
    <div></div>
    <div class="info">
        <div class="time">
            <div
                class="slider"
                onpointerdown={(e) => {
                    const div = e.currentTarget;

                    function seek(e: PointerEvent) {
                        const { left, width } = div.getBoundingClientRect();

                        let p = (e.clientX - left) / width;
                        if (p < 0) p = 0;
                        if (p > 1) p = 1;

                        setVolume(p);
                        localStorage.setItem(saveKey, p.toString());
                    }

                    seek(e);

                    window.addEventListener("pointermove", seek);

                    window.addEventListener(
                        "pointerup",
                        () => {
                            window.removeEventListener("pointermove", seek);
                        },
                        {
                            once: true
                        }
                    );
                }}
            >
                <div class="volume" style="--volume: {volume / 100}%"></div>
            </div>
            <span>{volume}%</span>
        </div>
    </div>
</div>

<style>
    .player {
        display: grid;
        grid-template-columns: 2.5em 1fr;
        align-items: center;
        gap: 1em;
        padding: 0.5em 1em 0.5em 0.5em;
        border-radius: 2em;
        background: gray;
        transition: filter 0.2s;
        color: white;
        user-select: none;
        font-size: medium;
    }

    .player:not(.paused) {
        color: white;
        filter: drop-shadow(0.5em 0.5em 1em rgba(0, 0, 0, 0.1));
    }

    button {
        width: 100%;
        aspect-ratio: 1;
        background-repeat: no-repeat;
        background-position: 50% 50%;
        border-radius: 50%;
        cursor: pointer;
    }

    .play {
        width: 40px;
    }

    [aria-label="pause"] {
        background-image: url(/images/pause.svg);
    }

    [aria-label="play"] {
        background-image: url(/images/play.svg);
    }

    .info {
        overflow: hidden;
    }

    .time {
        display: flex;
        align-items: center;
        gap: 0.5em;
    }

    .time span {
        font-size: 0.7em;
    }

    .slider {
        flex: 1;
        height: 0.5em;
        background: lightgray;
        border-radius: 0.5em;
        overflow: hidden;
        cursor: grab;
    }
    .slider:active {
        cursor: grabbing;
    }

    .progress {
        width: calc(100 * var(--progress));
        height: 100%;
        background: lightgreen;
    }
    .volume {
        width: calc(100 * var(--volume));
        height: 100%;
        background: lightgreen;
    }
</style>
