<template>
    <u-popup :show="show" mode="bottom" round="30rpx" closeable @close="close">
        <view class="up-picker-area d-flex flex-cln">
            <!-- 标题 -->
            <view class="area-title">{{ title }}</view>
            <!-- 顶部链路 -->
            <view class="area-breadcrumb">
                <!-- 全国根：selectCodeMax 为空或 000000 时显示 -->
                <template v-if="isNationRoot">
                    <view class="crumb disabled" @click="onClickNationBreadcrumb">全国</view>
                    <view class="sep" v-if="selectedCodes.length">/</view>
                </template>
                <!-- 基础链路（selectCodeMax 的完整链路），仅最后一个可点击以切换到第一页（市级） -->
                <template v-for="(code, idx) in baseChain" :key="'base-' + code">
                    <view class="crumb" :class="idx === baseChain.length - 1 ? '' : 'disabled'" @click="idx === baseChain.length - 1 && onClickBaseBreadcrumb()">
                        {{ getNameByCode(code) }}
                    </view>
                    <view class="sep" v-if="idx < baseChain.length - 1 || selectedCodes.length">/</view>
                </template>

                <!-- 选中链路 -->
                <template v-for="(code, idx) in selectedCodes" :key="'sel-' + code">
                    <view class="crumb" :class="{ active: idx === currentSwiper }" @click="jumpToLevel(idx)">
                        {{ getNameByCode(code) }}
                    </view>
                    <view class="sep" v-if="idx < selectedCodes.length - 1">/</view>
                </template>
            </view>

            <!-- 滑动列区域 -->
            <view class="area-body">
                <swiper :current="currentSwiper" @change="onSwiperChange" class="area-swiper">
                    <template v-for="(parent, colIdx) in columnParents" :key="'col-' + parent">
                        <swiper-item>
                            <scroll-view
                              :id="`sv-${colIdx}`"
                              scroll-y
                              class="area-scroll"
                              :scroll-into-view="scrollIntoViewArr[colIdx]"
                            >
                                <!-- 顶部特殊项：全国（仅全国范围且首列显示） -->
                                <view v-if="isNationRoot && colIdx === 0" class="picker-item" :id="`area-item-0-000000`" @click="onPickNation">
                                    <view class="name" :class="{ selected: currentValue === '000000' }">全国</view>
                                    <up-icon v-if="currentValue === '000000'" name="checkbox-mark" color="#000" size="36rpx" />
                                </view>

                                <!-- 顶部特殊项：选择范围自身（非全国，首列显示），如 云南省 -->
                                <view v-else-if="!isNationRoot && colIdx === 0" class="picker-item" :id="`area-item-0-${canonical6(baseRoot)}`" @click="onPickBaseRoot">
                                    <view class="name" :class="{ selected: currentValue === baseRoot }">{{ getNameByCode(baseRoot) }}</view>
                                    <up-icon v-if="currentValue === baseRoot" name="checkbox-mark" color="#000" size="36rpx" />
                                </view>

                                <!-- 正常子级项 -->
                                <template v-for="item in childrenMap[parent] || []" :key="item.adcdCode">
                                    <view class="picker-item" :id="`area-item-${colIdx}-${canonical6(item.adcdCode)}`" @click="onPick(item, colIdx)">
                                        <view class="name" :class="{ selected: canonical6(selectedCodes[colIdx]) === canonical6(item.adcdCode) }">
                                            {{ item.adcdName }}
                                        </view>
                                        <up-icon v-if="canonical6(selectedCodes[colIdx]) === canonical6(item.adcdCode)" name="checkbox-mark" color="#000" size="36rpx" />
                                    </view>
                                </template>
                            </scroll-view>
                        </swiper-item>
                    </template>
                </swiper>
            </view>

            <!-- 底部操作 -->
            <view class="area-footer">
                <up-button class="btn" @click="close">取消</up-button>
                <up-button class="btn" color="#2A6D52" @click="confirmPick">确定</up-button>
            </view>
        </view>
    </u-popup>
    <up-toast ref="uToastRef" />
</template>

