<script lang="ts">
	import { statusStore } from '$lib/Types.svelte';
	import type { Node } from '../../flow/types';
	import type { PrevType } from './types';

	type FuncBase = (x: number) => number;

	let {
		node,
		canvasX,
		canvasY,
		count,
		from,
		hovering = $bindable()
	}: {
		node: Node;
		canvasX: FuncBase;
		canvasY: FuncBase;
		from: PrevType;
		count: number;
		hovering: Node | undefined;
	} = $props();

	let fromText = $derived(
		Object.keys(from.cur).reduce(
			(acc, i) =>
				`${acc}\n\t${i === 'null' ? 'Created' : statusStore.nodesR[i].name}: ${from.cur[i]}`,
			'From:'
		)
	);

	type Particle = {
		to: string;
		percentage: number;
		rand: number;
		randXStart: number;
		randXEnd: number;
		color: string;
	};

	let particlesState: Record<string, Particle[]> = $state({});
	let particleCount = 0;

	let MAX_PARTICLES = 400;

	function spwanParticle(key: string) {
		if (particleCount > MAX_PARTICLES) return;
		if (from.cur[key] <= (particlesState[key] ?? []).length) {
			return;
		}
		const toAdd: Particle = {
			percentage: 0,
			to: key,
			rand: Math.random(),
			randXStart: Math.floor(Math.random() * 100),
			randXEnd: Math.floor(Math.random() * 100),
			color: [
				'oklch(68.5% 0.169 237.323)',
				'oklch(62.3% 0.214 259.815)',
				'oklch(62.7% 0.265 303.9)'
			][Math.floor(Math.random() * 3)]
		};
		if (particlesState[key]) {
			particlesState[key].push(toAdd);
		} else {
			particlesState[key] = [toAdd];
		}
		particleCount++;
	}

	const MAX_ROUNDS = 200;
	let timeout: number | undefined = undefined;

	function t(k: number) {
		if (k > MAX_ROUNDS || !from) {
			timeout = undefined;
			return;
		}
		for (const key of Object.keys(from.cur)) {
			spwanParticle(key);
		}
		timeout = setTimeout(() => t(k + 1), Math.random() * 1000) as unknown as number;
	}

	$effect(() => {
		if (timeout !== undefined) clearTimeout(timeout);
		// this is used for making this effect block dependednt on form
		// eslint-disable-next-line
		const _ = from;
		particlesState = {};
		timeout = setTimeout(() => t(0), 10) as unknown as number;
		return () => {
			if (timeout !== undefined) clearTimeout(timeout);
		};
	});

	let showColor = $derived(hovering === undefined || hovering === node);
</script>

<div
	class="shadow-sm shadow-violet-500 border rounded-full min-w-[50px] min-h-[50px] grid place-items-center bg-white z-40 absolute"
	style="left: {canvasX(node.x + node.width / 2)}px; top: {canvasY(node.y - node.height / 2)}px;"
	title={`${node?.name ?? ''}: ${count}\n${fromText}`}
	onmouseenter={() => {
		hovering = node;
	}}
	onmouseleave={() => {
		hovering = undefined;
	}}
	role="figure"
>
	<span class={`bi bi-${node?.icon ?? ''}`}> </span>
</div>

{#each Object.keys(particlesState) as key}
	{@const size = 20}
	{@const to = statusStore.nodesR[key]}
	{@const f_x = node.x + node.width / 2}
	{@const f_y = node.y - node.height / 2}
	{@const t_x = to.x + to.width / 2}
	{@const t_y = to.y - to.height / 2}
	{@const diff = Math.sqrt((f_x - t_x) ** 2 + (f_y - t_y) ** 2)}
	{@const theta = Math.atan2(f_x - t_x, f_y - t_y)}
	<div
		class="absolute z-30"
		style="height: {(25 / 2) *
			diff}px; width: {size}px; transform-origin: top center; transform: translate({canvasX(f_x) +
			25 -
			size / 2}px, {canvasY(f_y) + 25 + size / 8}px) rotate({theta}rad);"
	>
		{#each particlesState[key] as particle}
			<div
				class="animateMove absolute w-2 h-2 text-black rounded-full shadow-lg"
				style="--start-x: {particle.randXStart}%; --end-x: {particle.randXEnd}%; background: {!showColor
					? '#18181818'
					: particle.color};"
			></div>
		{/each}
	</div>
{/each}

