<template>
	<l-popup :visible="show" position="bottom" @click-overlay="onClose">
		<view class="l-cascader" :style="[styles]">
			<text class="l-cascader__title">{{title}}</text>
			<view class="l-cascader__close-btn" @click="onCloseBtn" v-if="closeable">
				<view class="l-cascader__close-icon" >
					<l-icon name="tdesign:close" size="24px"></l-icon>
				</view>
			</view>
			<view class="l-cascader__content">
				<l-tabs 
				:list="steps" 
				:value="stepIndex" 
				:space-evenly="false" @change="onTabChange" size="large" 
				:color="color" 
				:visible="show"
				:activeColor="activeColor" 
				:lineColor="activeColor"
				:bgColor="bgColor">
				</l-tabs>
				<template v-if="subTitles.length > 0 ">
					<text v-show="subTitles.length > stepIndex" class="l-cascader__options-title">
						{{subTitles.length > stepIndex ? subTitles[stepIndex]: ''}}
					</text>
				</template>
			
				<view class="l-cascader__options-container" :style="[containerStyles]">
					<scroll-view  
						class="l-cascader__options"  
						v-for="(_options, index) in items"
						:key="index"
						:scroll-y="true">
						<view class="l-cascader__cell" v-for="(item, _index) in _options" :key="_index" @click="handleSelect(item[fieldKeys.value], index, true)">
							<text 
								class="l-cascader__cell-title" 
								:class="{'l-cascader__cell--disabled': item['disabled'] == true}" 
								:style="[color != null ?'color:' + color: '']">{{item[fieldKeys.label]}}</text>
							<view class="l-cascader__cell-icon"
								v-if="selectedValue.length > index && selectedValue[index] == item[fieldKeys.value]">
								<l-icon
									:size="iconSize"
									:color="activeColor"
									name="check">
								</l-icon>
							</view>
						</view>
					</scroll-view>
				</view>
			</view>
			<view class="l-cascader__footer" v-if="innerConfirmBtn">
				<l-button 
					@click="handleConfirm"
					:color="innerConfirmBtn.color || props.color"
					:shape="innerConfirmBtn.shape || 'round'"
					:type="innerConfirmBtn.type || 'primary'">
					{{
						 innerConfirmBtn.content
					}}
				</l-button>
			</view>
		</view>
	</l-popup>
