<template>
	<view class="l-picker" :style="[styles]" ref="pickerRef">
		<view class="l-picker__toolbar" v-if="cancelBtn != null || title != null || confirmBtn != null">
			<!-- #ifndef APP-HARMONY -->
			<text class="l-picker__cancel" :style="[cancelStyle??{}]" v-if="cancelBtn != null" @click="onCancel">{{cancelBtn}}</text>
			<text v-else class="l-picker__cancel"></text>
			<!-- #endif -->
			<!-- #ifdef APP-HARMONY -->
			<view class="l-picker__cancel" v-if="cancelBtn != null" @click="onCancel">
				<text class="l-picker__cancel-text" :style="[cancelStyle??{}]">{{cancelBtn}}</text>
			</view>
			<view v-else class="l-picker__cancel"></view>
			<!-- #endif -->
			
			<text class="l-picker__title" :style="[titleStyle??{}]">{{title}}</text>
			
			<!-- #ifndef APP-HARMONY -->
			<text class="l-picker__confirm" :style="[confirmStyle??{}]" v-if="confirmBtn != null" @click="onConfirm">{{confirmBtn}}</text>
			<text v-else class="l-picker__confirm"></text>
			<!-- #endif -->
			<!-- #ifdef APP-HARMONY -->
			<view class="l-picker__confirm" v-if="confirmBtn != null" @click="onConfirm">
				<text class="l-picker__confirm-text" :style="[confirmStyle??{}]">{{confirmBtn}}</text>
			</view>
			<view v-else class="l-picker__confirm"></view>
			<!-- #endif -->
		</view>
		<slot name="header"></slot>
		<view class="l-picker__main" :style="[groupHeight != null ? { height:  groupHeight}: {}]">
			<slot>
				<l-picker-item v-for="(options, i) in props.columns" :options="options" :key="i" :column="i" :value="pickerValue.length > i ? pickerValue[i]: null"></l-picker-item>
			</slot>
			<view class="l-picker__empty" v-if="isEmpty">
				<slot name="empty"></slot>
			</view>
		</view>
		<slot name="footer" />
		<view class="l-picker__loading" ref="loadingRef" v-if="loading" :style="[loadingMaskColor != null ? {background: loadingMaskColor}: {}]">
			<!-- #ifndef APP -->
			<l-loading :size="loadingSize" :color="loadingColor"></l-loading>
			<!-- #endif -->
		</view>
	</view>
