<script lang="ts">
	import { bandwidthTest, getClientInfo, sendAnalyticsData } from '$lib';
	import { Chart, registerables } from 'chart.js';
	import type { Action } from 'svelte/action';
	import { onMount } from 'svelte';

	Chart.register(...registerables);

	const MaxTestDurationSec = 20;

	let currentBandwidth = $state(0);
	let accumulatedBandwidth = 0;
	let numBandwidthMeasurements = 0;
	let currentLatency = $state(0);
	let serverLocation = $state('-');
	let clientIp = $state('Detecting...');
	let clientLocation = $state('Detecting...');
	let progress = $state(0);
	let bandwidthMeasurements: number[] = $state([]);
	let timeMeasurements: string[] = $state([]);
	let testStatus = $state('Idle');

	// run ip info to get client IP and location
	onMount(async () => {
		let info = await getClientInfo();
		clientIp = info.clientIp;
		clientLocation = info.clientLocation;
	});

	// define callbacks
	let bandwidthCallback = (
		elapsedMs: number,
		loadedBytes: number,
		totalBytes: number,
		bw: number,
		done: boolean
	) => {
		if (testStatus == 'Stopped' || testStatus == 'Completed') {
			return true;
		}
		let mbps = (bw / 1000000) * 8; // convert Bps to Mbps
		// update the accumulated bandwidth
		accumulatedBandwidth += mbps;
		numBandwidthMeasurements++;
		// calculate the average bandwidth
		if (numBandwidthMeasurements > 0) {
			currentBandwidth = accumulatedBandwidth / numBandwidthMeasurements;
		} else {
			currentBandwidth = 0;
		}
		// update the bandwidth measurements array
		bandwidthMeasurements.push(mbps); // convert Bps to Mbps
		timeMeasurements.push((elapsedMs / 1000).toFixed(1)); // convert ms to seconds
		// only keep the last 20 measurements
		if (bandwidthMeasurements.length > 20) {
			bandwidthMeasurements.shift();
			timeMeasurements.shift();
		}
		// update the progress state. It is the max between the byte progress and the time progress
		let timeProgress = (elapsedMs / (MaxTestDurationSec * 1000)) * 100;
		let byteProgress = (loadedBytes / totalBytes) * 100;
		progress = Math.max(timeProgress, byteProgress);
		if (done) {
			testStatus = 'Completed';
			progress = 100;
		} else {
			testStatus = 'Running';
		}
		return false;
	};
	let latencyCallback = (latency: number) => {
		// update the latency state
		currentLatency = latency;
	};
	let serverLocationCallback = (location: string) => {
		serverLocation = location;
	};

	let testTimeoutHandler = 0;

	const startTest = () => {
		testStatus = 'Running';
		progress = 0;
		bandwidthMeasurements = [];
		timeMeasurements = [];
		currentBandwidth = 0;
		currentLatency = 0;
		bandwidthTest(bandwidthCallback, latencyCallback, serverLocationCallback);
		testTimeoutHandler = setTimeout(async () => {
			console.log('Test timed out after', MaxTestDurationSec, 'seconds');
			testStatus = 'Completed';
			progress = 100;
		}, MaxTestDurationSec * 1000);
	};
	const stopTest = () => {
		testStatus = 'Stopped';
		clearTimeout(testTimeoutHandler);
	};
	$effect(() => {
		(async () => {
			if (testStatus === 'Completed') {
				// send analytics event
				await sendAnalyticsData(currentBandwidth, currentLatency, serverLocation);
			}
		})();
	});
	//counter(callback);
	//bandwidthTest(bandwidthCallback, latencyCallback);

	let canvas: HTMLCanvasElement;

	const chart: Action<HTMLCanvasElement> = (node) => {
		let speedChart: Chart;

		function dispatch<T>(name: string, detail: T) {
			node.dispatchEvent(new CustomEvent(name, { detail }));
		}

		$effect(() => {
			const ctx = canvas.getContext('2d');
			if (speedChart) {
				speedChart.destroy();
			}
			speedChart = new Chart(ctx, {
				type: 'line',
				data: {
					labels: $state.snapshot(timeMeasurements),
					datasets: [
						{
							label: 'Download Speed (Mbps)',
							data: $state.snapshot(bandwidthMeasurements),
							borderColor: '#4f46e5',
							backgroundColor: 'rgba(79, 70, 229, 0.1)',
							tension: 0.4,
							fill: true
						}
					]
				},
				options: {
					animation: false,
					responsive: true,
					maintainAspectRatio: false,
					scales: {
						y: {
							beginAtZero: true,
							title: {
								display: true,
								text: 'Speed (Mbps)'
							}
						},
						x: {
							title: {
								display: true,
								text: 'Time (seconds)'
							}
						}
					},
					plugins: {
						legend: {
							position: 'top'
						},
						tooltip: {
							mode: 'index',
							intersect: false
						}
					}
				}
			});
		});
		dispatch('updated', bandwidthMeasurements);
		return () => {
			speedChart.destroy();
		};
	};
	const getStatusClass = () => {
		switch (testStatus) {
			case 'Idle':
				return 'bg-gray-300';
			case 'Running':
				return 'bg-blue-500';
			case 'Completed':
				return 'bg-green-500';
			case 'Error':
				return 'bg-red-500';
			case 'Stopped':
				return 'bg-red-500';
			default:
				return 'bg-gray-300';
		}
	};
