<script>
	import { getContext, createEventDispatcher } from 'svelte';
	import { useSvelteFlow, useNodesInitialized, useStore } from '@xyflow/svelte';
	import { SvelteFlow, Controls, Background, BackgroundVariant } from '@xyflow/svelte';

	const dispatch = createEventDispatcher();
	const i18n = getContext('i18n');

	import { onMount, tick } from 'svelte';

	import { writable } from 'svelte/store';
	import { models, showOverview, theme, user } from '$lib/stores';

	import '@xyflow/svelte/dist/style.css';

	import CustomNode from './Overview/Node.svelte';
	import Flow from './Overview/Flow.svelte';
	import XMark from '../icons/XMark.svelte';

	const { width, height } = useStore();

	const { fitView, getViewport } = useSvelteFlow();
	const nodesInitialized = useNodesInitialized();

	export let history;

	const nodes = writable([]);
	const edges = writable([]);

	const nodeTypes = {
		custom: CustomNode
	};

	$: if (history) {
		drawFlow();
	}

	const drawFlow = async () => {
		const nodeList = [];
		const edgeList = [];
		const levelOffset = 150; // Vertical spacing between layers
		const siblingOffset = 250; // Horizontal spacing between nodes at the same layer

		// Map to keep track of node positions at each level
		let positionMap = new Map();

		// Helper function to truncate labels
		function createLabel(content) {
			const maxLength = 100;
			return content.length > maxLength ? content.substr(0, maxLength) + '...' : content;
		}

		// Create nodes and map children to ensure alignment in width
		let layerWidths = {}; // Track widths of each layer

		Object.keys(history.messages).forEach((id) => {
			const message = history.messages[id];
			const level = message.parentId ? positionMap.get(message.parentId).level + 1 : 0;
			if (!layerWidths[level]) layerWidths[level] = 0;

			positionMap.set(id, {
				id: message.id,
				level,
				position: layerWidths[level]++
			});
		});

		// Adjust positions based on siblings count to centralize vertical spacing
		Object.keys(history.messages).forEach((id) => {
			const pos = positionMap.get(id);
			const xOffset = pos.position * siblingOffset;
			const y = pos.level * levelOffset;
			const x = xOffset;

			nodeList.push({
				id: pos.id,
				type: 'custom',
				data: {
					user: $user,
					message: history.messages[id],
					model: $models.find((model) => model.id === history.messages[id].model),
					label: createLabel(history.messages[id].content)
				},
				position: { x, y }
			});

			// Create edges
			const parentId = history.messages[id].parentId;
			if (parentId) {
				edgeList.push({
					id: parentId + '-' + pos.id,
					source: parentId,
					target: pos.id,
					type: 'smoothstep',
					animated: true
				});
			}
		});

		await edges.set([...edgeList]);
		await nodes.set([...nodeList]);
	};

	onMount(() => {
		nodesInitialized.subscribe(async (initialized) => {
			if (initialized) {
				await tick();
				const res = await fitView();
			}
		});

		width.subscribe((value) => {
			if (value) {
				fitView();
			}
		});

		height.subscribe((value) => {
			if (value) {
				fitView();
			}
		});
	});
</script>

<div class="w-full h-full relative">
	<div class=" absolute z-50 w-full flex justify-between dark:text-gray-100 px-5 py-4">
		<div class=" text-lg font-medium self-center font-primary">{$i18n.t('Chat Overview')}</div>
		<button
			class="self-center"
			on:click={() => {
				dispatch('close');
				showOverview.set(false);
			}}
		>
			<XMark className="size-4" />
		</button>
	</div>

	{#if $nodes.length > 0}
		<Flow {nodes} {nodeTypes} {edges} />
	{/if}
</div>
