<script lang="ts" setup generic="T extends {[key: string]: any}, P extends Path<T>">
import type {
	AttributeFn,
	AttributeValue,
	Attributes,
	BagelFieldOptions,
	BaseBagelField,
	BglFormSchemaT,
	Field,
	Path
} from '@bagelink/vue'
import type { MaybeRefOrGetter } from 'vue'
import { BagelForm, Btn, Loading, Icon, Card, useI18n } from '@bagelink/vue'
import { ref, computed, watch, toValue, onMounted } from 'vue'

export interface FieldArrayProps<T, P extends Path<T>> {
	el?: any
	id?: string
	label?: string
	placeholder?: string
	children?: Field<T>[]
	class?: AttributeValue | AttributeFn<T, P>
	attrs?: Attributes<T, P>
	required?: boolean
	disabled?: boolean
	helptext?: string
	options?: BagelFieldOptions<T, P>
	defaultValue?: T[]
	add?: boolean
	delete?: boolean
	collapsed?: boolean
	transform?: (value: T) => T
	schema?: MaybeRefOrGetter<BglFormSchemaT<T>>
	modelValue?: T[]
	type?: 'object' | 'number' | 'text' | 'array'
}

export interface PrimitiveArrFieldT extends BaseBagelField<{ value: string }, 'value'> {
	type: FieldArrayProps<{ value: string }, 'value'>['type']
}

const props = withDefaults(
	defineProps<FieldArrayProps<T, P>>(),
	{
		delete: true,
		add: true,
		el: 'div',
		type: 'object',
		collapsed: false,
	}
)

const emit = defineEmits(['update:modelValue'])

const { $t } = useI18n()

const BagelFormFA = BagelForm<T, P>

// State
const minimizedItems = ref<boolean[]>([])
const internalData = ref<any[]>(props.modelValue || [])
const schemaState = ref<'loading' | 'loaded' | 'error'>('loaded')
let lastEmittedValue = '' // Event handlers state

// Generate schema for primitive types
const primitiveSchema = computed<PrimitiveArrFieldT[]>(() => {
	if (props.type === 'text') {
		return [{ id: 'value', type: 'text', label: '', $el: 'text' }]
	} if (props.type === 'number') {
		return [{ id: 'value', type: 'number', label: '', $el: 'number' }]
	}
	return []
})

const resolvedSchemaData = computed(() => {
	// Handle 'array' type as equivalent to 'object' type
	const isObjectType = props.type === 'object' || props.type === 'array'

	if (!isObjectType) { return primitiveSchema.value as BglFormSchemaT<T> }

	// Use children prop first, then schema prop, then attrs.schema
	const attrsSchema = props.attrs?.schema !== undefined ? toValue(props.attrs.schema) : null
	const schemaToUse = props.children || toValue(props.schema) || attrsSchema

	// // If no schema but we have defaultValue, try to infer schema from first item
	// const noSchema = null === schemaToUse || schemaToUse === undefined
	// 	|| (Array.isArray(schemaToUse) && 0 === schemaToUse.length)
	// const hasDefaultValue = props.defaultValue !== undefined
	// 	&& null !== props.defaultValue
	// 	&& 0 < props.defaultValue.length

	// Don't infer schema from defaultValue - this causes unwanted restoration
	// Let the component work with empty arrays
	return schemaToUse as BglFormSchemaT<T>
})// Watch for external changes to modelValue - simple and straightforward
watch(() => props.modelValue, (newValue) => {
	// Simply sync with external changes, no automatic defaultValue restoration
	if (newValue && Array.isArray(newValue)) {
		internalData.value = [...newValue]
	} else {
		internalData.value = []
	}
}, { deep: true, immediate: false })

// Watch for changes to internalData length to sync minimizedItems
watch(() => internalData.value.length, (newLength) => {
	// Resize minimizedItems array to match internalData length
	if (minimizedItems.value.length !== newLength) {
		// If array grew, add new items with collapsed state
		if (minimizedItems.value.length < newLength) {
			const itemsToAdd = newLength - minimizedItems.value.length
			for (let i = 0; i < itemsToAdd; i++) {
				minimizedItems.value.push(props.collapsed || false)
			}
		} else {
			// If array shrank, remove excess items
			minimizedItems.value = minimizedItems.value.slice(0, newLength)
		}
	}
})

