<template>
    <ul class="m-drag" :style="{ height: (itemHeight * state.newList.length) + 'px' }">
        <li v-for="(item, index) in state.newList" :key="index" class="m-drag-item"
            :class="{ active: state.currentIndex === index }" :style="{
                top: state.itemYList[index].top + 'px'
            }">
            <slot :item="item" />
            <!-- css实现拖拽图标 -->
            
            <div class="icon" @touchstart.stop="touchStart($event, index)" @touchmove.stop="touchMove" @touchend.stop="touchEnd">
                <image src="/static/icons/move.png" class="icon50 margin-left-30" />
                <!-- <i class="lines" /> -->
            </div>
            <div class="icon" >
                <image src="/static/icons/delete.png" class="icon50 margin-left-30" />
            </div>
        </li>
    </ul>
</template>

<script setup>
import { reactive, watch } from 'vue'
const emits = defineEmits(['change'])
const props = defineProps({
    // 每一项item高度，必须
    itemHeight: {
        type: Number,
        required: true
    },
    // 数据列表，必须
    list: {
        type: Array,
        required: true
    },
    // 是否只读
    readonly: {
        type: Boolean,
        default: false
    }
})

const state = reactive({
    // 数据
    newList: [],
    // 初始数据
    initialList: [],
    // 记录所有item的初始坐标
    initialItemYList: [],
    // 坐标数据
    itemYList: [],
    // 记录当前手指的垂直方向的坐标
    touchY: 0,
    // 记录当前操作的item数据
    currentItemY: {},
    // 当前操作的item的下标
    currentIndex: -1
})

watch(
    () => props.list,
    (val) => {
        if (!val?.length) return
        // 获取数据列表
        state.newList = [...val]
        // 记录初始数据
        state.initialList = [...val]
        // 获取所有item的初始坐标
        state.initialItemYList = getItemsY()
        // 初始化坐标
        state.itemYList = getItemsY()
    },
    {
        immediate: true
    }
)

/** @初始化各个item的坐标 **/
function getItemsY() {
    return props.list.map((item, i) => {
        return {
            top: (i * props.itemHeight)
        }
    })
}

let isDragging = false

function touchStart(event, index) {
    if (props.readonly) return

    // ⚠️ 标记为正在拖拽
    state.isDragging = true

    h5BodyScroll(false)
    const [{ pageY }] = event.touches

    state.currentIndex = index
    state.touchY = pageY
    state.currentItemY = state.itemYList[index]
}



function touchMove(event) {
    if (props.readonly || !state.isDragging) return

    const [{ pageY }] = event.touches
    const current = state.itemYList[state.currentIndex]
    const prep = state.itemYList[state.currentIndex - 1]
    const next = state.itemYList[state.currentIndex + 1]

    // 计算移动距离
    const diff = Math.abs(pageY - state.touchY)

    // 只有移动超过一定距离才认为是拖拽（避免误触）
    if (diff > 5) { // 5px阈值
        state.itemYList[state.currentIndex] = {
            top: current.top + (pageY - state.touchY)
        }
        state.touchY = pageY

        // 交换位置逻辑
        if (next && current.top > next.top - props.itemHeight / 2) {
            changePosition(state.currentIndex + 1)
        } else if (prep && current.top < prep.top + props.itemHeight / 2) {
            changePosition(state.currentIndex - 1)
        }
    }
}




/** @手指松开 */
function touchEnd() {
    if (props.readonly) return

    // 触发change
    change()

    // 归位
    state.itemYList[state.currentIndex] = state.initialItemYList[state.currentIndex]
    state.initialList = [...state.newList]
    state.currentIndex = -1
    state.isDragging = false // ← 重置拖拽状态

    // 恢复滚动
    h5BodyScroll(true)
}



/** @交换位置 **/
// index 需要与第几个下标交换位置
function changePosition(index) {
    // 记录当前拖拽的item数据
    const tempItem = state.newList[state.currentIndex]
    // 设置原来位置的item
    state.newList[state.currentIndex] = state.newList[index]
    // 将临时存放的数据设置好
    state.newList[index] = tempItem

    // 调整位置item
    state.itemYList[index] = state.itemYList[state.currentIndex]
    state.itemYList[state.currentIndex] = state.currentItemY

    // 改变当前操作的的下标
    state.currentIndex = index

    // 记录新位置的数据
    state.currentItemY = state.initialItemYList[state.currentIndex]
}

/** @回传数据 **/
function change() {
    // 如果顺序未发生改变，则不触发change事件
    if (JSON.stringify(state.newList) == JSON.stringify(state.initialList)) return
    // 传给父组件新数据
    emits('change', state.newList, state.newList[state.currentIndex])
}

// h5 ios回弹
function h5BodyScroll(flag) {
    // #ifdef H5
    document.body.style.overflow = flag ? 'initial' : 'hidden'
    document.body.style.webkitOverflowScrolling = flag ? 'touch' : 'auto'
    // #endif
}

</script>

<style scoped lang="scss">
.m-drag {
    position: relative;
}

.m-drag-item {
    position: absolute;
    left: 0;
    right: 0;
    transition: all ease 0.25s;
    display: flex;
    align-items: center;

    // ⚠️ 防止长按选中文字或图片
    user-select: none;
    -webkit-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;

    .content-wrapper {
        flex: 1;
    }

    .icon {
        position: relative;
        top: -40rpx;
        // padding: 30rpx;
        .lines {
            background: #e0e0e0;
            width: 20px;
            height: 2px;
            border-radius: 100rpx;
            margin-left: auto;
            position: relative;
            display: block;
            transition: all ease 0.25s;
            top: -40rpx;

            &::before,
            &::after {
                position: absolute;
                width: inherit;
                height: inherit;
                border-radius: inherit;
                background: #e0e0e0;
                transition: inherit;
                content: '';
                display: block;
            }

            &::before {
                top: -14rpx;
            }

            &::after {
                bottom: -14rpx;
            }
        }
    }

    &.active {
        box-shadow: 0 0 14rpx rgba(0, 0, 0, 0.08);
        transition: initial;
        z-index: 1;

        .icon .lines {
            background: #2e97f9;

            &::before,
            &::after {
                background: #2e97f9;
            }
        }
    }
}


</style>