<script setup lang="ts">
import { ref, computed, watch, nextTick, getCurrentInstance } from 'vue';
import { useClientRequest } from '@/utils/request';

type MaybeStringNumber = string | number;
interface AreaItem {
    adcdCode: string;
    adcdName: string;
}

interface ConfirmPayload {
    value: string;
    name: string;
    fullNames: string;
    fullName: string;
}

interface UtPickerAreaProps {
    modelValue?: MaybeStringNumber;
    show?: boolean;
    title?: string;
    maxLevel?: number;
    selectCodeMax?: string;
    selectedCodes?: string[];
}

const props = withDefaults(defineProps<UtPickerAreaProps>(), {
    modelValue: '',
    show: false,
    title: '选择区域',
    maxLevel: 3,
    selectCodeMax: '',
    selectedCodes: () => [] as string[],
});

const emits = defineEmits<{
    (e: 'update:modelValue', value: string): void;
    (e: 'update:show', value: boolean): void;
    (e: 'confirm', payload: ConfirmPayload): void;
    (e: 'update:selectedCodes', value: string[]): void;
}>();

const uToastRef = ref<{ show: (opts: any) => void } | null>(null);

const close = () => emits('update:show', false);

// ---------------- 工具与状态 ----------------
// 统一为字符串，不再强制 6 位；全国仍使用 '000000'
const normalize6 = (code: MaybeStringNumber): string => String(code ?? '');
// 修复：全国返回空串用于层级与前缀判断，子级都视为全国的后代
const trim00Pairs = (code: MaybeStringNumber): string => {
    const s = normalize6(code);
    if (s === '000000') return '';
    if (s.length <= 6) {
        let t = s;
        while (t.endsWith('00')) t = t.slice(0, -2);
        return t;
    }
    // 6 位之后不做去 00 处理，直接保留扩展位（如 9/12 位）
    let first6 = s.slice(0, 6);
    while (first6.endsWith('00')) first6 = first6.slice(0, -2);
    return first6 + s.slice(6);
};
// 层级：0 全国；<=6 位时按 2 位一层；>6 位时 9/12 位按 3 位一层
const codeLevel = (code: MaybeStringNumber): number => {
    const t = trim00Pairs(code);
    if (!t) return 0;
    if (t.length <= 6) return Math.floor(t.length / 2);
    return 3 + Math.ceil((t.length - 6) / 3);
};
const isDescendant = (code: MaybeStringNumber, root: MaybeStringNumber): boolean => {
    const p = trim00Pairs(root);
    const c = trim00Pairs(code);
    return c.startsWith(p); // p=='' 时，任何 c 都成立（全国范围）
};

// 生成用于 nameMap 的最小 6 位标准键：
// - 全国固定 '000000'
// - <=6 位：去掉末尾 00 对后右补齐到 6 位
// - >6 位：取前 6 位，再按上述规则去 00 后补齐到 6 位
const nameKey = (code: MaybeStringNumber): string => {
    const s = String(code ?? '');
    if (!s || s === '000000') return '000000';
    const base6 = s.length <= 6 ? s : s.slice(0, 6);
    let t = base6;
    while (t.endsWith('00') && t.length >= 2) t = t.slice(0, -2);
    return t.padEnd(6, '0');
};
// 规范化用于比较和锚点：
// - 全国返回 '000000'
// - <=6 位：去尾部 00 对后右补齐至 6 位
// - >6 位：保持原始完整码
const canonical6 = (code: MaybeStringNumber): string => {
    const s = String(code ?? '');
    if (!s) return '';
    if (s === '000000') return '000000';
    if (s.length <= 6) {
        let t = s;
        while (t.endsWith('00')) t = t.slice(0, -2);
        return t.padEnd(6, '0');
    }
    return s;
};
const chainFromRoot = (code: MaybeStringNumber): string[] => {
    const s = normalize6(code);
    if (!s || s === '000000') return [];
    const list: string[] = [];
    // 省/市/区：统一输出为“最少6位”，少于补0，多余去掉末尾00（canonical6 内处理）
    for (let i = 2; i <= Math.min(6, s.length); i += 2) {
        list.push(canonical6(s.slice(0, i)));
    }
    // 扩展层级：9/12 位，保持真实长度；其 6 位基底已按 canonical6 规范化
    if (s.length > 6) {
        const base6 = canonical6(s).slice(0, 6);
        for (let j = 9; j <= s.length; j += 3) {
            list.push(base6 + s.slice(6, j));
        }
    }
    return list;
};

