<template>
    <div v-if="isBody" class="ui-drag-modal-box-hide">
        <Teleport :disabled="!isBody" to="#app">
            <div :id="'drag-modal-' + uuid"
                 :class="[isModalShow?'ui-drag-modal-show':'']"
                 :style="{
                     left: dragModalLeft + 'px',
                     top: dragModalTop + 'px',
                     width: widthVal + 'px',
                     height: heightVal + 'px',
                     zIndex: isModalShow ? zIndex: -1
                 }"
                 class="ui-drag-modal-box"
                 @click.capture="dragModalCapture">
                <div :class="[bg,ui]" :style="{width: widthVal + 'px', height: heightVal + 'px'}"
                     class="ui-drag-modal-dialog shadow-xl"
                     @mousedown="dragModalMouseDown">
                    <div :class="titleBorder?'border-bottom':''" class="ui-drag-modal-dialog-header">
                        <div :class="titleUi" class="ui-drag-modal-dialog-title text-lg">
                            <span v-if="title">{{ title }}</span>
                        </div>
                        <div class="ui-drag-modal-dialog-extra">
                            <template v-for="item in closeIconData">
                                <el-tooltip :content="item.name" placement="top" popper-class="z-9999">
                                    <div class="dialog-icon" @click="_closeIconClick(item)">
                                        <HcIcon :name="item.icon"/>
                                    </div>
                                </el-tooltip>
                            </template>
                            <el-tooltip :content="isFullscreen?'退出全屏':'窗口全屏'" placement="top"
                                        popper-class="z-9999">
                                <div class="dialog-icon" @click="_fullscreenClick()">
                                    <HcIcon :name="isFullscreen?'fullscreen-exit':'fullscreen'"/>
                                </div>
                            </el-tooltip>
                            <el-tooltip v-if="closeIcon" content="关闭窗口" placement="top" popper-class="z-9999">
                                <div class="dialog-icon" @click="_closeClick()">
                                    <HcIcon name="close"/>
                                </div>
                            </el-tooltip>
                        </div>
                    </div>
                    <div v-loading="isLoading" :element-loading-text="isLoadingText"
                         class="ui-drag-modal-dialog-body"
                         @mousedown.stop="dragModalBodyMouseDown">
                        <slot></slot>
                    </div>
                    <span class="ui-drag-modal-resize" @mousedown="dragModalResizeMouseDown"/>
                </div>
            </div>
        </Teleport>
    </div>
</template>

<script setup>
import {ref, nextTick, watch} from "vue"
import {deepClone, getRandom} from "vue-utils-plus"
import {useAppStore} from "~src/store";

const useAppState = useAppStore()
//参数
const props = defineProps({
    ui: {
        type: String,
        default: ''
    },
    bg: {
        type: String,
        default: ''
    },
    widths: {
        type: [Number, String],
        default: 960
    },
    title: {
        type: String,
        default: ''
    },
    titleUi: {
        type: [String, Object, Array],
        default: ''
    },
    titleBorder: {
        type: Boolean,
        default: false
    },
    closeIcon: {
        type: Boolean,
        default: true
    },
    isShow: {
        type: Boolean,
        default: false
    },
    lefts: {
        type: [Number, String],
        default: 120
    },
    tops: {
        type: [Number, String],
        default: 80
    },
    height: {
        type: [Number, String],
        default: 440
    },
    //是否排序置顶
    isSortTop: {
        type: Boolean,
        default: false
    },
    eid: {
        type: [Number, String],
        default: ''
    },
    //关闭时销毁
    isCloseDestroy: {
        type: Boolean,
        default: true
    },
    loading: {
        type: Boolean,
        default: false
    },
    loadingText: {
        type: [Number, String],
        default: '加载中...'
    },
    closeIconArr: {
        type: Array,
        default: () => ([])
    }
})

//变量
const isBody = ref(false)
const isModalShow = ref(props.isShow)
const uuid = props.eid || getRandom()
const dragModalLeft = ref(parseInt(props.lefts + ''))
const dragModalTop = ref(parseInt(props.tops + ''))
const widthVal = ref(parseInt(props.widths + ''))
const heightVal = ref(parseInt(props.height))
const closeIconData = ref(props.closeIconArr)

const isLoading = ref(props.loading)
const isLoadingText = ref(props.loadingText)

//监听
watch(() => [
    props.isShow,
    props.loading,
    props.loadingText,
    props.closeIconArr
], ([isShow, loading, loadingText, closeIcon]) => {
    isModalShow.value = isShow
    isLoading.value = loading
    isLoadingText.value = loadingText
    closeIconData.value = closeIcon
})

//深度监听弹窗排序列表变化
const dragModalSortTopList = ref(useAppState.dragModalSortTop)
watch(() => [
    useAppState.dragModalSortTop
], ([sortTopList]) => {
    dragModalSortTopList.value = sortTopList
    setModalIndex(sortTopList)
}, {deep: true})

//设置窗口层级
const zIndex = ref(2000)
const setModalIndex = (sortTopList) => {
    if (props.isSortTop) {
        const index = sortTopList.indexOf(uuid)
        zIndex.value = 2000 + (index + 1)
    }
}

