<script setup lang="ts">
import { Btn, Card, SelectInput, TextInput } from '@bagelink/vue'
import { ref, watch } from 'vue'

interface Props {
	modelValue?: Record<string, any> | any[]
	arrayMode?: boolean
	placeholder?: string
	basic?: boolean
}

const props = withDefaults(defineProps<Props>(), {
	modelValue: () => ({}),
	arrayMode: false,
	placeholder: 'Add a field...',
})

const emit = defineEmits<{
	'update:modelValue': [value: Record<string, any> | any[]]
}>()

interface Field {
	key: string
	value: any
	type: 'string' | 'number' | 'boolean' | 'null' | 'object' | 'array'
}

const fields = ref<Field[]>([])

// Initialize fields from modelValue
function initFields() {
	if (props.arrayMode) {
		const arr = Array.isArray(props.modelValue) ? props.modelValue : []
		fields.value = arr.map((item, index) => ({
			key: String(index),
			value: typeof item === 'object' && item !== null ? JSON.stringify(item) : String(item ?? ''),
			type: detectType(item),
		}))
	} else {
		const obj = props.modelValue as Record<string, any>
		fields.value = Object.entries(obj).map(([key, value]) => ({
			key,
			value: typeof value === 'object' && value !== null ? JSON.stringify(value) : String(value ?? ''),
			type: detectType(value),
		}))
	}
}

function detectType(value: any): Field['type'] {
	if (value === null || value === undefined) return 'null'
	if (Array.isArray(value)) return 'array'
	if (typeof value === 'object') return 'object'
	if (typeof value === 'boolean') return 'boolean'
	if (typeof value === 'number') return 'number'
	return 'string'
}

function addField() {
	fields.value.push({
		key: props.arrayMode ? String(fields.value.length) : '',
		value: '',
		type: 'string',
	})
}

function removeField(index: number) {
	fields.value.splice(index, 1)
	updateOutput()
}

function updateFieldValue(index: number, newValue: string) {
	fields.value[index].value = newValue
	updateOutput()
}

function updateFieldKey(index: number, newKey: string) {
	fields.value[index].key = newKey
	updateOutput()
}

function parseValue(field: Field): any {
	if (field.type === 'null') return null
	if (field.type === 'boolean') return field.value === 'true' || field.value === '1' || field.value === true
	if (field.type === 'number') return Number(field.value) || 0
	if (field.type === 'object' || field.type === 'array') {
		try {
			return JSON.parse(field.value)
		} catch {
			return field.type === 'array' ? [] : {}
		}
	}
	return String(field.value)
}

function updateOutput() {
	if (props.arrayMode) {
		const result = fields.value.map(field => parseValue(field))
		emit('update:modelValue', result)
	} else {
		const result: Record<string, any> = {}
		fields.value.forEach((field) => {
			if (field.key.trim()) {
				result[field.key] = parseValue(field)
			}
		})
		emit('update:modelValue', result)
	}
}

// Initialize on mount and watch for changes
watch(() => props.modelValue, () => {
	// Only reinit if structure significantly changed
	if (fields.value.length === 0) {
		initFields()
	}
}, { immediate: true })
</script>

<template>
	<div class="json-builder">
		<!-- Fields -->
		<Card thin class="gap-05 mb-05 bg-bg m_p-025">
			<div
				v-for="(field, index) in fields"
				:key="index"
				class="py-025 grid align-items-center"
				:class="basic ? 'grid-json-builder-row-basic' : 'grid-json-builder-row'"
			>
				<!-- Key (not shown in array mode) -->
				<TextInput
					v-if="!basic && !arrayMode"
					:model-value="field.key"
					placeholder="key"
					class="m-0 light-input"
					style="flex: 1;"
					@update:model-value="(val: string) => updateFieldKey(index, val)"
				/>
				<p v-if="basic" class="txt12 ellipsis-1">
					{{ field.key }}
				</p>
				<SelectInput
					v-if="!basic"
					v-model="field.type"
					placeholder="Type"
					:options="[{ label: 'String', value: 'string' }, { label: 'Number', value: 'number' }, { label: 'Boolean', value: 'boolean' }, { label: 'Null', value: 'null' }, { label: 'Object', value: 'object' }, { label: 'Array', value: 'array' }]"
					class="m-0 light-input"
				/>

				<p v-if="basic" class="txt12 ellipsis-1">
					{{ field.value }}
				</p>
				<template v-if="!basic">
					<!-- Value -->
					<TextInput
						v-if="field.type === 'string' || field.type === 'number'"
						:model-value="field.value"
						:placeholder="field.type === 'number' ? '0' : 'value'"
						:type="field.type === 'number' ? 'number' : 'text'"
						class="m-0 light-input"
						style="flex: 2;"
						@update:model-value="(val: string) => updateFieldValue(index, val)"
					/>
					<SelectInput
						v-else-if="field.type === 'boolean'"
						v-model="field.value"
						placeholder="True or False"
						:options="[{ label: 'True', value: true }, { label: 'False', value: false }]"
						class="m-0 light-input"
					/>
					<TextInput
						v-else-if="field.type === 'object' || field.type === 'array'"
						:model-value="field.value"
						:placeholder="field.type === 'array' ? '[]' : '{}'"
						class="m-0 light-input"
						style="flex: 2;"
						@update:model-value="(val: string) => updateFieldValue(index, val)"
					/>
					<span
						v-else
						class="txt-12 txt-gray p-025"
						style="flex: 2;"
					>
						null
					</span>
				</template>

				<!-- Remove button -->
				<Btn
					icon="close"
					size="xs"
					@click="removeField(index)"
				/>
			</div>

			<!-- Empty state -->
			<div
				v-if="fields.length === 0"
				class="txt-center txt-gray txt12"
			>
				אין שדות.
				<br>
				הוסיפו שדות באמצעות הכפתור למטה.
			</div>
		</Card>
		<Btn
			value="הוספת שדה"
			icon="add"
			color="purple"
			outline
			size="s"
			@click="addField"
		/>
	</div>
</template>

<style scoped>
.json-builder {
	/* Add any custom styles here */
	--input-height: 27px;
	--input-font-size: 12px;
}
.grid-json-builder-row{
	grid-template-columns: 2fr 1fr 2fr auto;
	grid-template-columns: 2fr 90px 2fr auto;

	gap: 0.5rem;
}
.grid-json-builder-row-basic{
	grid-template-columns: 1fr 1fr auto;
	gap: 0.5rem;
}
</style>