// Initialize with existing data or defaultValue on mount - only once!
onMounted(() => {
	// If no modelValue provided, use defaultValue as initial data (one time only)
	if (!props.modelValue || props.modelValue.length === 0) {
		if (props.defaultValue && props.defaultValue.length > 0) {
			internalData.value = [...props.defaultValue]
			emitValue() // This will set the initial value and then it becomes "regular" data
		}
	}

	// Initialize minimized state based on collapsed prop
	if (props.collapsed) {
		minimizedItems.value = Array.from({ length: internalData.value.length }, () => true)
	} else {
		minimizedItems.value = Array.from({ length: internalData.value.length }, () => false)
	}
})

// Function to load default values (explicit user action)
function loadDefaults() {
	if (props.defaultValue && props.defaultValue.length > 0) {
		internalData.value = [...props.defaultValue]
		emitValue()
	} else {
		// If no defaultValue in props, add a single empty item
		addItem()
	}
}

// Resolve schema
// async function resolveSchema() {
// 	// For primitive types, use the predefined schemaks
// 	if (props.type !== 'object') {
// 		resolvedSchemaData.value = primitiveSchema.value
// 		schemaState.value = 'loaded'
// 		return
// 	}

// 	// For object type without schema
// 	if (!props.schema) {
// 		resolvedSchemaData.value = []
// 		schemaState.value = 'loaded'
// 		return
// 	}

// 	// For object type with schema
// 	try {
// 		// schemaState.value = 'loading'
// 		const isPromise = (obj: any) => obj && typeof obj.then === 'function'

// 		let result: any
// 		if (typeof props.schema === 'function') {
// 			result = props.schema()
// 			result = isPromise(result) ? await result : result
// 		} else {
// 			result = isPromise(props.schema) ? await props.schema : props.schema
// 		}

// 		resolvedSchemaData.value = result
// 		schemaState.value = 'loaded'
// 	} catch (error) {
// 		console.error('Schema error:', error)
// 		schemaState.value = 'error'
// 		resolvedSchemaData.value = []
// 	}
// }

// // Initialize schema on mount
// onMounted(resolveSchema)

// Event handlers

function emitValue() {
	// Only emit if the value has actually changed to prevent recursive updates
	const currentValue = JSON.stringify(props.modelValue || [])
	const newValue = JSON.stringify(internalData.value || [])

	// Double-check against last emitted value to prevent loops
	if (currentValue !== newValue && lastEmittedValue !== newValue) {
		lastEmittedValue = newValue
		emit('update:modelValue', internalData.value)
		// Reset after a short delay to allow for new changes
		setTimeout(() => {
			lastEmittedValue = ''
		}, 50)
	}
}

function deleteItem(i: number) {
	internalData.value.splice(i, 1)
	minimizedItems.value.splice(i, 1)
	emitValue()
}

function addItem() {
	// Add appropriate default value based on type
	const defaultValues: { [key: string]: any } = {
		text: '',
		number: 0,
		object: {},
		array: {}
	}
	const defaultValue = defaultValues[props.type]
	internalData.value.push(defaultValue !== undefined ? defaultValue : {})

	// Add minimized state for new item - always open (false) when newly added
	minimizedItems.value.push(false)

	emitValue()
}

function toggleMinimized(index: number) {
	minimizedItems.value[index] = !minimizedItems.value[index]
}

function updateItem(index: number, value: any) {
	// Handle primitive types by extracting the value property
	if (props.type === 'text' || props.type === 'number') {
		internalData.value[index] = props.type === 'number' ? Number(value.value) : value.value
	} else {
		internalData.value[index] = value
	}
	emitValue()
}

// Computed properties for rendering
const isPrimitiveType = computed(() => props.type === 'text' || props.type === 'number')
const canRenderItems = computed(() => {
	const schemaData = resolvedSchemaData.value
	const hasValidSchema = (Array.isArray(schemaData) && schemaData.length > 0)
		|| (props.children && props.children.length > 0)
	const hasDefaultValue = props.defaultValue && props.defaultValue.length > 0

	// For primitive types or when we have schema or defaultValue
	const isObjectType = props.type === 'object' || props.type === 'array'
	const shouldRender = isPrimitiveType.value
		|| (isObjectType && (hasValidSchema === true || hasDefaultValue === true))
	return shouldRender
})
const showMinimizeButton = computed(() => {
	const schemaData = resolvedSchemaData.value
	const hasLongSchema = Array.isArray(schemaData) && schemaData.length > 2
	const hasRichText = Array.isArray(schemaData)
		&& schemaData.some((schema: any) => schema.$el === 'richtext')
	return hasLongSchema || hasRichText
})
</script>

