<script lang="ts">
	import { onDestroy } from 'svelte';
	import Composer from './Composer.svelte';
	import FallBack from './FallBack.svelte';
	import components from '$lib/core/componentLoader';
	import { createComposerStore, getComposerStore } from './composerStores';
	import { coreServices } from './coreServices';
	import { Machine, interpret } from 'xstate';

	interface IComposerLayout {
		areas: string;
		columns?: string;
		rows?: string;
		gap?: string;
		style?: string;
	}

	interface IComposer {
		layout?: IComposerLayout;
		id: string;
		me?: { id: string; do: any };
		slot?: string;
		component?: string;
		store?: Record<string, any>;
		children?: IComposer[];
		machine?: any;
	}

	export let composer: IComposer;
	let layoutStyle = '';

	let machineService;

	$: {
		layoutStyle = computeLayoutStyle(composer?.layout);

		initializeComposerState(composer);

		if (composer?.children) {
			composer.children.forEach((child) => {
				initializeComposerState(child);
			});
		}
		if (composer?.machine) {
			const machine = Machine({ ...composer.machine, id: composer.id });
			machineService = interpret(machine).onTransition((state) => {
				getComposerStore(composer.id).update((storeValue) => ({
					...storeValue,
					machine: { state: state.value }
				}));
			});
			machineService.start();
			composer.machineService = machineService;
		}

		if (composer?.children) {
			composer.children.forEach((child) => {
				if (child.machine) {
					const childMachine = Machine({ ...child.machine, id: child.id });
					machineService = interpret(childMachine).onTransition((state) => {
						getComposerStore(child.id).update((storeValue) => ({
							...storeValue,
							machine: { state: state.value }
						}));
					});
					machineService.start();
					child.machineService = machineService;
				}
			});
		}
	}

	function computeLayoutStyle(layout?: IComposerLayout): string {
		if (!layout) return '';
		return `
            grid-template-areas: ${layout.areas};
            ${layout.gap ? `gap: ${layout.gap};` : ''}
            ${layout.columns ? `grid-template-columns: ${layout.columns};` : ''}
            ${layout.rows ? `grid-template-rows: ${layout.rows};` : ''}
        `;
	}

	function initializeComposerState(child: IComposer) {
		if (!child) return; // Add this line

		if (child.id) {
			child.store = createComposerStore(child.id, child.store || {});
		}

		if (child.children) {
			child.children.forEach(initializeComposerState);
		}
	}

	let unsubscribers = [];

	onDestroy(() => {
		unsubscribers.forEach((unsub) => unsub());
	});

	async function getComponent(componentName: string) {
		if (components[componentName]) {
			const module = await components[componentName]();
			return module.default;
		}
		return FallBack;
	}

	async function loadComponentAndService(component: IComposer) {
		const componentName = component.component || 'FallBack';
		component.me = {
			id: component.id,
			do: {
				core: coreServices,
				machine: component.machineService || null
			}
		};
		return await getComponent(componentName);
	}
</script>

<div
	class={`grid w-full h-full overflow-hidden ${composer?.layout?.tailwindClasses || ''}`}
	style={layoutStyle}
>
	{#await loadComponentAndService(composer) then Component}
		<svelte:component
			this={Component}
			id={composer.id}
			store={getComposerStore(composer.id)}
			machine={composer.machine}
			me={composer.me}
		/>
	{/await}
	{#if composer?.children}
		{#each composer.children as child (child.id)}
			<div
				class="grid w-full h-full overflow-hidden ${composer?.layout?.tailwindClasses || ''}"
				style={`grid-area: ${child.slot}`}
			>
				{#await loadComponentAndService(child) then ChildComponent}
					<svelte:component
						this={ChildComponent}
						id={child.id}
						store={getComposerStore(child.id)}
						machine={child.machine}
						me={child.me}
					/>
					{#if child.children && child.children.length}
						<Composer composer={child} />
					{/if}
				{/await}
			</div>
		{/each}
	{/if}
</div>
