<script lang="ts">
	import { onMount, onDestroy } from 'svelte';
	import { get } from 'svelte/store';
	import { trackEnded, onPlaybackControl, onSeek, onVolume, reportPlaybackState } from '$lib/socket';
	import { currentVolume } from '$lib/stores/content';

	interface Props {
		src: string;
		title: string;
		artistName?: string;
		thumbnail?: string;
		duration?: number;
		autoplay?: boolean;
	}

	let { src, title, artistName, thumbnail, duration: propDuration, autoplay = true }: Props = $props();

	let audioElement: HTMLAudioElement | null = $state(null);
	let waveformData: number[] = $state([]);
	let isLoading = $state(true);
	let isPlaying = $state(false);
	let currentTime = $state(0);
	let duration = $state(propDuration || 0);
	let error = $state<string | null>(null);

	let unsubPlayback: (() => void) | null = null;
	let unsubSeek: (() => void) | null = null;
	let unsubVolume: (() => void) | null = null;
	let previousSrc: string | null = null;
	let audioContext: AudioContext | null = null;
	let analyser: AnalyserNode | null = null;
	let isRealtimeWaveform = $state(false);
	let animationFrame: number | null = null;
	let isLightArtwork = $state(false);

	const WAVEFORM_BARS = 100;

	// Detect if artwork is light or dark to set logo color
	function detectArtworkBrightness(imgSrc: string) {
		const img = new Image();
		img.crossOrigin = 'anonymous';
		img.onload = () => {
			try {
				const canvas = document.createElement('canvas');
				const ctx = canvas.getContext('2d');
				if (!ctx) return;

				// Sample a small version for performance
				canvas.width = 50;
				canvas.height = 50;
				ctx.drawImage(img, 0, 0, 50, 50);

				const imageData = ctx.getImageData(0, 0, 50, 50);
				const data = imageData.data;
				let totalBrightness = 0;

				// Calculate average brightness
				for (let i = 0; i < data.length; i += 4) {
					// Perceived brightness formula
					const brightness = (data[i] * 0.299 + data[i + 1] * 0.587 + data[i + 2] * 0.114);
					totalBrightness += brightness;
				}

				const avgBrightness = totalBrightness / (data.length / 4);
				isLightArtwork = avgBrightness > 128;
				console.log('[SoundCloud] Artwork brightness:', avgBrightness, isLightArtwork ? 'light' : 'dark');
			} catch (e) {
				console.error('[SoundCloud] Failed to analyze artwork:', e);
			}
		};
		img.src = imgSrc;
	}

	// Analyze artwork when thumbnail changes
	$effect(() => {
		if (thumbnail) {
			detectArtworkBrightness(thumbnail);
		}
	});

	function handleAudioEnabled() {
		console.log('[SoundCloud] droppyAudioEnabled received, attempting play');
		if (audioElement && audioElement.paused) {
			audioElement.play().then(() => {
				console.log('[SoundCloud] Play succeeded after user interaction');
			}).catch((err) => {
				console.log('[SoundCloud] Play still failed:', err.message);
			});
		}
	}

	onMount(async () => {
		previousSrc = src;
		// Generate waveform from audio
		await generateWaveform();

		// Listen for audio enable event (user clicked "Click to Start")
		window.addEventListener('droppyAudioEnabled', handleAudioEnabled);

		// Subscribe to remote playback controls
		unsubPlayback = onPlaybackControl((action) => {
			if (!audioElement) return;
			if (action === 'play') {
				audioElement.play().catch(() => {});
			} else if (action === 'pause') {
				audioElement.pause();
			} else if (action === 'toggle') {
				if (audioElement.paused) {
					audioElement.play().catch(() => {});
				} else {
					audioElement.pause();
				}
			}
		});

		// Subscribe to remote seek
		unsubSeek = onSeek((time) => {
			if (audioElement) {
				audioElement.currentTime = time;
			}
		});

		// Subscribe to volume changes
		unsubVolume = onVolume((volume) => {
			console.log('[SoundCloud] Volume change received:', volume, 'audioElement:', !!audioElement);
			if (audioElement) {
				audioElement.volume = volume;
			}
		});
	});

	onDestroy(() => {
		unsubPlayback?.();
		unsubSeek?.();
		unsubVolume?.();
		window.removeEventListener('droppyAudioEnabled', handleAudioEnabled);
		if (animationFrame) {
			cancelAnimationFrame(animationFrame);
		}
		if (audioContext) {
			audioContext.close();
		}
	});

	// Watch for src changes to regenerate waveform
	$effect(() => {
		// This effect tracks `src` - when it changes, regenerate
		if (previousSrc !== null && src !== previousSrc) {
			previousSrc = src;
			// Clean up previous real-time waveform
			if (animationFrame) {
				cancelAnimationFrame(animationFrame);
				animationFrame = null;
			}
			if (audioContext) {
				audioContext.close();
				audioContext = null;
				analyser = null;
			}
			// Reset state for new track
			waveformData = [];
			isLoading = true;
			isRealtimeWaveform = false;
			error = null;
			currentTime = 0;
			isPlaying = false;
			duration = propDuration || 0;
			generateWaveform();
		}
	});

	async function generateWaveform() {
		try {
			isLoading = true;
			console.log('[SoundCloud Waveform] Starting generation for:', src);

			// Fetch audio data
			const response = await fetch(src);
			if (!response.ok) {
				console.error('[SoundCloud Waveform] Fetch failed:', response.status, response.statusText);
				throw new Error(`Failed to load audio: ${response.status}`);
			}

			const arrayBuffer = await response.arrayBuffer();
			console.log('[SoundCloud Waveform] Fetched', arrayBuffer.byteLength, 'bytes');

			if (arrayBuffer.byteLength === 0) {
				throw new Error('Empty audio buffer');
			}

			// Decode audio using Web Audio API
			const ctx = new (window.AudioContext || (window as any).webkitAudioContext)();
			const audioBuffer = await ctx.decodeAudioData(arrayBuffer);
			console.log('[SoundCloud Waveform] Decoded audio:', audioBuffer.duration, 'seconds');

			// Extract waveform using RMS (root mean square) like SoundCloud-Waveform-Generator
			const channelData = audioBuffer.getChannelData(0);
			const sectionSize = Math.floor(channelData.length / WAVEFORM_BARS);
			const peaks: number[] = [];

			for (let i = 0; i < WAVEFORM_BARS; i++) {
				const start = i * sectionSize;
				const end = Math.min(start + sectionSize, channelData.length);

				// Calculate RMS for this section
				let sum = 0;
				for (let j = start; j < end; j++) {
					sum += channelData[j] * channelData[j];
				}
				const rms = Math.sqrt(sum / (end - start));
				peaks.push(rms);
			}

			// Normalize to 0-1 range
			const maxPeak = Math.max(...peaks);
			if (maxPeak > 0) {
				waveformData = peaks.map(p => p / maxPeak);
			} else {
				waveformData = peaks.map(() => 0.1);
			}

			// Set duration from audio buffer
			if (!duration) {
				duration = audioBuffer.duration;
			}

			ctx.close();
			isLoading = false;
			console.log('[SoundCloud Waveform] Generation complete');
		} catch (e) {
			console.error('[SoundCloud Waveform] Pre-fetch failed, switching to real-time:', e);
			// Switch to real-time waveform generation from audio element
			isRealtimeWaveform = true;
			// Initialize with flat waveform - will be updated in real-time when audio plays
			waveformData = Array.from({ length: WAVEFORM_BARS }, () => 0.15);
			isLoading = false;
		}
	}

	// Set up real-time waveform analysis from audio element
	function setupRealtimeWaveform() {
		if (!audioElement || audioContext) return;

		try {
			audioContext = new (window.AudioContext || (window as any).webkitAudioContext)();
			const source = audioContext.createMediaElementSource(audioElement);
			analyser = audioContext.createAnalyser();
			analyser.fftSize = 256;

			source.connect(analyser);
			analyser.connect(audioContext.destination);

			console.log('[SoundCloud Waveform] Real-time analyser connected');
			updateRealtimeWaveform();
		} catch (e) {
			console.error('[SoundCloud Waveform] Failed to setup real-time analyser:', e);
		}
	}

	function updateRealtimeWaveform() {
		if (!analyser || !isPlaying) {
			animationFrame = null;
			return;
		}

		const bufferLength = analyser.frequencyBinCount;
		const dataArray = new Uint8Array(bufferLength);
		analyser.getByteFrequencyData(dataArray);

		// Map frequency data to waveform bars
		const barsFromFreq = Math.min(bufferLength, WAVEFORM_BARS);
		const newWaveform = Array.from({ length: WAVEFORM_BARS }, (_, i) => {
			const freqIndex = Math.floor((i / WAVEFORM_BARS) * barsFromFreq);
			return dataArray[freqIndex] / 255;
		});

		waveformData = newWaveform;
		animationFrame = requestAnimationFrame(updateRealtimeWaveform);
	}

	function handleTimeUpdate() {
		if (audioElement) {
			currentTime = audioElement.currentTime;
			// Report playback state to uploader
			reportPlaybackState({
				playing: !audioElement.paused,
				currentTime: audioElement.currentTime,
				duration: audioElement.duration || duration
			});
		}
	}

	function handlePlayPauseState() {
		if (audioElement) {
			reportPlaybackState({
				playing: !audioElement.paused,
				currentTime: audioElement.currentTime,
				duration: audioElement.duration || duration
			});
		}
	}

	function handleLoadedMetadata() {
		console.log('[SoundCloud] handleLoadedMetadata called, audioElement:', !!audioElement);
		if (audioElement) {
			duration = audioElement.duration;
			console.log('[SoundCloud] Duration:', duration, 'Autoplay:', autoplay);
			// Apply initial volume from store
			audioElement.volume = get(currentVolume);
			if (autoplay) {
				console.log('[SoundCloud] Attempting autoplay...');
				audioElement.play().then(() => {
					console.log('[SoundCloud] Autoplay succeeded');
				}).catch((err) => {
					console.log('[SoundCloud] Autoplay blocked:', err.message);
				});
			}
		}
	}

	function handlePlay() {
		isPlaying = true;
		handlePlayPauseState();
		// Start real-time waveform if in that mode
		if (isRealtimeWaveform) {
			setupRealtimeWaveform();
			if (analyser) {
				updateRealtimeWaveform();
			}
		}
	}

	function handlePause() {
		isPlaying = false;
		handlePlayPauseState();
		// Stop real-time waveform animation
		if (animationFrame) {
			cancelAnimationFrame(animationFrame);
			animationFrame = null;
		}
	}

	function handleEnded() {
		isPlaying = false;
		trackEnded();
	}

	function handleError() {
		error = 'Failed to play audio';
	}

	function seekTo(event: MouseEvent) {
		if (!audioElement || !duration) return;

		const waveform = event.currentTarget as HTMLElement;
		const rect = waveform.getBoundingClientRect();
		const x = event.clientX - rect.left;
		const percent = x / rect.width;
		const newTime = percent * duration;

		audioElement.currentTime = newTime;
	}

	function togglePlayPause() {
		if (!audioElement) return;
		if (audioElement.paused) {
			audioElement.play().catch(() => {});
		} else {
			audioElement.pause();
		}
	}

	function formatTime(seconds: number): string {
		const mins = Math.floor(seconds / 60);
		const secs = Math.floor(seconds % 60);
		return `${mins}:${secs.toString().padStart(2, '0')}`;
	}

	let progress = $derived(duration > 0 ? (currentTime / duration) * 100 : 0);
	let progressBarIndex = $derived(Math.floor((currentTime / duration) * WAVEFORM_BARS) || 0);
