<!-->
	 taken from https://github.com/Linkcube/svelte-audio-controls
	 ISC License
-->
<svelte:options accessors />

<script context="module">
	let getAudio = null;

	export function jumpToTrack(s) {
		getAudio().currentTime = s;
		getAudio().play();
	}
</script>

<script>
	import { onMount, onDestroy } from 'svelte';
	import { fade } from 'svelte/transition';
	import {
		currentSongIndex,
		currentStream,
		getSongAtTime,
		updateCurrentSong
	} from '$lib/stores.js';

	export let src;
	export let audio = null;
	export let paused = true;
	export let duration = 0;
	export let muted = false;
	export let volume = 0.67;
	export let preload = 'metadata';
	export let iconColor = 'gray';
	export let textColor = 'gray';
	export let barPrimaryColor = 'lightblue';
	export let barSecondaryColor = '#6f6f6f';
	export let backgroundColor = 'white';
	export let display = false;
	export let inlineTooltip = false;
	export let disableTooltip = false;

	getAudio = () => {
		return audio;
	};

	let currentTime = 0;
	let tooltip;
	let tooltipX = 0;
	let tooltipY = 0;
	let showTooltip = false;
	let seekText = '';
	let seekTrack = '';
	let seeking = false;
	let volumeSeeking = false;
	let songBar;
	let volumeBar;
	let innerWidth;
	let innerHeight;

	onMount(async () => {
		// default volume
		const volumeData = localStorage.getItem('volume');
		volume = volumeData ? parseFloat(volumeData) : 0.67;
		setVolume(volume);

		// update browser metadata on track changes
		if ('mediaSession' in navigator) {
			currentSongIndex.subscribe((val) => {
				if (val != null && !paused) {
					setMediaMetadata($currentStream.tracks[val]);
				}
			});
		}
	});

	$: updateCurrentSong(currentTime, $currentSongIndex);
	$: updateAudioAttributes(audio);

	function seek(event, bounds) {
		let x = event.pageX - bounds.left;
		return Math.min(Math.max(x / bounds.width, 0), 1);
	}

	// exponential volume bar
	// default is linear, which doesn't correspond to human hearing
	function setVolume(volume) {
		if (volume != 0) {
			audio.volume = Math.pow(10, 2.5 * (volume - 1));
		} else {
			audio.volume = volume;
		}
	}

	function setMediaMetadata(track) {
		navigator.mediaSession.metadata = new MediaMetadata({
			artist: track[1],
			title: track[2]
		});
	}

	// browsers don't like if you update this while no media is playing
	function setMediaMetadataOnPlay() {
		if ('mediaSession' in navigator) {
			setMediaMetadata($currentStream.tracks[$currentSongIndex]);
		}
	}

	// workaround for bug https://github.com/sveltejs/svelte/issues/5347
	// need to init duration & volume after SSR first load
	function updateAudioAttributes(audio) {
		if (audio && audio.duration) {
			duration = audio.duration;
			setVolume(volume);

			// workaround for bug https://github.com/sveltejs/svelte/issues/5914
			audio.addEventListener('loadedmetadata', (event) => {
				paused = audio.paused;
			});
		}
	}

	function seekAudio(event) {
		if (!songBar) return;
		audio.currentTime = seek(event, songBar.getBoundingClientRect()) * duration;
	}

	function seekVolume(event) {
		if (!volumeBar) return;
		volume = seek(event, volumeBar.getBoundingClientRect());
		setVolume(volume);
		localStorage.setItem('volume', volume.toString());
		muted = false;
	}

	function formatSeconds(seconds) {
		if (isNaN(seconds)) return 'No Data';
		var sec_num = parseInt(seconds, 10);
		var hours = Math.floor(sec_num / 3600);
		var minutes = Math.floor(sec_num / 60) % 60;
		var seconds = sec_num % 60;

		return [hours, minutes, seconds]
			.map((v) => (v < 10 ? '0' + v : v))
			.filter((v, i) => v !== '00' || i > 0)
			.join(':');
	}

	function seekTooltip(event) {
		if (!inlineTooltip) {
			let tooltipBounds = tooltip.getBoundingClientRect();
			tooltipX = Math.min(event.pageX + 10, innerWidth - tooltipBounds.width);
			tooltipY = Math.min(songBar.offsetTop - 30, innerHeight - tooltipBounds.height);
		}
		let bounds = songBar.getBoundingClientRect();
		let seekValue = ((event.pageX - bounds.left) * duration) / bounds.width;
		let trackArray = $currentStream.tracks[getSongAtTime(seekValue)];
		seekTrack = trackArray[1] + ' - ' + trackArray[2];
		seekText = formatSeconds(seekValue);
	}

	function trackMouse(event) {
		if (seeking) seekAudio(event);
		if (showTooltip && !disableTooltip) seekTooltip(event);
		if (volumeSeeking) seekVolume(event);
	}
