<template>
    <div class="hc-contract-info-wbs relative h-full">
        <div class="wbs-template-body">
            <div v-loading="leftLoading" class="left">
                <hc-card-item scrollbar :title="`${leftNum}项`">
                    <el-tree
                        ref="leftTreeRef" :data="leftTreeData" show-checkbox node-key="id" :props="treeProps"
                        highlight-current :expand-on-click-node="false" @node-expand="nodeLeftTreeExpand"
                        @check-change="checkLeftTreeChange"
                    />
                </hc-card-item>
            </div>
            <div class="btn-action">
                <div class="relative">
                    <div class="relative">
                        <el-button hc-btn :type="leftNum <= 0 ? '' : 'primary'" :disabled="leftNum <= 0" @click="addTreeClick">
                            <i class="i-ri-arrow-right-line" />
                        </el-button>
                    </div>
                    <div class="relative mt-14px">
                        <el-button hc-btn :type="rightNum <= 0 ? '' : 'primary'" :disabled="rightNum <= 0" @click="delTreeClick">
                            <i class="i-ri-arrow-left-line" />
                        </el-button>
                    </div>
                </div>
            </div>
            <div v-loading="rightLoading" class="right">
                <hc-card-item scrollbar :title="`${rightNum}项`">
                    <el-tree
                        ref="rightTreeRef" :data="rightTreeData" show-checkbox node-key="id" :props="treeProps"
                        highlight-current :expand-on-click-node="false" :default-expanded-keys="rightExpands"
                        @check-change="checkRightTreeChange"
                    />
                </hc-card-item>
            </div>
        </div>
        <div class="action">
            <el-button hc-btn class="mr-4" :loading="submitLoading" @click="saveAndExit">保存并退出</el-button>
            <el-button hc-btn type="success" :loading="submitLoading" @click="saveAndBackStep">保存并返回上一步</el-button>
            <el-button hc-btn type="primary" :loading="submitLoading" @click="saveAndNextStep">保存并进入下一步</el-button>
        </div>
    </div>
</template>

<script setup>
import { nextTick, onMounted, ref, watch } from 'vue'
import { deepClone, getArrValue, getObjValue, isNullES } from 'js-fast-way'
import projectApi from '~api/project/project'
import contractApi from '~api/project/contract'

const props = defineProps({
    data: {
        type: Object,
        default: () => ({}),
    },
})

//事件
const emit = defineEmits(['close', 'next', 'back'])

//监听数据
const dataInfo = ref(props.data)
watch(() => props.data, (data) => {
    dataInfo.value = data
    getDataApi()
}, { deep: true })

//渲染完成
onMounted(() => {
    getDataApi()
})

//树配置
const leftTreeRef = ref(null)
const rightTreeRef = ref(null)
const treeProps = {
    children: 'children',
    label: 'title',
}

//获取数据
const getDataApi = async () => {
    await getProjectDeatil()
    if (isNullES(wbsId.value)) {
        return
    }
    await getLeftTreeApi()
    await getRightTreeApi()
}

//获取项目详情
const wbsId = ref('')
const projectInfo = ref({})
const getProjectDeatil = async () => {
    wbsId.value = ''
    projectInfo.value = {}
    const { pid } = getObjValue(dataInfo.value)
    if (isNullES(pid)) return
    const { data } = await projectApi.detail(pid)
    const res = getObjValue(data)
    projectInfo.value = res
    wbsId.value = res.referenceWbsTemplateId
}

//获取WBS树列表
const leftLoading = ref(false)
const leftTreeData = ref([])
const getLeftTreeApi = async () => {
    leftLoading.value = true
    const { pid } = getObjValue(dataInfo.value)
    const { data } = await projectApi.findProjectTree({
        projectId: pid,
        wbsId: wbsId.value,
    })
    leftTreeData.value = getArrValue(data)
    leftLoading.value = false
}

//获取右边数据
const rightLoading = ref(false)
const rightTreeData = ref([])
const getRightTreeApi = async () => {
    rightLoading.value = true
    const { pid, cid } = getObjValue(dataInfo.value)
    const { data } = await contractApi.getContractInfoTree({
        wbsId: wbsId.value,
        projectId: pid,
        contractId: cid,
    })
    rightTreeData.value = getArrValue(data)
    rightLoading.value = false
    setRightTree()
}

//左边树被展开
const rightExpands = ref([])
const nodeLeftTreeExpand = (data) => {
    rightExpands.value = rightExpands.value.concat([data.id])
}

//左边树复选框被点击
const leftNum = ref(0)
const checkLeftTreeChange = () => {
    const e = leftTreeRef.value
    let checkNum = e.getCheckedKeys().length
    let halfNum = e.getHalfCheckedKeys().length
    leftNum.value = checkNum + halfNum
}

//右边树复选框被点击
const rightNum = ref(0)
const checkRightTreeChange = () => {
    const e = rightTreeRef.value
    let checkNum = e.getCheckedKeys().length
    let halfNum = e.getHalfCheckedKeys().length
    rightNum.value = checkNum + halfNum
}