</script>

<!-- Main Card -->
<div
	class="mb-8 overflow-hidden rounded-xl bg-white shadow-lg transition-all duration-300 hover:shadow-xl"
>
	<div class="p-6 md:p-8">
		<div class="mb-6 flex items-center justify-between">
			<h2 class="text-xl font-semibold text-gray-800">Connection Statistics</h2>
			<div id="connection-status" class="flex items-center">
				<span class="h-3 w-3 rounded-full {getStatusClass()} mr-2"></span>
				<span class="text-sm text-gray-500">{testStatus}</span>
			</div>
		</div>

		<!-- Speed Display -->
		<div class="mb-8 grid grid-cols-1 gap-6 md:grid-cols-2">
			<div class="rounded-lg bg-gray-50 p-4 text-center">
				<div class="mb-1 flex items-center justify-center text-gray-500">
					<i class="fas fa-download mr-2"></i>
					<span>Download Speed</span>
				</div>
				<div id="download-speed" class="text-2xl font-bold text-indigo-600">
					{currentBandwidth.toFixed(2)}
				</div>
				<div class="text-sm text-gray-400">Mbps</div>
			</div>
			<div class="rounded-lg bg-gray-50 p-4 text-center">
				<div class="mb-1 flex items-center justify-center text-gray-500">
					<i class="fas fa-clock mr-2"></i>
					<span>Latency</span>
				</div>
				<div id="latency" class="text-2xl font-bold text-amber-500">
					{currentLatency.toFixed(0)}
				</div>
				<div class="text-sm text-gray-400">ms</div>
			</div>
		</div>
		<!-- Progress Bar -->
		<div class="mb-6">
			<div class="mb-2 flex justify-between">
				<span class="text-sm font-medium text-gray-700">Test Progress</span>
				<span id="progress-percent" class="text-sm font-medium text-gray-700"
					>{progress.toFixed(0)}%</span
				>
			</div>
			<div class="h-2.5 w-full rounded-full bg-gray-200">
				<div
					id="progress-bar"
					class="progress-bar h-2.5 rounded-full {progress < 100 && progress > 0 ? 'wave' : ''}"
					style="width: {progress}%"
				></div>
			</div>
		</div>
		<!-- Test Controls -->
		<div class="flex flex-col justify-center gap-4 sm:flex-row">
			<button
				id="start-test"
				class="{testStatus === 'Running'
					? 'bg-indigo-100 hover:bg-indigo-100'
					: 'glow bg-indigo-600 hover:bg-indigo-700'} flex items-center justify-center rounded-lg px-6 py-3 font-medium text-white transition-all"
				onclick={startTest}
				disabled={testStatus === 'Running'}
			>
				<i class="fas fa-play mr-2"></i>
				Start Test
			</button>
			<button
				id="stop-test"
				class="flex items-center justify-center rounded-lg bg-gray-200 px-6 py-3 font-medium text-gray-800 transition-all hover:bg-gray-300"
				disabled={testStatus !== 'Running'}
				onclick={stopTest}
			>
				<i class="fas fa-stop mr-2"></i>
				Stop Test
			</button>
		</div>
	</div>