// 根（选择范围）与基础链路
const baseRoot = computed(() => {
    const c = normalize6(props.selectCodeMax || '');
    // 空值或显式全国，统一为 '000000'
    if (!c || c === '000000') return '000000';
    return trim00Pairs(c);
});
const baseChain = computed(() => {
    // 完整显示 selectCodeMax 的链路（不包含全国 '000000'）
    return chainFromRoot(baseRoot.value);
});
const isNationRoot = computed(() => baseRoot.value === '000000');

// 缓存：父code -> 子数组
const childrenMap = ref<Record<string, AreaItem[] | undefined>>({});
// 新增：进行中请求去重缓存（父code -> Promise）
const pendingMap = ref<Record<string, Promise<AreaItem[]> | undefined>>({});
// 名称缓存：code -> name
const nameMap = ref<Record<string, string>>({ '000000': '全国' });

// 选中链路（不包含 baseRoot），例如 baseRoot=省，选中市/区... 这里存 [市, 区, ...]
const selectedCodes = ref<string[]>(props?.selectedCodes || []);
const currentValue = ref<string>(''); // 当前选中最终 code

// 计算列：每列的父节点仅为“下一列的父节点”，避免最后一级再多出一列
const columnParents = computed<string[]>(() => {
    const parents: string[] = [];
    const baseL = codeLevel(baseRoot.value); // baseRoot 的绝对层级（全国=0，省=1，市=2...）
    const maxCols = Math.max(0, props.maxLevel - baseL); // 允许渲染的最大列数（例如全国根且 maxLevel=3 -> 3 列：省/市/区）
    if (maxCols <= 0) return parents;

    // 第 0 列父节点固定为 baseRoot（展示 baseRoot 的子级）
    parents.push(baseRoot.value);

    // 后续列的父节点是“上一列选中的 code”，最多渲染到 maxCols 数量；没有选中则不再渲染，避免空列
    for (let k = 1; k < maxCols; k++) {
        const parentCode = selectedCodes.value[k - 1];
        if (!parentCode) break; // 未选择上一列时，不渲染后续空列
        parents.push(parentCode);
    }
    return parents;
});

// 当前 swiper 索引（指向当前操作的列）
const currentSwiper = ref<number>(0);

// ---------------- 异步数据获取（带缓存 + 去重） ----------------
const getChildren = async (parentCode: string): Promise<AreaItem[]> => {
    const key = normalize6(parentCode);
    // 命中结果缓存
    if (childrenMap.value[key]) return childrenMap.value[key] as AreaItem[];
    // 命中请求去重缓存
    if (pendingMap.value[key]) return pendingMap.value[key] as Promise<AreaItem[]>;

    const p = (async () => {
        const res: any = await useClientRequest.get('/app/adcd/listChildrenByCode', {
            adcdCode: key,
            leval: 1,
            pageSize: 1000,
        });
        if (res?.code === 200) {
            const rows: AreaItem[] = (res.rows || []).map((x: any) => ({
                // 不再截断为 6 位，保留完整 code
                adcdCode: nameKey(x.adcdCode),
                adcdName: x.adcdName,
            }));
            childrenMap.value[key] = rows; // 写入结果缓存
            rows.forEach((r) => {
                // 名称缓存：精确键必存；仅当长度<=6时，才缓存到最少6位标准键，避免覆盖区县名称
                nameMap.value[r.adcdCode] = r.adcdName;
                nameMap.value[nameKey(r.adcdCode)] = r.adcdName;
            });
            delete pendingMap.value[key]; // 清除进行中缓存
            return rows;
        }
        childrenMap.value[key] = [];
        delete pendingMap.value[key];
        return [];
    })();

    pendingMap.value[key] = p;
    return p;
};