</template>
<script lang="uts" setup>
	/**
	 * Picker 选择器组件
	 * @description 多列数据选择器，支持级联数据展示和自定义样式配置
	 * <br>插件类型：LPickerComponentPublicInstance 
	 * @tutorial https://ext.dcloud.net.cn/plugin?name=lime-picker
	 * 
	 * @property {string} cancelBtn 取消按钮文字
	 * @property {string | UTSJSONObject} cancelStyle 取消按钮样式
	 * @property {string} confirmBtn 确定按钮文字
	 * @property {string | UTSJSONObject} confirmStyle 确定按钮样式
	 * @property {string} title 标题文字
	 * @property {string | UTSJSONObject} titleStyle 标题样式
	 * @property {UTSJSONObject} keys 字段别名配置（例：{value: 'id', label: 'name'}）
	 * @property {PickerColumn[]} columns 选择器列数据（必填）
	 * @property {PickerValue[]} modelValue 选中值（支持v-model）
	 * @property {PickerValue[]} defaultValue 默认选中值
	 * @property {PickerValue[]} value 选中值（兼容旧版）
	 * @property {boolean} loading 是否显示加载状态
	 * @property {string} loadingColor 加载图标颜色
	 * @property {string} loadingMaskColor 加载遮罩颜色
	 * @property {string} loadingSize 加载图标尺寸
	 * @property {string} itemHeight 选项行高度
	 * @property {string} itemColor 选项文字颜色
	 * @property {string} itemFontSize 选项字体大小
	 * @property {string} itemActiveColor 选中项颜色
	 * @property {string} indicatorStyle 指示器样式
	 * @property {string} bgColor 背景颜色
	 * @property {string} groupHeight 选项组高度
	 * @property {string} radius 圆角半径
	 * @property {boolean} resetIndex 是否重置选中索引
	 * 
	 * @event {Function} confirm 点击确定时触发（事件参数：PickerConfirmEvent）
	 * @event {Function} cancel 点击取消时触发
	 * @event {Function} change 值变化时触发（事件参数：PickerPickEvent）
	 * @event {Function} column-change 列数据变化时触发（事件参数：PickerChangeInfo）
	 */
	import type { PickerProps, PickerColumn, PickerValue, PickerColumnItem, PickerConfirmEvent, PickerPickEvent } from './type';
	import { pushAt } from './utils';
	import { unitConvert } from '@/uni_modules/lime-shared/unitConvert'
	// #ifdef APP
	import { useLoading } from '@/uni_modules/lime-loading'
	// #endif
	const emit = defineEmits(['change', 'cancel', 'pick', 'confirm', 'update:modelValue', 'update:value']);
	const props = withDefaults(defineProps<PickerProps>(), {
		columns: [] as PickerColumn[],
		loading: false,
		resetIndex: false,
		loadingSize: '64rpx'
	})
	const pickerItemInstanceArray = reactive<LPickerItemComponentPublicInstance[]>([]);
	const modelValue = ref<PickerValue[]>(props.value ?? props.modelValue ?? props.defaultValue ?? [])
	const pickerValue = computed({
		set(value : PickerValue[]) {
			if (value.join('') == modelValue.value.join('')) return
			modelValue.value = value;
			emit('update:modelValue', value)
			emit('change', value)
		},
		get() : PickerValue[] {
			return props.value ?? props.modelValue ?? modelValue.value
		}
	} as WritableComputedOptions<PickerValue[]>)

	const isEmpty = computed(() : boolean => {
		return props.columns.length == 0 && pickerItemInstanceArray.every(child => child.options.length == 0)
	})
	const styles = computed(() : Map<string, any> => {
		const style = new Map<string, any>()
		if (props.bgColor != null) {
			style.set('background', props.bgColor!)
		}
		if (props.radius != null) {
			style.set('border-top-left-radius', props.radius!)
			style.set('border-top-right-radius', props.radius!)
		}
		return style
	})

	const curIndexArray = ref<number[]>([]);
	const curValueArray = ref([...pickerValue.value]);
	const curItemArray : PickerColumnItem[] = []
	const realColumns = computed(() : PickerColumn[] => {
		const pickerColumns = pickerItemInstanceArray.map((child) : PickerColumn => child.options)
		if (pickerColumns.length > 0) {
			return pickerColumns
		}
		return props.columns
	})

	const manageChildInList = (child : LPickerItemComponentPublicInstance, shouldAdd : boolean) => {
		const index = pickerItemInstanceArray.indexOf(child);
		if (shouldAdd) {
			if (index != -1) return
			pickerItemInstanceArray.push(child)
		} else {
			if (index == -1) return
			pickerItemInstanceArray.splice(index, 1);
		}
	}

	const updateItems = (item : PickerColumnItem, index : number, column : number) => {
		pushAt(curIndexArray.value, column, index)
		pushAt(curValueArray.value, column, item.value)
		pushAt(curItemArray, column, item)
	};
	
	const updatePickerItems = () => {
		const _indexs : number[] = []
		const _values : any[] = []
		pickerItemInstanceArray.forEach((child, column) => {
			if (child.options.length == 0) return
			const value = curValueArray.value.length > column ? curValueArray.value[column] : null;
			// #ifndef APP
			const index = value == null ? 0 : child._.exposed.getIndexByValue(value);
			child._.exposed.setIndex(index)
			// #endif
			// #ifdef APP
			// const index = value == null ? 0 : child.getIndexByValue(value)
			// child.setIndex(index)
			const index : number = (value == null ? 0 : child.$callMethod('getIndexByValue', value)) as number
			child.$callMethod('setIndex', index)
			// #endif
			const item = child.options[index]
			_indexs.push(index)
			_values.push(item.value)

			pushAt(curItemArray, column, item)
			// pushAt(curIndexArray.value, column, index)
			// pushAt(curValueArray.value, column, item.value)
			// // 不能改变单向数据流, 只有值不存在时候才处理
			// if(pickerValue.value.length == 0) {
			// 	pickerValue.value = [...curValueArray.value]
			// }
			// if(pickerValue.value.join('') == curValueArray.value.join('')) return
			// pickerValue.value = [...curValueArray.value]
		})
		// if (curIndexArray.value.join('') == _indexs.join('')) return
		if (curValueArray.value.join('') == _values.join('') && curIndexArray.value.join('') == _indexs.join('')) return
		curIndexArray.value = _indexs
		curValueArray.value = _values
		// if(pickerValue.value.length == 0) {
		pickerValue.value = [...curValueArray.value]
		// }
	}

	const onPick = (item : PickerColumnItem, index : number, column : number) => {
		if (curIndexArray.value[column] == index) return
		pushAt(curIndexArray.value, column, index)
		pushAt(curValueArray.value, column, item.value)
		pushAt(curItemArray, column, item)
		const obj : PickerPickEvent = {
			values: curValueArray.value,
			column,
			index
		}
		pickerValue.value = [...curValueArray.value]
		emit('pick', obj)
	};

	const onCancel = (e : UniPointerEvent) => {
		updatePickerItems()
		emit('cancel', e)
	}
	const onConfirm = () => {
		const values = [...curValueArray.value];
		const indexs = [...curIndexArray.value];
		const items = curItemArray.map((item) : PickerColumnItem => toRaw(item))
		if (pickerValue.value.join('') != values.join('')) {
			pickerValue.value = values;
		}
		const obj : PickerConfirmEvent = {
			values,
			indexs,
			items
		}
		emit('confirm', obj)
	}
	const stopPickerValue = watch(pickerValue, () => {
		if (pickerValue.value.join('') == curValueArray.value.join('')) return
		curValueArray.value = pickerValue.value.map((item : PickerValue) => item);
		updatePickerItems()
	})

	const stopColumns = watch(realColumns, () => {
		updatePickerItems()
		// nextTick(() => {
		// 	setTimeout(()=>{
		// 		updatePickerItems()
		// 	},2000)
			
		// })
	})
	
	onMounted(() => {
		nextTick(() => {
			if (pickerValue.value.join('') != curValueArray.value.join('') && pickerValue.value.length > 0) {
				curValueArray.value = [...pickerValue.value]
				updatePickerItems()
			}
		})
	})
	// #ifdef APP
	const loadingRef = ref<UniElement | null>(null);
	// const {play, clear, failed} = useLoading(loadingRef, 'circular', props.loadingColor?? '#3283ff', unitConvert(props.loadingSize))
	const loadingAni = useLoading(loadingRef)
	loadingAni.type = 'circular'
	loadingAni.color = props.loadingColor ?? '#3283ff'
	loadingAni.ratio = unitConvert(props.loadingSize)
	watchEffect(() => {
		if (props.loading) {
			loadingAni.play()
		} else {
			loadingAni.clear()
		}
	})
	// #endif

	onBeforeUnmount(() => {
		stopPickerValue()
		stopColumns()
	})
	
	
	defineExpose({
		confirm: onConfirm,
		getSelectedOptions: (): PickerConfirmEvent => {
			const values = [...curValueArray.value];
			const indexs = [...curIndexArray.value];
			const items = curItemArray.map((item) : PickerColumnItem => toRaw(item))
			if (pickerValue.value.join('') != values.join('')) {
				pickerValue.value = values;
			}
			const obj : PickerConfirmEvent = {
				values,
				indexs,
				items
			}
			return obj
		}
	})
	
	provide('limePicker', props)
	provide('limePickerOnPick', onPick)
	provide('limePickerUpdateItems', updateItems)
	provide('limePickerItems', pickerItemInstanceArray)
	provide('limePickerManageChildInList', manageChildInList)
</script>
<style lang="scss">
	@import './index.scss';
</style>