{#each Object.keys(from.cur) as link}
	{@const size = 20}
	{@const to = statusStore.nodesR[link]}
	{@const f_x = node.x + node.width / 2}
	{@const f_y = node.y - node.height / 2}
	{@const t_x = to.x + to.width / 2}
	{@const t_y = to.y - to.height / 2}
	{@const diff = Math.sqrt((f_x - t_x) ** 2 + (f_y - t_y) ** 2)}
	{@const theta = Math.atan2(f_x - t_x, f_y - t_y)}
	<div
		class="absolute {showColor
			? 'bg-gradient-to-t from-blue-400/70 to-blue-200/70'
			: 'bg-gray-800/20'} z-10"
		style="height: {(25 / 2) * diff}px;
		width: {size}px; transform-origin: top center; transform: translate({canvasX(f_x) +
			25 -
			size / 2}px, {canvasY(f_y) + 25 + size / 8}px) rotate({theta}rad);"
	></div>
{/each}

{#if from.prev}
	{#each Object.keys(from.prev.cur) as link}
		{@const size = 10}
		{@const to = statusStore.nodesR[link]}
		{@const f_x = node.x + node.width / 2}
		{@const f_y = node.y - node.height / 2}
		{@const t_x = to.x + to.width / 2}
		{@const t_y = to.y - to.height / 2}
		{@const diff = Math.sqrt((f_x - t_x) ** 2 + (f_y - t_y) ** 2)}
		{@const theta = Math.atan2(f_x - t_x, f_y - t_y)}
		<div
			class="absolute {showColor
				? 'bg-gradient-to-t from-violet-400/70 to-violet-200/70'
				: 'bg-gray-600/20'}"
			style="height: {(25 / 2) *
				diff}px; width: {size}px; transform-origin: top center; transform: translate({canvasX(f_x) +
				25 -
				size / 2}px, {canvasY(f_y) + 25 - size / 4}px) rotate({theta}rad);"
		></div>
	{/each}
{/if}

{#if from.prev && from.prev.prev}
	{#each Object.keys(from.prev.prev.cur) as link}
		{@const size = 5}
		{@const to = statusStore.nodesR[link]}
		{@const f_x = node.x + node.width / 2}
		{@const f_y = node.y - node.height / 2}
		{@const t_x = to.x + to.width / 2}
		{@const t_y = to.y - to.height / 2}
		{@const diff = Math.sqrt((f_x - t_x) ** 2 + (f_y - t_y) ** 2)}
		{@const theta = Math.atan2(f_x - t_x, f_y - t_y)}
		<div
			class="absolute {showColor
				? 'bg-gradient-to-t from-violet-400/50 to-violet-200/50'
				: 'bg-gray-400/20'}"
			style="height: {(25 / 2) *
				diff}px; width: {size}px; transform-origin: top center; transform: translate({canvasX(f_x) +
				25 -
				size / 2}px, {canvasY(f_y) + 25 - size / 4}px) rotate({theta}rad); z-index: 2"
		></div>
	{/each}
{/if}

{#if from.prev && from.prev.prev && from.prev.prev.prev}
	{#each Object.keys(from.prev.prev.prev.cur) as link}
		{@const size = 2.5}
		{@const to = statusStore.nodesR[link]}
		{@const f_x = node.x + node.width / 2}
		{@const f_y = node.y - node.height / 2}
		{@const t_x = to.x + to.width / 2}
		{@const t_y = to.y - to.height / 2}
		{@const diff = Math.sqrt((f_x - t_x) ** 2 + (f_y - t_y) ** 2)}
		{@const theta = Math.atan2(f_x - t_x, f_y - t_y)}
		<div
			class="absolute {showColor
				? 'bg-gradient-to-t from-violet-200/50 to-violet-100/50'
				: 'bg-gray-400/20'}"
			style="height: {(25 / 2) *
				diff}px; width: {size}px; transform-origin: top center; transform: translate({canvasX(f_x) +
				25 -
				size / 2}px, {canvasY(f_y) + 25 - size / 4}px) rotate({theta}rad);"
		></div>
	{/each}
{/if}

<style>
	.animateMove {
		animation: animateMoves 5s ease-in infinite;
	}
	@keyframes animateMoves {
		0% {
			top: 100%;
			left: var(--start-x);
		}
		100% {
			top: 0%;
			left: var(--end-x);
		}
	}
</style>