// 确保能显示 baseChain 的名称：逐级拉取上级的子级来命名
const ensureBaseNames = async () => {
    // 若 baseChain 为空无需处理
    if (!baseChain.value.length) return;
    // 第一层名称来自全国的子级
    await getChildren('000000');
    // 逐级往下，确保每一层的 name 显示
    for (let i = 0; i < baseChain.value.length; i++) {
        const parent = i === 0 ? '000000' : baseChain.value[i - 1];
        await getChildren(parent);
    }
};

// 获取名称
const getNameByCode = (code: string | number): string => {
    const c = normalize6(code);
    if (c === '000000') return '全国';
    // 先查精确键
    let val = nameMap.value[c];
    if (val) return val;
    // 对长度<=6的code再查最少6位标准键，避免用>6位的名称覆盖6位层级
    if (c.length <= 6) {
        const k6 = nameKey(c);
        val = nameMap.value[k6];
        if (val) return val;
    }
    // 即时回退：在已加载的 childrenMap 中查找匹配项并缓存
    for (const rows of Object.values(childrenMap.value)) {
        if (!rows) continue;
        const found = rows.find((r) => r.adcdCode === c);
        if (found) {
            nameMap.value[c] = found.adcdName;
            if (String(found.adcdCode).length <= 6) {
                nameMap.value[nameKey(found.adcdCode)] = found.adcdName;
            }
            return found.adcdName;
        }
    }
    return '';
};

// ---------------- 回显与列构造 ----------------
const toast = (msg: string) => {
    uToastRef.value?.show({ message: msg, type: 'error' });
};

// 将传入值回显为 selectedCodes（不含 baseRoot）
const applyModelValue = async (val: MaybeStringNumber): Promise<void> => {
    const v = normalize6(val);
    // 确保基础链路名称已就绪，避免回显时中文缺失
    await ensureBaseNames();
    if (!v) {
        selectedCodes.value = [];
        currentValue.value = '';
        currentSwiper.value = Math.min(columnParents.value.length - 1, 0);
        return;
    }
    if (v === '000000') {
        selectedCodes.value = [];
        currentValue.value = '000000';
        await ensureColumnsData();
        currentSwiper.value = 0;
        scrollToAllSelected();
        return;
    }
    // 新增：等于 baseRoot 自身时
    if (v === baseRoot.value) {
        selectedCodes.value = [];
        currentValue.value = baseRoot.value;
        await ensureColumnsData();
        currentSwiper.value = 0;
        scrollToAllSelected();
        return;
    }
    // 必须在选择范围内
    if (!isDescendant(v, baseRoot.value)) {
        toast('不在选择范围内');
        selectedCodes.value = [];
        currentValue.value = '';
        currentSwiper.value = 0;
        return;
    }
    const full = chainFromRoot(v);
    const base = baseChain.value;
    const baseL = codeLevel(baseRoot.value);
    const maxCols = Math.max(0, props.maxLevel - baseL);
    const picked = full.slice(base.length, base.length + maxCols);

    
    selectedCodes.value = picked;
    currentValue.value = picked.length ? picked[picked.length - 1] : baseRoot.value;
    await ensureColumnsData();
    currentSwiper.value = Math.max(0, Math.min(selectedCodes.value.length - 1, columnParents.value.length - 1));
    scrollToAllSelected();
};

// 确保每一列的 children 数据已拉取
const ensureColumnsData = async (): Promise<void> => {
    for (const parent of columnParents.value) {
        await getChildren(parent);
    }
};

// ---------------- 交互 ----------------
const onSwiperChange = (e: any) => {
    const idx = e?.detail?.current ?? 0;
    const maxIdx = Math.max(0, columnParents.value.length - 1);
    currentSwiper.value = Math.min(idx, maxIdx);
};

// 跳到链路的某一级进行重新选择
const jumpToLevel = (idx: number) => {
    // 只能跳选中链路，且 idx 为选中链路下标（不包含 baseChain）
    currentSwiper.value = idx;
};