<template>
	<div :class="props.class">
		<!-- Label -->
		<p v-if="label" class="label mb-05">
			{{ label }}
		</p>
		<div class="ps-025  mb-05">
			<!-- Loading/Error States -->
			<div v-if="schemaState !== 'loaded'" class="flex-center h-300px">
				<Loading v-if="schemaState === 'loading'" />
				<Icon v-else-if="schemaState === 'error'" icon="error" color="red" />
			</div>

			<!-- No Schema Available -->
			<Card v-else-if="!canRenderItems" class="py-1 border mb-05">
				<p class="opacity-7">
					No schema available
				</p>
			</Card>

			<!-- Items Rendering -->
			<template v-else>
				<!-- Empty Array Message -->
				<Card v-if="internalData.length === 0" class="py-1  border mb-05">
					<p class="opacity-7 txt-center txt14">
						No {{ label?.toLowerCase() || 'items' }} added yet
					</p>
					<!-- Load defaults button if defaultValue exists -->
					<Btn
						v-if="props.defaultValue && props.defaultValue.length > 0" thin color="primary"
						class="txt12 mb-05" @click="loadDefaults"
					>
						{{ $t('fieldArray.loadDefault', { label: label || 'Items' }) }}
					</Btn>
				</Card>

				<!-- Array Items -->
				<div
					v-for="(item, i) in internalData" :key="i" outline thin
					class="mb-05 itemBox transition radius-05 overflow-hidden txt12 border"
					style="--input-font-size: 12px" :class="{ minimized: minimizedItems[i] }"
				>
					<div>
						<!-- Minimized View -->
						<div class="flex pointer">
							<p class="minimizedText txt12 p-05 opacity-7 flex-grow-2" @click="toggleMinimized(i)">
								{{ label }} {{ i + 1 }}
							</p>
							<Btn
								v-if="showMinimizeButton" class="rotate-180 txt10 opacity-7 p-025" flat thin
								icon="keyboard_arrow_down" @click="toggleMinimized(i)"
							/>
						</div>

						<!-- Form View -->
						<BagelFormFA
							v-if="!minimizedItems[i]" :model-value="isPrimitiveType ? { value: item } : item"
							:schema="resolvedSchemaData" class="bginputbg p-05 grid gap-05"
							@update:model-value="val => updateItem(i, val)"
						/>
						<Btn
							v-if="props.delete" icon="delete" class="txt10 opacity-7" thin flat
							@click="deleteItem(i)"
						/>
					</div>
				</div>

				<!-- Add Button -->
				<Btn v-if="add" thin icon="add" color="gray" class="txt12  arrayAddButton" @click="addItem">
					<p>{{ label }}</p>
				</Btn>
			</template>
		</div>
	</div>
</template>

<style>
.minimized {
	height: 2.3rem;
	overflow: hidden;
	border-color: transparent !important;

}

.minimizedText {
	/* display: none; */
	padding-top: 1rem !important;
}

.minimized .minimizedText {
	display: block;
}

.minimized .rotate-180 {
	transform: rotate(0deg);
}

.itemBox {
	background: var(--btn-bg);
	--label-font-size: 0.6rem;
	--input-height: 30px;
	--input-font-size: 7px;
}

.bginputbg {
	background: var(--input-bg);
}

.pt-065 {
	padding-top: 0.65rem;
}

.itemBox .bagel-input input,
.itemBox .bagel-input textarea,
.itemBox .bagel-input select,
.itemBox .custom-select .input {
	background: var(--bgl-white) !important;
}

.itemBox .code-editor-wrap textarea {
	background: transparent !important;
}

.itemBox .bagel-input {
	margin-bottom: 0.15rem !important;
}

.itemBox .richtext-editor-content {
	--richtext-font-size: 12px !important;
	font-size: 12px !important;
}

.itemBox iframe.editableContent {
	--richtext-font-size: 12px !important;
}

.itemBox .bagel-input.richtext-input {
	--richtext-font-size: 12px !important;
}

/* More specific selectors to override richtext font size */
.itemBox .richtext-input iframe {
	font-size: 12px !important;
}

.itemBox .richtext-input .editableContent body {
	font-size: 12px !important;
}

.itemBox .richtext-input {
	font-size: 12px !important;
}
</style>
