<script lang="ts">
	import { Button } from '$lib/components/common'
	import { GripVertical, Loader2, Plus, X } from 'lucide-svelte'
	import { createEventDispatcher } from 'svelte'
	import type { InputType, StaticInput, StaticOptions } from '../../inputType'
	import SubTypeEditor from './SubTypeEditor.svelte'
	import { dndzone, SOURCES, TRIGGERS } from 'svelte-dnd-action'
	import { generateRandomString, pluralize } from '$lib/utils'
	import Toggle from '$lib/components/Toggle.svelte'
	import QuickAddColumn from './QuickAddColumn.svelte'

	export let componentInput: StaticInput<any[]> & { loading?: boolean }
	export let subFieldType: InputType | undefined = undefined
	export let selectOptions: StaticOptions['selectOptions'] | undefined = undefined
	export let id: string | undefined

	const dispatch = createEventDispatcher()
	const flipDurationMs = 200

	function addElementByType() {
		if (!Array.isArray(componentInput.value)) {
			componentInput.value = []
		}
		let value: any[] = componentInput.value
		if (subFieldType) {
			if (subFieldType === 'boolean') {
				value.push(false)
			} else if (subFieldType === 'number') {
				value.push(1)
				value = value
			} else if (subFieldType === 'object') {
				value.push({})
			} else if (subFieldType === 'labeledresource' || subFieldType === 'labeledselect') {
				value.push({ value: 'value', label: 'label' })
			} else if (subFieldType === 'tab-select') {
				value.push({ id: '', index: 0 })
			} else if (
				subFieldType === 'text' ||
				subFieldType === 'textarea' ||
				// TODO: Add support for these types
				subFieldType === 'date' ||
				subFieldType === 'time' ||
				subFieldType === 'datetime'
			) {
				value.push('')
			} else if (subFieldType === 'select' && selectOptions) {
				value.push(selectOptions[0])
			} else if (subFieldType === 'ag-grid') {
				value.push({ field: 'newField', editable: true, flex: 1 })
			} else if (subFieldType === 'table-column') {
				value.push({ field: 'newColumn', headerName: 'New column', type: 'text' })
			} else if (subFieldType === 'plotly') {
				value.push({
					value: {
						type: 'static',
						fieldType: 'array',
						subFieldType: 'number',
						value: [2, 4, 5, 6]
					},
					name: 'New dataset',
					aggregation_method: 'sum',
					type: 'bar',
					toolip: '',
					color: `#${Math.floor(Math.random() * 0xffffff)
						.toString(16)
						.padEnd(6, '0')}`
				})
			} else if (subFieldType === 'chartjs') {
				value.push({
					value: {
						type: 'static',
						fieldType: 'array',
						subFieldType: 'number',
						value: [2, 4, 5, 6]
					},
					name: 'New dataset'
				})
			} else if (subFieldType === 'ag-chart') {
				value.push({
					value: {
						type: 'oneOf',
						selected: 'bar',
						labels: {
							bar: 'Bar',
							scatter: 'Scatter',
							line: 'Line',
							area: 'Area',
							'range-bar': 'Range Bar',
							'range-area': 'Range Area'
						},
						configuration: {
							bar: {
								value: {
									type: 'static',
									fieldType: 'array',
									subFieldType: 'number',
									value: [25, 25, 50]
								}
							},
							scatter: {
								value: {
									type: 'static',
									fieldType: 'array',
									subFieldType: 'number',
									value: [25, 25, 50]
								}
							},
							line: {
								value: {
									type: 'static',
									fieldType: 'array',
									subFieldType: 'number',
									value: [25, 25, 50]
								}
							},
							area: {
								value: {
									type: 'static',
									fieldType: 'array',
									subFieldType: 'number',
									value: [25, 25, 50]
								}
							},
							'range-bar': {
								value: {
									type: 'static',
									fieldType: 'array',
									subFieldType: 'number-tuple',
									value: [
										[10, 15],
										[20, 25],
										[18, 27]
									]
								}
							},
							'range-area': {
								value: {
									type: 'static',
									fieldType: 'array',
									subFieldType: 'number-tuple',
									value: [
										[10, 15],
										[20, 25],
										[18, 27]
									]
								}
							}
						}
					},
					name: 'New dataset'
				})
			} else if (subFieldType === 'number-tuple') {
				value.push([0, 5])
			}
		} else {
			value.push('')
		}

		if (componentInput.value) {
			let value = componentInput.value[componentInput.value.length - 1]
			if (value != undefined) {
				items.push({
					value,
					id: generateRandomString()
				})
			}
		}
		componentInput = componentInput
	}

	function deleteElementByType(index: number) {
		if (componentInput.value) {
			componentInput.value.splice(index, 1)
			items.splice(index, 1) // Add this
			items = items
			componentInput.value = componentInput.value
			dispatch('deleteArrayItem', { index })
		}
	}

	let dragDisabled = true

	let dragging = false
	function handleConsider(e) {
		const {
			items: newItems,
			info: { source, trigger }
		} = e.detail
		items = newItems
		// Ensure dragging is stopped on drag finish via keyboard
		if (source === SOURCES.KEYBOARD && trigger === TRIGGERS.DRAG_STOPPED) {
			dragDisabled = true
		}
	}

	function handleFinalize(e) {
		const {
			items: newItems,
			info: { source }
		} = e.detail

		items = newItems

		// Ensure dragging is stopped on drag finish via pointer (mouse, touch)
		if (source === SOURCES.POINTER) {
			dragDisabled = true
		}

		const reorderedValues = items.map((item) => item.value)
		componentInput.value = reorderedValues
		dragging = false
	}

	function startDrag(e) {
		dragging = true
		// preventing default to prevent lag on touch devices (because of the browser checking for screen scrolling)
		e.preventDefault()
		dragDisabled = false
	}

	function handleKeyDown(e) {
		if ((e.key === 'Enter' || e.key === ' ') && dragDisabled) dragDisabled = false
	}

	let items = (Array.isArray(componentInput.value) ? componentInput.value : [])
		.filter((x) => x != undefined)
		.map((item, index) => {
			return { value: item, id: generateRandomString() }
		})

	$: items != undefined && handleItemsChange()

	function handleItemsChange() {
		componentInput.value = items.map((item) => item.value).filter((item) => item != undefined)
	}

	let raw: boolean = false
	// let mounted = false

	// $: if (componentInput.value && mounted) {
	// 	const newItems = (Array.isArray(componentInput.value) ? componentInput.value : [])
	// 		.filter((x) => x != undefined)
	// 		.map((item, index) => {
	// 			return { value: item, id: generateRandomString() }
	// 		})

	// 	if (
	// 		JSON.stringify(newItems.map((i) => i.value)) !== JSON.stringify(items.map((i) => i.value))
	// 	) {
	// 		items = newItems
	// 	}
	// }

	// onMount(() => {
	// 	mounted = true
	// })