// 选择某列的一项（到达最后一级时自动确认）
const onPick = async (item: AreaItem, colIdx: number) => {
    const code = canonical6(item.adcdCode);
    if (!isDescendant(code, baseRoot.value)) {
        return toast('不在选择范围内');
    }
    // 特判：误点到全国（正常不会走到这，因为全国走 onPickNation）
    if (code === '000000' && isNationRoot.value && colIdx === 0) {
        return onPickNation();
    }

    selectedCodes.value = [...selectedCodes.value.slice(0, colIdx), code];
    currentValue.value = code;

    // 是否达到允许的最后一列（相对 baseRoot 的列数）
    const baseL = codeLevel(baseRoot.value);
    const maxCols = Math.max(0, props.maxLevel - baseL);
    const reachedFinalColumn = (colIdx + 1) >= maxCols;
    if (reachedFinalColumn) {
        scrollToAllSelected();
        confirmPick();
        return;
    }

    await getChildren(code);
    const nextChildren = childrenMap.value[code] || [];
    currentSwiper.value = nextChildren.length ? colIdx + 1 : colIdx;
    scrollToAllSelected();
};

// 选全国
const onPickNation = (): void => {
    if (!isNationRoot.value) return;
    selectedCodes.value = [];
    currentValue.value = '000000';
    currentSwiper.value = 0;
    scrollToAllSelected();
};

// 选“选择范围自身”（非全国时的顶部项，如：云南省）
const onPickBaseRoot = async (): Promise<void> => {
    if (isNationRoot.value) return; // 全国时不走这里
    // 将当前值选为 baseRoot，自身级别
    selectedCodes.value = [];
    currentValue.value = baseRoot.value;
    currentSwiper.value = 0;

    // 若允许的列数仅 1（选择范围本身即最终列），直接确认
    const baseL = codeLevel(baseRoot.value);
    const maxCols = Math.max(0, props.maxLevel - baseL);
    if (maxCols <= 1) {
        scrollToAllSelected();
        confirmPick();
        return;
    }

    // 否则保持在第1列，滚动到该项
    await ensureColumnsData();
    scrollToAllSelected();
};

// 组装完整名称：包含基础链路与已选链路（全国仅返回“全国”）
const buildFullName = (): string => {
  if (currentValue.value === '000000') return '全国';
  const baseNames = baseChain.value.map((code) => getNameByCode(code));
  // 若当前值是 baseRoot 自身（选择范围自身），则不重复追加 selectedCodes
  const selNames = selectedCodes.value.map((code) => getNameByCode(code));
  return [...baseNames, ...selNames].filter(Boolean).join('');
};

const confirmPick = (): void => {
    if (!currentValue.value && isNationRoot.value) currentValue.value = '000000';

    const codeList = selectedCodes.value.slice();
    const nameList = codeList.map((i) => getNameByCode(i));
    const fullName = buildFullName();

    emits('update:modelValue', currentValue.value);
    emits('confirm', {
        value: currentValue.value,
        name: getNameByCode(currentValue.value),
        fullNames: nameList.join(''),
        fullName // 新增：完整地址名称
    });
    emits('update:selectedCodes', codeList);
    close();
};

// ---------------- 滚动（H5 兼容）----------------
// 选中项锚点
const scrollIntoViewArr = ref<string[]>([]);
const instance = getCurrentInstance();
const proxy = instance && instance.proxy;

const refreshScrollArrays = (): void => {
    const len = columnParents.value.length;
    // 初始化长度匹配列数
    if (scrollIntoViewArr.value.length !== len) {
        scrollIntoViewArr.value = Array(len).fill('');
    }
};

// 仅用锚点滚动
const updateScrollIntoView = (): void => {
    refreshScrollArrays();
    scrollIntoViewArr.value = scrollIntoViewArr.value.map(() => '');
    nextTick(() => {
        scrollIntoViewArr.value = columnParents.value.map((_, i) => {
            if (i === 0 && isNationRoot.value && currentValue.value === '000000') return 'area-item-0-000000';
            if (i === 0 && !isNationRoot.value && currentValue.value === baseRoot.value) return `area-item-0-${canonical6(baseRoot.value)}`;
            const code = selectedCodes.value[i];
            return code ? `area-item-${i}-${canonical6(code)}` : '';
        });
    });
};