</template>
<script lang="ts">
	// @ts-nocheck
	/**
	 * Cascader 级联选择器组件
	 * @description 支持多级联动的选择器，适用于地区选择、分类选择等场景
	 * @tutorial https://ext.dcloud.net.cn/plugin?name=lime-cascader
	 * 
	 * @property {boolean} visible 控制组件显示/隐藏（必填）
	 * @property {boolean} checkStrictly 父子节点选择是否关联（默认false联动选择）
	 * @property {object[]} options 数据源（必填，符合CascaderOption结构）
	 * @property {string} title 主标题文本
	 * @property {object} keys 字段别名配置（例：{label:'name',value:'id'}）
	 * @property {string} value 当前选中值（支持v-model）
	 * @property {string} defaultValue 默认选中值
	 * @property {string} placeholder 未选择时的提示文字
	 * @property {string[]} subTitles 各级副标题（如：['省份','城市','区县']）
	 * @property {boolean} closeable 是否显示关闭按钮
	 * @property {boolean} uniCloud 是否使用uniCloud数据源
	 * @property {boolean} swipeable 是否支持手势滑动切换层级
	 * @property {string} iconSize 图标尺寸（支持CSS单位）
	 * @property {string} activeColor 选中状态主题色
	 * @property {string} fontSize 文字字号（支持CSS单位）
	 * @property {string} color 文字颜色
	 * @property {string} bgColor 背景颜色
	 * @event {Function} change 选项变化时触发（返回当前选中路径）
	 * @event {Function} pick 选中时触发
	 * @event {Function} close 关闭时触发
	 * @event {Function} finish 点击完成时触发
	 */
	import { defineComponent, ref, computed, watch, reactive, onMounted ,onUnmounted, toRaw, watchEffect } from '@/uni_modules/lime-shared/vue';
	import cascaderProps from './props';
	import { CascaderOption, KeysType, ChildrenInfoType } from './type';
	import { getIndexesByValue, parseOptions, parseKeys, splitEveryTwo, getUniCloudArea, pickUniCloudArea, getIndexByValue, updateChildren } from './utils';
	
	
	export default defineComponent({
		name: 'l-cascader',
		emits: ['pick', 'change', 'close', 'finish', 'update:modelValue', 'input', 'update:visible'],
		props: cascaderProps,
		setup(props, {emit}) {
			const childrenInfo: ChildrenInfoType = {
				value: '',
				level: 0,
			};
			const fieldKeys = computed(():KeysType => parseKeys(props.keys, props.uniCloud))
			const cascaderValue = computed({
				set(value: string){
					// modelValue.value = value
					emit('update:modelValue', value)
					// #ifdef VUE2
					emit('input', value)
					// #endif
				},
				get():string {
					return props.value ?? props.modelValue
				}
			})
			const show = computed({
				set(value: boolean){
					emit('update:visible', value)
				},
				get():boolean {
					return props.visible
				}
			} as WritableComputedOptions<string>)
			
			const cache = new Map<string, Record<string,any>[]>();
			const stepIndex = ref(0)
			const selectedIndexes = reactive<number[]>([]);
			const selectedValue = reactive<string[]>([]);
			const uniCloudColumns = ref<UTSJSONObject[]>([]);
			const realColumns = computed(():UTSJSONObject[] =>{
				if(props.uniCloud) {
					return uniCloudColumns.value
				}
				return props.options
			})
			const items = reactive<CascaderOption[][]>([realColumns.value]);
			const steps = reactive<CascaderOption[]>([{ label: props.placeholder }])
			const innerConfirmBtn = computed(():UTSJSONObject|null=> {
				if(props.confirmBtn == null) return null
				if(typeof props.confirmBtn == 'string') {
					return {
						content: props.confirmBtn as string
					}
				}
				return props.confirmBtn as UTSJSONObject
			})
			const styles = computed(() =>{
				const style:Record<string, any> = {}
				if(props.bgColor) {
					style['background'] = props.bgColor!
				}
				return style
			})
			const containerStyles = computed(()=>{
				const style:Record<string, any> = {}
				style['width'] = (items.length + 1) + '00%';
				style['transform'] = `translateX(${-stepIndex.value}00vw)`;
				return style
			})
			
			const onTabChange = (index : number) => {
				stepIndex.value = index
			}
			// 监听选中索引变化
			const watchSelectedIndexes = () => {
				if (realColumns.value.length > 0) {
					items.splice(0, items.length, ...[parseOptions(realColumns.value, fieldKeys.value)]);
					let current = realColumns.value;
					for (let i = 0, size = selectedIndexes.length; i < size; i += 1) {
						const index = selectedIndexes[i];
						const next = current[index]
						const value = next?.[fieldKeys.value.value]
						const label = next?.[fieldKeys.value.label]
						const children = next?.[fieldKeys.value.children]
						if(value) {
							selectedValue.push(value);
						}
						if(label && steps[i]?.['label'] != label) {
							steps.push({label});
						}
						
						if(children) {
							current = children
							items.push(parseOptions(children, fieldKeys.value));
						}
					}
				}
				if (steps.length < items.length) {
					steps.push({ label: props.placeholder });
				}
				// stepIndex.value = items.length - 1;
				stepIndex.value = Math.max(Math.min(selectedIndexes.length - 1, items.length - 1), 0);
			}
			
			let timer = 0
			const initWithValue = () => {
				clearTimeout(timer)
				timer = setTimeout(()=>{
					if (cascaderValue.value) {
						steps.pop()
						const path = getIndexesByValue(realColumns.value, cascaderValue.value, fieldKeys.value)
						path?.forEach((e : number, index) => {
							// @ts-ignore
							if(selectedIndexes.length > index) {
								selectedIndexes[index] = e
							} else {
								// @ts-ignore
								selectedIndexes.push(e);
							}
						});
						watchSelectedIndexes();
					} else {
						selectedIndexes.length = 0;
						selectedValue.length = 0;
						steps.length = 1;
						steps[0] = { label: props.placeholder } 
						items.length = 1;
						items[0] = parseOptions(realColumns.value, fieldKeys.value) 
						stepIndex.value = 0;
					}
				},50)
			}
			// 设置级联选择器值
			const setCascaderValue = (value: string, selectedOptions: CascaderOption[]) => {
				cascaderValue.value = value;
				emit('change', value, [...selectedOptions])
			}
			const setSteps = (index: number, label: string) => {
				steps[index] = {label}
			}
			// 取消选择
			const cancelSelect = (value: string, level: number, index: number, item:CascaderOption) => {
				selectedIndexes[level] = index;
				selectedIndexes.length = level;
				selectedValue.length = level;
				// steps[level] = String(props.placeholder);
				// steps[level + 1] = props.placeholder;
				setSteps(level, props.placeholder)
				setSteps(level + 1, props.placeholder)
				steps.length = level + 1;
				
				const children = item[fieldKeys.value.children] as CascaderOption[]|null
				if (children != null && children.length > 0) {
					 items[level + 1] = item[fieldKeys.value.children];
				} else if (children != null && children.length == 0) {
				    childrenInfo.value = value;
				    childrenInfo.level = level;
				}
			}
			// 选择
			const chooseSelect = (value: string, level: number, index: number, item:CascaderOption) => {
				selectedIndexes[level] = index;
				selectedIndexes.length = level + 1;
				selectedValue[level] = String(value);
				selectedValue.length = level + 1;
				setSteps(level, `${item[fieldKeys.value.label] ?? props.placeholder}`)
				const children = item[fieldKeys.value.children] as CascaderOption[]|null
				if (children != null && children.length > 0) {
					// setItems(level + 1, children)
					items[level + 1] = children;
				    items.length = level + 2;
				    stepIndex.value += 1;
					setSteps(level + 1, props.placeholder)
				    steps.length = level + 2;
				} else if (children != null && children.length == 0) {
				    childrenInfo.value = value;
				    childrenInfo.level = level;
				} else {
					// 如果存在确确按钮，则需要点按钮关闭
					if(props.confirmBtn != null) return
					items.length = level + 1
					steps.length = level + 1;
					setCascaderValue(
						`${item[fieldKeys.value.value] ?? ''}`,
						items.map((item, index):CascaderOption => toRaw(item[selectedIndexes[index]]))
					)
				    emit('finish');
					show.value = false
				}
			}
			const handleSelect = (value: string, level: number, shouldEmit: boolean) => {
				const _value = value
				if(items.length <= level) return
				const index = items[level].findIndex((item: CascaderOption):boolean => item[fieldKeys.value.value] == _value);
				let item = selectedIndexes.slice(0, level).reduce((acc:CascaderOption[], item:number, index:number):CascaderOption[] => {
				    if (index == 0) {
				        return [acc[item]] as CascaderOption[];
				    }
					const children = acc[0][fieldKeys.value.children] as CascaderOption[]|null
				    return [children?.[item] ?? {}] as CascaderOption[];
				}, realColumns.value);
				
				let cursor :CascaderOption|null
				if (level == 0) {
				    cursor = item[index];
				} else {
					const children = item[0][fieldKeys.value.children] as CascaderOption[]|null
				    cursor = children?.[index];
				}
				const disabled = cursor?.['disabled'] == true
				if (disabled || cursor == null) {
				    return;
				}
				
				// 反选条件：1：有确认按钮并且没有下级  2：允许各自取消（checkStrictly）
				const hasChildren = Boolean(cursor[fieldKeys.value.children]);
				const isSelected = selectedValue.includes(_value);
				const canCancel = 
				    (props.confirmBtn && !hasChildren) || 
				    (props.checkStrictly);
				
				if (canCancel && isSelected) {
				// if (props.checkStrictly && selectedValue.includes(_value)) {
				    cancelSelect(_value, level, index, cursor);
				} else {
				    chooseSelect(_value, level, index, cursor);
				}
				if(shouldEmit){
					const code = cursor[fieldKeys.value.value] as string
					emit('pick', level, index, code, toRaw([...selectedIndexes]))
					if(!props.uniCloud) return
					pickUniCloudArea(uniCloudColumns.value, level, code, toRaw([...selectedIndexes]), cache)
					
				}
			}
			
			// 更新级联选择器值
			const updateCascaderValue = () => {
			    setCascaderValue(
			        selectedValue[selectedValue.length - 1],
			        items
			          .filter((item, index):boolean => selectedIndexes.length > index)
			          .map((item, index):CascaderOption => toRaw(item[selectedIndexes[index]]))
			      );
			};
			const onClose = () => {
				emit('close');
				show.value = false
			}
			const onCloseBtn = () => {
				if (props.checkStrictly) {
				    updateCascaderValue();
				    onClose()
				} else {
				    onClose()
				}
			}
			
			const handleConfirm = () => {
				// 1. 如果没有选中任何选项，直接关闭
				if (selectedValue.length === 0) {
				    show.value = false;
				    return;
				}
				// 2. 获取当前选中的完整路径（各级选项）
				const selectedOptions = items
				    .filter((_, index) => selectedIndexes.length > index)
				    .map((item, index) => toRaw(item[selectedIndexes[index]]));
				
				
				  // 3. 更新级联选择器的值（如果是联动模式）
				if (!props.checkStrictly) {
				    setCascaderValue(
				      selectedValue[selectedValue.length - 1],
				      selectedOptions
				    );
				}
				
				// 4. 触发 finish 事件，返回选中值和选项路径
				emit('finish');
				
				  // 5. 关闭弹窗
				show.value = false;
			}
			
			const optionsWatch = watch(():CascaderOption[] => realColumns.value, (_:CascaderOption[]) => {
				watchSelectedIndexes()
				if(selectedIndexes.length == 0) {
					initWithValue()
				}
				if (show.value) {
			        handleSelect(childrenInfo.value, childrenInfo.level, false);
			    }
			},{ deep: true});
			
			const placeholderWatch = watch(():string=> props.placeholder, (newValue: string, oldValue: string) => {
			    const index = steps.indexOf({label : oldValue} as CascaderOption);
			    if (index != -1) {
					setSteps(index, newValue)
			    }
			});
				
			onMounted(() => {
				if(props.uniCloud) {
					const update = async () => {
						const provinces = await getUniCloudArea({type: 0}, cache)
						uniCloudColumns.value = provinces
						if(cascaderValue.value != '' && /^\d{6}$/.test(cascaderValue.value)) {
							const [province, citie, countie] = splitEveryTwo(cascaderValue.value );
							const provinceCode = province.padEnd(6, '0')
							const provinceIndex = getIndexByValue(uniCloudColumns.value, provinceCode)
							const cities = await getUniCloudArea({type: 1, parent_code: provinceCode}, cache)
							const citieCode = (province + citie).padEnd(6, '0')
							const citiesIndex = getIndexByValue(uniCloudColumns.value, citieCode)
							const counties = await getUniCloudArea({type: 2, parent_code: citieCode}, cache)
							
							updateChildren(uniCloudColumns.value, cities, [provinceIndex])
							updateChildren(uniCloudColumns.value[provinceIndex]['children'] as UTSJSONObject[], counties, [citiesIndex])
						}
						initWithValue()
					}
					update()
					return
				}
				initWithValue()
			})
			
			watchEffect(()=>{
				const value = cascaderValue.value
				if(realColumns.value.length > 0 && selectedIndexes.length == 0) {
					initWithValue()
				}
			})
			// 监听 cascaderValue 变化，当值被清空时重置状态
			const cascaderValueWatch = watch(():string => cascaderValue.value, (newValue: string, oldValue: string) => {
				if (newValue == '' && oldValue != '') {
					initWithValue()
				}
			})
			
			onUnmounted(()=>{
				optionsWatch()
				placeholderWatch()
				cascaderValueWatch()
			})
			return {
				show,
				items,
				steps,
				stepIndex,
				selectedValue,
				styles,
				containerStyles,
				fieldKeys,
				handleSelect,
				onCloseBtn,
				onClose,
				onTabChange,
				handleConfirm,
				innerConfirmBtn
			}
		}
	})
</script>
<style lang="scss">
	@import './index';
</style>