</div>
<!-- Connection Info Card -->
<div class="connection-info mb-8 overflow-hidden rounded-xl bg-white shadow-lg">
	<div class="p-6 md:p-8">
		<h2 class="mb-6 text-xl font-semibold text-gray-800">Connection Information</h2>
		<div class="grid grid-cols-1 gap-6 md:grid-cols-2">
			<div>
				<h3 class="mb-2 text-sm font-medium text-gray-500">CLIENT INFORMATION</h3>
				<div class="mb-3 flex items-center">
					<i class="fas fa-laptop mr-3 text-indigo-500"></i>
					<div>
						<div class="text-sm text-gray-500">IP Address</div>
						<div id="client-ip" class="text-lg font-medium text-gray-800">{clientIp}</div>
					</div>
				</div>
				<div class="flex items-center">
					<i class="fas fa-map-marker-alt mr-3 text-indigo-500"></i>
					<div>
						<div class="text-sm text-gray-500">Approximate Location</div>
						<div id="client-location" class="text-lg font-medium text-gray-800">
							{clientLocation}
						</div>
					</div>
				</div>
			</div>
			<div>
				<h3 class="mb-2 text-sm font-medium text-gray-500">SERVER INFORMATION</h3>
				<div class="mb-3 flex items-center">
					<i class="fas fa-server mr-3 text-emerald-500"></i>
					<div>
						<div class="text-sm text-gray-500">Server Location</div>
						<div id="server-location" class="text-lg font-medium text-gray-800">
							{serverLocation}
						</div>
					</div>
				</div>
				<div class="flex items-center">
					<i class="fas fa-network-wired mr-3 text-emerald-500"></i>
					<div>
						<div class="text-sm text-gray-500">Test Server</div>
						<div class="text-lg font-medium text-gray-800">huggingface.co</div>
					</div>
				</div>
			</div>
		</div>
	</div>
</div>
<!-- Results Graph -->
<div class="mb-8 overflow-hidden rounded-xl bg-white shadow-lg">
	<div class="p-6 md:p-8">
		<h2 class="mb-6 text-xl font-semibold text-gray-800">Speed Over Time</h2>
		<div class="relative h-64">
			<canvas id="speed-chart" bind:this={canvas} use:chart></canvas>
		</div>
	</div>
</div>
<!-- Information Section -->
<div class="overflow-hidden rounded-xl bg-white shadow-lg">
	<div class="p-6 md:p-8">
		<h2 class="mb-4 text-xl font-semibold text-gray-800">About This Test</h2>
		<div class="prose prose-indigo max-w-none text-gray-600">
			<p>
				This bandwidth test measures your connection speed to Hugging Face's servers by downloading
				a sample file. The test calculates:
			</p>
			<ul class="mt-2 list-disc space-y-1 pl-5">
				<li>
					<strong>Download speed:</strong> How fast data can be transferred from Hugging Face to your
					device
				</li>
				<li>
					<strong>Latency:</strong> The time it takes to establish connection to Hugging Face server
				</li>
			</ul>
			<p class="mt-4">
				For accurate results, close other bandwidth-intensive applications and ensure you're not on
				a VPN unless testing through it.
			</p>
		</div>
	</div>
</div>