const scrollToAllSelected = (): void => {
    updateScrollIntoView();
};

// ---------------- 监听与初始化 ----------------
const rebuildByInputs = async (): Promise<void> => {
    await ensureBaseNames();
    await ensureColumnsData();
    await applyModelValue(String(props.modelValue || ''));
};

watch(
    () => [props.selectCodeMax, props.maxLevel],
    async () => {
        // 变更范围或层级，重建链路与列
        selectedCodes.value = [];
        currentValue.value = '';
        currentSwiper.value = 0;
        await rebuildByInputs();
    },
    { immediate: true }
);

watch(
    () => props.modelValue,
    async (nv) => {
        await applyModelValue(String(nv || ''));
    }
);

// 每次列父集合变化时，刷新列数据并滚动
watch(
    () => columnParents.value.slice(),
    async () => {
        await ensureColumnsData();
        // 定位到当前列并滚动选中项
        currentSwiper.value = Math.max(0, Math.min(currentSwiper.value, columnParents.value.length - 1));
        scrollToAllSelected();
    }
);

// 点击顶部“全国”：切到省级并滚动到省级区域
const onClickNationBreadcrumb = async (): Promise<void> => {
    if (!isNationRoot.value) return;
    // 确保省级数据已加载
    await getChildren('000000');

    // 切到第 0 列（省级）
    currentSwiper.value = 0;

    // 保证滚动数组长度正确
    refreshScrollArrays();

    // 有已选省则对齐该省；否则滚到顶部
    nextTick(() => {
        const first = selectedCodes.value[0];
        scrollIntoViewArr.value.splice(0, 1, first ? `area-item-0-${canonical6(first)}` : '');
    });
};

// 点击顶部“选择范围自身”（如云南省）：切到第0列（市级）并滚动到已选市；未选则回到顶部
const onClickBaseBreadcrumb = async (): Promise<void> => {
    if (isNationRoot.value) return; // 全国时不走这里
    await getChildren(baseRoot.value); // 确保市级数据已加载
    currentSwiper.value = 0; // 切到第0列（展示 baseRoot 的子级：市）
    refreshScrollArrays();
    nextTick(() => {
        const selCity = selectedCodes.value[0]; // 若已有选中的市
        scrollIntoViewArr.value.splice(0, 1, selCity ? `area-item-0-${canonical6(selCity)}` : '');
    });
};
</script>

<style scoped lang="scss">
.up-picker-area {
    height: 70vh; /* 高度 70vh */
    display: flex;
    flex-direction: column;
    background: #fff;
}

.area-title {
    padding: 20rpx 24rpx;
    font-size: 32rpx;
    font-weight: 600;
    text-align: center;
    color: #000;
    border-bottom: 1px solid #f2f2f2;
}

.area-breadcrumb {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    padding: 16rpx 24rpx;
    gap: 8rpx;
    border-bottom: 1px solid #f2f2f2;

    .crumb {
        font-size: 28rpx;
        color: #333;
        padding: 8rpx 12rpx;
        border-radius: 8rpx;

        &.active {
            font-weight: 700;
            color: #000;
        }

        &.disabled {
            color: #999;
        }
    }

    .sep {
        color: #bbb;
        padding: 0 8rpx;
    }
}

.area-body {
    flex: 1;
    overflow: hidden;
}

.area-swiper {
    height: 100%;
}

.area-scroll {
    height: 100%;
    /* 移除 will-change 与像素滚动相关样式，仅保留稳定布局 */
}


.picker-item {
    display: flex;
    align-items: center;
    padding: 24rpx 32rpx;
    border-bottom: 1px solid #f5f5f5;

    .name {
        flex: 1;
        font-size: 30rpx;
        color: #333;

        &.selected {
            font-weight: 700;
            color: #000; /* 选中项黑色加粗 */
        }
    }
}

.area-footer {
    display: flex;
    gap: 20rpx;
    padding: 20rpx 24rpx;
    border-top: 1px solid #f2f2f2;
    background: #fff;

    .btn {
        flex: 1;
    }
}
</style>