</script>

<div class="flex gap-2 flex-col mt-2 w-full">
	{#if Array.isArray(items) && componentInput.value}
		<div class="flex flex-row items-center justify-between">
			<div class="text-xs text-tertiary font-semibold">{pluralize(items.length, 'item')}</div>

			{#if subFieldType === 'ag-grid' || subFieldType === 'table-column'}
				<Toggle
					options={{
						right: 'Raw'
					}}
					size="xs"
					bind:checked={raw}
				/>
			{/if}
		</div>
		<section
			use:dndzone={{
				items,
				dragDisabled,
				flipDurationMs,
				dropTargetStyle: {}
			}}
			on:consider={handleConsider}
			on:finalize={handleFinalize}
		>
			{#each items as item, index (item.id)}
				<div class="border-0 outline-none w-full">
					<!-- svelte-ignore a11y-no-noninteractive-tabindex -->

					<div class="flex flex-row gap-2 items-center relative my-1 w-full">
						<div class="grow min-w-0">
							<SubTypeEditor
								{id}
								subFieldType={raw ? 'object' : subFieldType}
								bind:componentInput
								bind:value={item.value}
								on:remove={() => deleteElementByType(index)}
								{dragging}
							/>
						</div>

						<div class="flex justify-between flex-col items-center">
							<!-- svelte-ignore a11y-no-static-element-interactions -->
							<div
								tabindex={dragDisabled ? 0 : -1}
								class="w-4 h-4 cursor-move"
								on:mousedown={startDrag}
								on:touchstart={startDrag}
								on:keydown={handleKeyDown}
							>
								<GripVertical size={16} />
							</div>
							{#if subFieldType !== 'db-explorer'}
								<button
									class="z-10 rounded-full p-1 duration-200 hover:bg-surface-hover"
									aria-label="Remove item"
									on:click|preventDefault|stopPropagation={() => deleteElementByType(index)}
								>
									<X size={14} />
								</button>
							{/if}
						</div>
					</div>
				</div>
			{/each}
		</section>
	{/if}
	{#if subFieldType === 'db-explorer'}
		{#if componentInput.loading}
			<div class="flex flex-row gap-2 w-full items-center text-xs">
				<Loader2 class="animate-spin" size={14} />
				Loading columns defintions...
			</div>
		{/if}
	{/if}
	{#if subFieldType !== 'db-explorer'}
		<Button size="xs" color="light" startIcon={{ icon: Plus }} on:click={() => addElementByType()}>
			Add
		</Button>
		{#if subFieldType === 'table-column' || subFieldType == 'ag-grid'}
			<QuickAddColumn
				{id}
				columns={componentInput.value?.map((item) => item.field)}
				on:add={({ detail }) => {
					if (!componentInput.value) componentInput.value = []
					if (subFieldType === 'table-column') {
						componentInput.value.push({ field: detail, headerName: detail, type: 'text' })
					} else if (subFieldType === 'ag-grid') {
						componentInput.value.push({ field: detail, headerName: detail, flex: 1 })
					}
					componentInput = componentInput

					if (componentInput.value) {
						let value = componentInput.value[componentInput.value.length - 1]
						if (value) {
							items.push({
								value,
								id: generateRandomString()
							})
						}
					}
				}}
			/>
		{/if}
	{/if}
</div>
