<script lang="ts">
	import { type WritableBox, boxWith } from "svelte-toolbelt";
	import type { ComboboxRootProps } from "../types.js";
	import { noop } from "../../../internal/noop.js";
	import FloatingLayer from "../../utilities/floating-layer/components/floating-layer.svelte";
	import { SelectRootState } from "../../select/select.svelte.js";
	import ListboxHiddenInput from "../../select/components/select-hidden-input.svelte";
	import { watch } from "runed";

	let {
		value = $bindable(),
		onValueChange = noop,
		name = "",
		disabled = false,
		type,
		open = $bindable(false),
		onOpenChange = noop,
		onOpenChangeComplete = noop,
		loop = false,
		scrollAlignment = "nearest",
		required = false,
		items = [],
		allowDeselect = true,
		inputValue = "",
		children,
	}: ComboboxRootProps = $props();

	if (value === undefined) {
		const defaultValue = type === "single" ? "" : [];
		value = defaultValue;
	}

	watch.pre(
		() => value,
		() => {
			if (value !== undefined) return;
			value = type === "single" ? "" : [];
		}
	);

	const rootState = SelectRootState.create({
		type,
		value: boxWith(
			() => value!,
			(v) => {
				value = v;
				// @ts-expect-error - we know
				onValueChange(v);
			}
		) as WritableBox<string> | WritableBox<string[]>,
		disabled: boxWith(() => disabled),
		required: boxWith(() => required),
		open: boxWith(
			() => open,
			(v) => {
				open = v;
				onOpenChange(v);
			}
		),
		loop: boxWith(() => loop),
		scrollAlignment: boxWith(() => scrollAlignment),
		name: boxWith(() => name),
		isCombobox: true,
		items: boxWith(() => items),
		allowDeselect: boxWith(() => allowDeselect),
		inputValue: boxWith(
			() => inputValue,
			(v) => (inputValue = v)
		),
		onOpenChangeComplete: boxWith(() => onOpenChangeComplete),
	});
</script>

<FloatingLayer>
	{@render children?.()}
</FloatingLayer>

{#if Array.isArray(rootState.opts.value.current)}
	{#if rootState.opts.value.current.length}
		{#each rootState.opts.value.current as item (item)}
			<ListboxHiddenInput value={item} />
		{/each}
	{/if}
{:else}
	<ListboxHiddenInput bind:value={rootState.opts.value.current as string} />
{/if}