//页面渲染完成
nextTick(() => {
    //页面渲染完成后，再让 vue3 的 Teleport，把弹出框挂载到外部节点上。
    isBody.value = true
    if (props.isSortTop) {
        const sortTopList = dragModalSortTopList.value
        let index = sortTopList.indexOf(uuid)
        if (index === -1) {
            sortTopList.push(uuid)
            index = sortTopList.length - 1
        }
        useAppState.setDragModalSortTop(sortTopList)
        setModalIndex(sortTopList)
        //窗口位置偏移，防止重叠在一起，误导用户
        dragModalLeft.value = dragModalLeft.value + (index * 20)
        dragModalTop.value = dragModalTop.value + (index * 20)
    }
})

//弹窗拖动
const dragModalMouseDown = (event) => {
    dragModalCapture()
    // 阻止默认事件和冒泡
    event.preventDefault()
    event.stopPropagation()
    //获取相关dom元素
    let body = document.body, dom = document.getElementById('drag-modal-' + uuid)
    // 鼠标按下，计算当前元素距离可视区的距离
    const disX = event.clientX - dom.offsetLeft, disY = event.clientY - dom.offsetTop;
    const lefts = body.clientWidth - dom.clientWidth, tops = body.clientHeight - dom.clientHeight;
    document.onmousemove = (ve) => {
        // 通过事件委托，计算移动的距离
        let left = ve.clientX - disX, top = ve.clientY - disY
        // 判断是否超出可视区
        if (left <= 0) left = 0
        if (left > lefts) {
            left = lefts
        }

        if (top <= 0) top = 0
        if (top > tops) {
            top = tops
        }
        // 移动当前元素
        dragModalLeft.value = left
        dragModalTop.value = top
    }
    document.onmouseup = () => {
        document.onmousemove = null;
        document.onmouseup = null;
    }
}

//禁止拖动
const dragModalBodyMouseDown = () => {
    dragModalCapture()
}

//弹窗改变宽高
const dragModalResizeMouseDown = (event) => {
    dragModalCapture()
    // 阻止默认事件和冒泡
    event.preventDefault()
    event.stopPropagation()
    //获取相关dom元素
    let body = document.body, dom = document.getElementById('drag-modal-' + uuid)
    let clientX = event.clientX, clientY = event.clientY;
    let offsetWidth = dom.offsetWidth, clientHeight = dom.clientHeight;
    document.onmousemove = (e) => {
        //拖拽时为了对宽和高 限制一下范围，定义两个变量
        let W = e.clientX - clientX + offsetWidth;
        let H = e.clientY - clientY + clientHeight;

        if (body.offsetWidth - e.clientX < 0) {
            W = body.offsetWidth - parseInt(dom.style.marginLeft);
        }
        if (body.offsetHeight - e.clientY < 0) {
            H = body.offsetHeight - parseInt(dom.style.marginTop);
        }

        widthVal.value = W;// 拖拽后物体的宽
        heightVal.value = H;// 拖拽后物体的高
    }
    document.onmouseup = () => {
        document.onmousemove = null;
        document.onmouseup = null;
    }
}

//事件
const emit = defineEmits(['close', 'closeIconTap'])
const show = () => {
    isModalShow.value = true;
}
const hide = () => {
    isModalShow.value = false;
    if (props.isCloseDestroy) {
        destroyModal()
    }
}
const _closeClick = () => {
    if (!isLoading.value) {
        emit('close')
    }
}

const _closeIconClick = (item) => {
    if (!isLoading.value) {
        emit('closeIconTap', item)
    }
}

//关闭弹窗
const closeFunc = () => {
    hide();
}

//缓存样式
const cacheStyleJson = ref({})
const isFullscreen = ref(false)

//全屏
const _fullscreenClick = () => {
    if (isFullscreen.value) {
        const styleJson = deepClone(cacheStyleJson.value)
        dragModalLeft.value = styleJson.left
        dragModalTop.value = styleJson.top
        widthVal.value = styleJson.width
        heightVal.value = styleJson.height
        isFullscreen.value = false
    } else {
        const {clientWidth, clientHeight} = document.body
        cacheStyleJson.value = deepClone({
            width: widthVal.value,
            height: heightVal.value,
            left: dragModalLeft.value,
            top: dragModalTop.value
        })
        dragModalLeft.value = 0
        dragModalTop.value = 0
        widthVal.value = clientWidth
        heightVal.value = clientHeight
        isFullscreen.value = true
    }
}

//弹窗被点击
const dragModalCapture = () => {
    if (props.isSortTop) {
        const sortTopList = dragModalSortTopList.value
        const index = sortTopList.indexOf(uuid)
        if (index === -1) {
            //检查是否已经存在，不存在则添加
            sortTopList.push(uuid)
            useAppState.setDragModalSortTop(sortTopList)
        } else if (index !== sortTopList.length - 1) {
            //检查是否在最上层，不在则置顶，可以解决多次点击时，频繁更改全局状态的问题
            sortTopList.splice(index, 1)
            sortTopList.push(uuid)
            useAppState.setDragModalSortTop(sortTopList)
        }
    }
}

//销毁此弹窗
const destroyModal = () => {
    isBody.value = false;
    if (props.isSortTop) {
        const sortTopList = dragModalSortTopList.value
        const index = sortTopList.indexOf(uuid)
        if (index !== -1) {
            sortTopList.splice(index, 1)
        }
    }
}

// 暴露出去
defineExpose({
    destroyModal,
    closeFunc
})
</script>

<style lang="scss" scoped>
@import './modal.scss';
</style>