</script>

<svelte:window
	bind:innerWidth
	bind:innerHeight
	on:mouseup={() => (seeking = volumeSeeking = false)}
	on:mousemove={trackMouse}
/>

{#if display}
	<div class="controls" style="--color:{textColor}; --background-color:{backgroundColor}">
		<button
			class="material-icons"
			style="--icon-color:{iconColor}"
			on:click={() => (audio.paused ? audio.play() : audio.pause())}
		>
			{#if paused}
				play_arrow
			{:else}
				pause
			{/if}
		</button>
		<progress
			bind:this={songBar}
			value={currentTime ? currentTime : 0}
			max={duration}
			on:mousedown={() => (seeking = true)}
			on:mouseenter={() => (showTooltip = true)}
			on:mouseleave={() => (showTooltip = false)}
			on:click={seekAudio}
			style="--primary-color:{barPrimaryColor}; --secondary-color:{barSecondaryColor}"
			class="song-progress"
		/>
		<div class="control-times">{formatSeconds(currentTime)}/{formatSeconds(duration)}</div>
		<button
			style="--icon-color:{iconColor}"
			class="material-icons"
			on:click={() => (muted = !muted)}
		>
			{#if muted}
				volume_off
			{:else if volume < 0.01}
				volume_mute
			{:else if volume < 0.5}
				volume_down
			{:else}
				volume_up
			{/if}
		</button>
		<progress
			bind:this={volumeBar}
			value={volume}
			on:mousedown={() => (volumeSeeking = true)}
			on:click={seekVolume}
			style="--primary-color:{barPrimaryColor}; --secondary-color:{barSecondaryColor}"
			class="volume-progress"
		/>
		{#if !disableTooltip && (inlineTooltip || showTooltip)}
			<div
				class:hover-tooltip={!inlineTooltip}
				transition:fade
				bind:this={tooltip}
				class="tooltip"
				style="--left:{tooltipX}px;
                --top:{tooltipY}px;
                --background-color:{backgroundColor};
                --box-color:{barSecondaryColor};
                --text-color:{textColor}"
			>
				{#if showTooltip}
					{seekText}
					<br />
					{seekTrack}
				{:else if duration > 3600}
					--:--:--
				{:else}
					--:--
				{/if}
			</div>
		{/if}
	</div>
{/if}

<audio
	bind:this={audio}
	bind:paused
	bind:duration
	bind:currentTime
	{muted}
	{volume}
	on:play={setMediaMetadataOnPlay}
	on:ended
	{src}
	{preload}
/>

<style>
	.controls {
		display: flex;
		flex-flow: row;
		justify-content: space-around;
		color: var(--color);
		background-color: var(--background-color);
		padding-left: 10px;
		padding-right: 10px;
		-webkit-user-select: none; /* Safari */
		-ms-user-select: none; /* IE 10+ and Edge */
		user-select: none; /* Standard syntax */
		padding-top: 5px;
		padding-bottom: 5px;
		border: 3px double;
		border-radius: 5px;
		color: rgba(0, 0, 0, 0.6);
	}

	.control-times {
		margin: auto;
		margin-right: 5px;
	}

	.tooltip {
		background-color: var(--background-color);
		padding: 1px;
		border-radius: 5px;
		border-width: 3px;
		box-shadow: 6px 6px var(--box-color);
		color: var(--text-color);
		pointer-events: none;
		min-width: 50px;
		text-align: center;
		margin-bottom: 5px;
	}

	.hover-tooltip {
		position: absolute;
		top: var(--top);
		left: var(--left);
	}

	.material-icons {
		font-size: 16px;
		margin-bottom: 0px;
		color: var(--icon-color);
		background-color: rgba(0, 0, 0, 0);
		cursor: pointer;
		transition: 0.3s;
		border: none;
		border-radius: 25px;
	}

	.material-icons:hover {
		box-shadow: 0px 6px rgba(0, 0, 0, 0.6);
	}

	.material-icons::-moz-focus-inner {
		border: 0;
	}

	progress {
		display: block;
		color: var(--primary-color);
		background: var(--secondary-color);
		border: none;
		height: 15px;
		margin: auto;
		margin-left: 5px;
		margin-right: 5px;
	}

	progress::-webkit-progress-bar {
		background-color: var(--secondary-color);
		width: 100%;
	}

	progress::-moz-progress-bar {
		background: var(--primary-color);
	}

	progress::-webkit-progress-value {
		background: var(--primary-color);
	}

	.song-progress {
		width: 100%;
	}

	.volume-progress {
		width: 10%;
		max-width: 100px;
		min-width: 50px;
	}
</style>