</script>

<div class="soundcloud-player">
	<!-- Background blur from artwork -->
	{#if thumbnail}
		<div class="player-backdrop" style="background-image: url({thumbnail})"></div>
	{/if}
	<div class="player-overlay"></div>

	<div class="player-content">
		<!-- Artwork -->
		<div class="artwork-section">
			{#if thumbnail}
				<img src={thumbnail} alt="Track artwork" class="artwork" />
			{:else}
				<div class="artwork-placeholder">
					<svg viewBox="0 0 24 24">
						<path d="M9 18V5l12-2v13"/>
						<circle cx="6" cy="18" r="3"/>
						<circle cx="18" cy="16" r="3"/>
					</svg>
				</div>
			{/if}

			<!-- Play/Pause overlay button -->
			<button class="play-overlay" onclick={togglePlayPause} aria-label={isPlaying ? 'Pause' : 'Play'}>
				{#if isPlaying}
					<svg viewBox="0 0 24 24" class="pause-icon">
						<rect x="6" y="4" width="4" height="16"/>
						<rect x="14" y="4" width="4" height="16"/>
					</svg>
				{:else}
					<svg viewBox="0 0 24 24" class="play-icon">
						<polygon points="5 3 19 12 5 21 5 3"/>
					</svg>
				{/if}
			</button>
		</div>

		<!-- Track info and waveform -->
		<div class="track-section">
			<div class="track-header">
				<div class="track-meta">
					<h1 class="track-title">{title}</h1>
					{#if artistName}
						<p class="track-artist">{artistName}</p>
					{/if}
				</div>
				<div class="soundcloud-badge">
					<img
						src={isLightArtwork ? "https://vault.moe/or760bEJ0KtY.png" : "https://vault.moe/YDgpzxVhx7uL.png"}
						alt="SoundCloud"
					/>
				</div>
			</div>

			<!-- Waveform visualization -->
			<div class="waveform-container">
				{#if isLoading}
					<div class="waveform-loading">
						<div class="loading-bar"></div>
					</div>
				{:else if error}
					<div class="waveform-error">{error}</div>
				{:else}
					<button
						class="waveform"
						onclick={seekTo}
						aria-label="Seek in track"
					>
						{#each waveformData as amplitude, i}
							<div
								class="waveform-bar"
								class:played={i < progressBarIndex}
								style="height: {Math.max(4, amplitude * 100)}%"
							></div>
						{/each}

						<!-- Progress indicator line -->
						<div class="progress-line" style="left: {progress}%"></div>
					</button>
				{/if}
			</div>

			<!-- Time display -->
			<div class="time-display">
				<span class="current-time">{formatTime(currentTime)}</span>
				<span class="duration">{formatTime(duration)}</span>
			</div>
		</div>
	</div>

	<!-- Hidden audio element -->
	<audio
		bind:this={audioElement}
		{src}
		ontimeupdate={handleTimeUpdate}
		onloadedmetadata={handleLoadedMetadata}
		onplay={handlePlay}
		onpause={handlePause}
		onended={handleEnded}
		onerror={handleError}
		preload="auto"
	></audio>
</div>

<style>
	.soundcloud-player {
		position: relative;
		width: 100%;
		height: 100%;
		display: flex;
		align-items: center;
		justify-content: center;
		overflow: hidden;
		font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
	}

	.player-backdrop {
		position: absolute;
		inset: -100px;
		background-size: cover;
		background-position: center;
		filter: blur(80px) saturate(1.5) brightness(0.3);
		transform: scale(1.3);
	}

	.player-overlay {
		position: absolute;
		inset: 0;
		background: linear-gradient(135deg, rgba(255, 85, 0, 0.1) 0%, rgba(0, 0, 0, 0.6) 100%);
	}

	.player-content {
		position: relative;
		z-index: 1;
		display: flex;
		align-items: center;
		gap: clamp(2rem, 5vw, 4rem);
		padding: clamp(2rem, 5vw, 4rem);
		max-width: 1400px;
		width: 100%;
	}

	/* Artwork section */
	.artwork-section {
		position: relative;
		flex-shrink: 0;
	}

	.artwork {
		width: clamp(200px, 30vmin, 350px);
		height: clamp(200px, 30vmin, 350px);
		border-radius: 8px;
		object-fit: cover;
		box-shadow:
			0 8px 40px rgba(0, 0, 0, 0.5),
			0 0 0 1px rgba(255, 255, 255, 0.1);
	}

	.artwork-placeholder {
		width: clamp(200px, 30vmin, 350px);
		height: clamp(200px, 30vmin, 350px);
		border-radius: 8px;
		background: linear-gradient(135deg, #2a2a2a 0%, #1a1a1a 100%);
		display: flex;
		align-items: center;
		justify-content: center;
		box-shadow:
			0 8px 40px rgba(0, 0, 0, 0.5),
			0 0 0 1px rgba(255, 255, 255, 0.1);
	}

	.artwork-placeholder svg {
		width: 40%;
		height: 40%;
		stroke: #ff5500;
		fill: none;
		stroke-width: 1.5;
		opacity: 0.5;
	}

	.play-overlay {
		position: absolute;
		inset: 0;
		display: flex;
		align-items: center;
		justify-content: center;
		background: rgba(0, 0, 0, 0.4);
		border-radius: 8px;
		border: none;
		cursor: pointer;
		opacity: 0;
		transition: opacity 0.2s ease;
	}

	.artwork-section:hover .play-overlay {
		opacity: 1;
	}

	.play-overlay svg {
		width: 80px;
		height: 80px;
		fill: #ff5500;
		filter: drop-shadow(0 4px 12px rgba(255, 85, 0, 0.4));
	}

	/* Track section */
	.track-section {
		flex: 1;
		min-width: 0;
		display: flex;
		flex-direction: column;
		gap: 1.5rem;
	}

	.track-header {
		display: flex;
		align-items: flex-start;
		justify-content: space-between;
		gap: 1rem;
	}

	.track-meta {
		min-width: 0;
	}

	.track-title {
		font-size: clamp(2rem, 5vmin, 3.5rem);
		font-weight: 700;
		color: #fff;
		margin: 0;
		line-height: 1.2;
		text-shadow: 0 2px 20px rgba(0, 0, 0, 0.5);
		word-wrap: break-word;
	}

	.track-artist {
		font-size: clamp(1.2rem, 3vmin, 2rem);
		font-weight: 400;
		color: rgba(255, 255, 255, 0.7);
		margin: 0.5rem 0 0;
	}

	.soundcloud-badge {
		flex-shrink: 0;
		width: 52px;
		height: 52px;
		background: #ff5500;
		border-radius: 12px;
		display: flex;
		align-items: center;
		justify-content: center;
		box-shadow: 0 4px 20px rgba(255, 85, 0, 0.3);
	}

	.soundcloud-badge img {
		width: 32px;
		height: 32px;
		object-fit: contain;
	}

	/* Waveform */
	.waveform-container {
		width: 100%;
		height: 120px;
		position: relative;
	}

	.waveform-loading {
		width: 100%;
		height: 100%;
		display: flex;
		align-items: center;
		justify-content: center;
		background: rgba(255, 255, 255, 0.05);
		border-radius: 4px;
	}

	.loading-bar {
		width: 200px;
		height: 4px;
		background: rgba(255, 255, 255, 0.1);
		border-radius: 2px;
		overflow: hidden;
		position: relative;
	}

	.loading-bar::after {
		content: '';
		position: absolute;
		top: 0;
		left: -100%;
		width: 100%;
		height: 100%;
		background: linear-gradient(90deg, transparent, #ff5500, transparent);
		animation: loading-slide 1.5s ease-in-out infinite;
	}

	@keyframes loading-slide {
		0% { left: -100%; }
		100% { left: 100%; }
	}

	.waveform-error {
		width: 100%;
		height: 100%;
		display: flex;
		align-items: center;
		justify-content: center;
		color: #ff5500;
		font-size: 1rem;
	}

	.waveform {
		width: 100%;
		height: 100%;
		display: flex;
		align-items: center;
		gap: 2px;
		cursor: pointer;
		background: transparent;
		border: none;
		padding: 0;
		position: relative;
	}

	.waveform-bar {
		flex: 1;
		min-width: 2px;
		background: rgba(255, 255, 255, 0.3);
		border-radius: 1px;
		transition: background 0.1s ease;
	}

	.waveform-bar.played {
		background: #ff5500;
	}

	.waveform:hover .waveform-bar:not(.played) {
		background: rgba(255, 255, 255, 0.5);
	}

	.progress-line {
		position: absolute;
		top: 0;
		bottom: 0;
		width: 2px;
		background: #fff;
		box-shadow: 0 0 10px rgba(255, 255, 255, 0.5);
		pointer-events: none;
	}

	/* Time display */
	.time-display {
		display: flex;
		justify-content: space-between;
		font-size: clamp(1rem, 2vmin, 1.25rem);
		font-variant-numeric: tabular-nums;
	}

	.current-time {
		color: #ff5500;
		font-weight: 500;
	}

	.duration {
		color: rgba(255, 255, 255, 0.5);
	}

	/* Responsive adjustments */
	@media (max-width: 900px) {
		.player-content {
			flex-direction: column;
			text-align: center;
		}

		.track-header {
			flex-direction: column;
			align-items: center;
		}

		.soundcloud-badge {
			order: -1;
		}
	}
</style>
