<script lang="ts">
	import { getContext, onDestroy } from 'svelte'
	import { initConfig, initOutput, selectId } from '../../editor/appUtils'
	import type { AppInput } from '../../inputType'
	import type {
		AppViewerContext,
		ComponentCustomCSS,
		ListContext,
		ListInputs,
		RichConfigurations
	} from '../../types'
	import RunnableWrapper from '../helpers/RunnableWrapper.svelte'
	import LightweightSchemaForm from '$lib/components/LightweightSchemaForm.svelte'
	import type { Schema } from '$lib/common'
	import { initCss } from '../../utils'
	import { twMerge } from 'tailwind-merge'
	import { components } from '../../editor/component'
	import ResolveConfig from '../helpers/ResolveConfig.svelte'
	import ResolveStyle from '../helpers/ResolveStyle.svelte'

	export let id: string
	export let componentInput: AppInput | undefined
	export let initializing: boolean | undefined = undefined
	export let render: boolean
	export let configuration: RichConfigurations
	export let customCss: ComponentCustomCSS<'schemaformcomponent'> | undefined = undefined

	const { worldStore, connectingInput, app, selectedComponent, componentControl } =
		getContext<AppViewerContext>('AppViewerContext')
	const iterContext = getContext<ListContext>('ListWrapperContext')
	const listInputs: ListInputs | undefined = getContext<ListInputs>('ListInputs')

	const outputs = initOutput($worldStore, id, {
		result: undefined,
		loading: false,
		valid: true,
		values: {}
	})

	let result: Schema | undefined = undefined
	let args: Record<string, unknown> = {}

	function handleArgsChange() {
		const newArgs: Record<string, unknown> = {}

		for (const key in args) {
			if (result?.properties[key]) {
				newArgs[key] = args[key]
			}
		}

		outputs.values.set(newArgs, true)
		if (iterContext && listInputs) {
			listInputs.set(id, newArgs)
		}
	}

	onDestroy(() => {
		listInputs?.remove(id)
	})

	let schemaForm: LightweightSchemaForm

	$componentControl[id] = {
		setValue(nvalue: any) {
			args = nvalue
		},
		invalidate(key: string, error: string) {
			schemaForm?.invalidate(key, error)
		},
		validateAll() {
			schemaForm?.validateAll()
		},
		validate(key: string) {
			schemaForm?.validate(key)
		}
	}

	$: args && handleArgsChange()

	$: outputs.valid.set(valid)

	let css = initCss($app.css?.schemaformcomponent, customCss)

	const resolvedConfig = initConfig(
		components['schemaformcomponent'].initialData.configuration,
		configuration
	)

	let valid = true
</script>

{#each Object.keys(components['schemaformcomponent'].initialData.configuration) as key (key)}
	<ResolveConfig
		{id}
		{key}
		bind:resolvedConfig={resolvedConfig[key]}
		configuration={configuration[key]}
	/>
{/each}

{#each Object.keys(css ?? {}) as key (key)}
	<ResolveStyle
		{id}
		{customCss}
		{key}
		bind:css={css[key]}
		componentStyle={$app.css?.schemaformcomponent}
	/>
{/each}

<RunnableWrapper {outputs} {render} autoRefresh {componentInput} {id} bind:initializing bind:result>
	{#if result && Object.keys(result?.properties ?? {}).length > 0}
		<div
			class={twMerge('p-2 overflow-auto h-full', css?.container?.class, 'wm-schema-form')}
			style={css?.container?.style}
			on:pointerdown|stopPropagation={(e) =>
				!$connectingInput.opened && selectId(e, id, selectedComponent, $app)}
		>
			<LightweightSchemaForm
				schema={result}
				bind:isValid={valid}
				bind:args
				bind:this={schemaForm}
				displayType={Boolean(resolvedConfig.displayType)}
				largeGap={Boolean(resolvedConfig.largeGap)}
				{css}
			/>
		</div>
	{:else}
		<p class="m-2 italic">Empty form (no property)</p>
	{/if}
</RunnableWrapper>