//左边树新增到右边
const addTreeClick = () => {
    const left = leftTreeRef.value, right = rightTreeRef.value
    if (rightTreeData.value.length < 1) {
        //直接把左边勾选的树复制到右侧
        let allTree = deepClone(leftTreeData.value)
        const halfKeys = right.getHalfCheckedKeys()
        const keys = right.getCheckedKeys().concat(halfKeys)
        getRightTree(allTree, keys)
        rightTreeData.value = allTree
    } else {
        //只增加右侧树没有的节点，不会覆盖右侧树多余的节点
        let checkNodes = left.getCheckedNodes(false, true)

        let rIdMap = new Map()
        checkNodes.forEach((data) => {
            rIdMap.set(data.id, data)
        })

        let lIdSet = new Set()
        getRightTreeData(lIdSet, rightTreeData.value)

        //在右侧id减去左侧有的id，剩下的就是新增的id
        lIdSet.forEach((id) => {
            rIdMap.delete(id)
        })

        let addMap = new Map()
        rIdMap.forEach((data) => {
            if (data.parentId !== '0' && data.parentId !== 0) {
                //在左侧树能找到父节点的，新增
                let lNode = right.getNode(data.parentId)
                if (lNode) addMap.set(data, lNode.data.id)
            }
        })

        //把半选和选中的数组key合并
        const halfKeys = left.getHalfCheckedKeys()
        const keys = left.getCheckedKeys().concat(halfKeys)
        const myArray = Array.from(addMap.keys())
        let myright = deepClone(myArray)
        getRightTree(myright, keys)
        myright.forEach((data) => {
            right.append(data, data.parentId)
        })
    }
}

//获取右边树
const getRightTree = (arr, keys) => {
    //对比所有的node和选中的key
    for (let i = arr.length - 1; i >= 0; i--) {
        let isIn = false
        for (let j = keys.length - 1; j >= 0; j--) {
            if (keys[j] === arr[i].id) {
                isIn = true
                //已经匹配到的key移除，节省性能
                keys.splice(j, 1)
                break
            }
        }
        if (isIn) {
            //包含在选中的节点，如果有childer继续递归判断
            if (arr[i].children && arr[i].children.length) {
                getRightTree(arr[i].children, keys)
            }
        } else {
            //不包含在选中key的node删除
            arr.splice(i, 1)
        }
    }
}

const getRightTreeData = (set, arr) => {
    arr.forEach((data) => {
        set.add(data.id)
        if (data.children && data.children.length) {
            getRightTreeData(set, data.children)
        }
    })
}

//右边树移除
const delTreeClick = () => {
    const left = leftTreeRef.value, right = rightTreeRef.value
    let delNodes = right.getCheckedNodes()
    //只把选中的节点移除
    delNodes.forEach((node) => {
        right.remove(node)
        left.setChecked(node.id, false)
    })
    checkLeftTreeChange()
    checkRightTreeChange()
}

const setRightTree = () => {
    let ids = []
    const data = rightTreeData.value
    for (let i = 0; i < data.length; i++) {
        getLeafIds(ids, data[i])
    }
    //在左边把右边的节点勾选上
    const e = leftTreeRef.value
    nextTick(() => {
        e.setCheckedKeys(ids, true)
    })
}

const getLeafIds = (ids, data) => {
    if (data.children && data.children.length) {
        for (let i = 0; i < data.children.length; i++) {
            getLeafIds(ids, data.children[i])
        }
    } else {
        ids.push(data.id)
    }
}

const getTreeAllId = async (name) => {
    let tree
    if (name === 'left') {
        tree = leftTreeRef.value
    } else if (name === 'right') {
        tree = rightTreeRef.value
    }
    let ids = []
    for (let i = 0; i < tree.data.length; i++) {
        await getIds(ids, tree.data[i])
    }
    return ids.join(',')
}

const getIds = async (ids, data) => {
    ids.push(data.id)
    if (data.children && data.children.length) {
        for (let i = 0; i < data.children.length; i++) {
            await getIds(ids, data.children[i])
        }
    }
}

//保存并退出
const saveAndExit = async () => {
    const isRes = await saveDataApi()
    if (!isRes) return
    emit('close', dataInfo.value)
}

//保存并返回上一步
const saveAndBackStep = async () => {
    const isRes = await saveDataApi()
    if (!isRes) return
    emit('back', dataInfo.value)
}

//保存并进入下一步
const saveAndNextStep = async () => {
    const isRes = await saveDataApi()
    if (!isRes) return
    emit('next', dataInfo.value)
}

//保存
const submitLoading = ref(false)
const saveDataApi = async () => {
    submitLoading.value = true
    const ids = await getTreeAllId('right')
    const { pid, cid } = getObjValue(dataInfo.value)
    const { code } = contractApi.submitWbsTreeInContract({
        wbsId: wbsId.value,
        projectId: pid,
        contractId: cid,
        wbsTreeIds: ids,
    })
    submitLoading.value = false
    if (code === 200) {
        window?.$message?.success('保存成功')
    }
    return code === 200
}
</script>

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