<template>
    <hc-drawer v-model="isShow" ui="hc-project-list-edit-formula-drawer" to-id="hc-layout-box" is-close @close="drawerClose">
        <hc-card is-action-btn :scrollbar="isScrollBar">
            <div class="hc-project-list-edit-formula-card" :class="isScrollBar ? '' : 'is-no-scroll'">
                <!-- 顶部操作 -->
                <div class="hc-formula-card-box border-dashed-card hc-flex mb-14px h-58px">
                    <div class="retain hc-flex h-full w-174px">
                        <el-checkbox v-model="isRetain" size="large" />
                        <span class="ml-5px text-14px">保留</span>
                        <div class="relative ml-5px w-90px">
                            <el-input-number v-model="retainNum" block :step="1" :min="0" :max="5" :disabled="!isRetain" controls-position="right" />
                        </div>
                        <span class="ml-5px text-14px">位</span>
                    </div>
                    <div class="range hc-flex h-full w-155px">
                        <el-button :type="deviationRangeShow ? 'primary' : ''" @click="setDeviationRange">允许偏差值范围</el-button>
                    </div>
                    <div class="menu h-full flex-1">
                        <hc-body padding="0">
                            <el-menu :default-active="formulaMenuIndex" mode="horizontal" @select="handleFormulaMenu">
                                <el-sub-menu v-for="(arr, key, index) in formulaMenuList" :key="key" :index="key">
                                    <template #title>{{ key }}</template>
                                    <el-menu-item v-for="(item, i) in arr" :key="i" :index="`${index + 1}-${i + 1}`">{{ item?.name }}</el-menu-item>
                                </el-sub-menu>
                            </el-menu>
                        </hc-body>
                    </div>
                    <div class="hand hc-flex h-full w-100px">
                        <el-button>手写模式</el-button>
                    </div>
                </div>
                <!-- 函数公式 -->
                <div class="border-dashed-card hc-formula-card-math mb-14px">
                    <div class="header hc-flex">
                        <div class="name flex-1 text-14px">函数公式.</div>
                        <div class="extra relative ml-24px">
                            <el-button :type="isResetFun ? 'primary' : 'info'" size="small" @click="resetFunClick">重置函数</el-button>
                        </div>
                    </div>
                    <div class="body relative">
                        <template v-for="(item, index) in resultFormula" :key="index">
                            <span class="element-class text-26px" :class="item.selected ? 'is-cur' : ''" @click="resultFormulaItem(item)">{{ item.name }}</span>
                        </template>
                        <span class="ml-10px mr-10px text-26px">=</span>
                        <template v-for="(item, index) in processFormula" :key="index">
                            <span class="element-class text-26px" :class="item.selected ? 'is-cur' : ''" @click="processFormulaItem(item)">{{ item.name }}</span>
                        </template>
                    </div>
                </div>
                <!-- 重置函数 -->
                <div v-if="isResetFun" class="hc-formula-reset-fun mb-14px">
                    <hc-body split padding="0">
                        <template #left>
                            <hc-card class="reset-fun-left-card" scrollbar :loading="treeResetFunLoading">
                                <template #header>
                                    <hc-search-input v-model="resetFunTree" @search="resetFunTreeSearch" />
                                </template>
                                <el-tree
                                    ref="treeResetFunLazyRef" :default-expanded-keys="treeResetFunLazyExpanded" node-key="id" :props="defaultProps"
                                    :expand-on-click-node="false" lazy highlight-current :load="treeResetFunLazyLoad" @node-click="treeResetFunLazyClick"
                                />
                            </hc-card>
                        </template>
                        <hc-card class="reset-fun-right-card">
                            <template #header>
                                <hc-search-input v-model="resetFunEle" placeholder="请输入你想搜索的元素字段" @search="resetFunEleSearch" />
                            </template>
                            <div class="body h-full">
                                <div class="tag-box">
                                    <template v-for="(item, index) in resetFunEleData" :key="index">
                                        <el-button v-if="item.k" type="primary" plain size="small" @click="resetFunEleTagClick(item)">{{ item.name }}</el-button>
                                        <el-button v-else type="primary" plain size="small" @click="resetFunEleTagClick(item)">{{ item.eName }}</el-button>
                                    </template>
                                </div>
                                <div class="action-box hc-flex">
                                    <div class="left hc-flex flex-1">
                                        <div class="btn hc-flex-center" @click="resetFunText">
                                            <span class="text">输入值</span>
                                        </div>
                                        <div class="btn hc-flex-center" @click="resetFunBrackets('(')">
                                            <span class="symbol">(</span>
                                        </div>
                                        <div class="btn hc-flex-center" @click="resetFunBrackets(')')">
                                            <span class="symbol">)</span>
                                        </div>
                                        <div class="btn hc-flex-center" @click="resetFunOperator('+')">
                                            <i class="i-ri-add-line" />
                                        </div>
                                        <div class="btn hc-flex-center" @click="resetFunOperator('-')">
                                            <i class="i-ri-subtract-line" />
                                        </div>
                                        <div class="btn hc-flex-center" @click="resetFunOperator('*')">
                                            <i class="i-ri-close-line" />
                                        </div>
                                        <div class="btn hc-flex-center" @click="resetFunOperator('%')">
                                            <hc-icon name="divide" />
                                        </div>
                                    </div>
                                    <div class="right hc-flex">
                                        <el-tooltip content="删除元素" placement="top-end">
                                            <div class="btn hc-flex-center" @click="resetFunDel">
                                                <i class="i-ri-delete-back-2-line" />
                                            </div>
                                        </el-tooltip>
                                        <el-tooltip content="清空所有" placement="top-end">
                                            <div class="btn hc-flex-center" @click="resetFunClear">
                                                <i class="i-ri-delete-bin-3-line" />
                                            </div>
                                        </el-tooltip>
                                    </div>
                                </div>
                                <div class="input-box">
                                    <draggable v-model="selectEleFormula" item-key="index">
                                        <template #item="{ element }">
                                            <span class="element-class" :class="[`is-${element.type}`, element.selected ? 'is-cur' : '']" @click="selectEleFormulaItem(element)">{{ element.name }}</span>
                                        </template>
                                    </draggable>
                                </div>
                            </div>
                        </hc-card>
                    </hc-body>
                </div>
            </div>
            <template #action>
                <el-button @click="drawerClose">取消</el-button>
                <el-button type="primary" :loading="submitLoading" @click="submitClick">保存</el-button>
            </template>
        </hc-card>
    </hc-drawer>
</template>

<script setup>
import { nextTick, ref, watch } from 'vue'
import { useClick } from 'hc-vue3-ui'
import { ElMessageBox } from 'element-plus'
import {
    arrIndex, deepClone, getArrValue,
    getObjValue, getRandom, isNullES,
} from 'js-fast-way'
import draggable from 'vuedraggable'
import mainApi from '~api/project/formula'
import eleApi from '~api/project/element'
import treeApi from '~api/wbs/tree'
import priApi from '~api/wbs/private'

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

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

//双向绑定
const isShow = defineModel('modelValue', {
    default: false,
})

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

//监听显示
watch(isShow, (val) => {
    if (val) getDataApi()
})

//基础变量
const symbolReg = /(\+|-|\*|\/)（.+）/ //加减乘除
const operatorReg = /^\+|-|\*|%/ //加减乘除
const startFCRegExp = /^FC\.([a-zA-Z\d]+)\(/ //匹配开始的FC.xxx(
const isScrollBar = ref(true)

//获取数据
const getDataApi = async () => {
    console.log(dataInfo.value)
    getTypeMapApi().then()
    getWbsFormElementData().then()
}

//保留位数
const isRetain = ref(false)
const retainNum = ref(2)

//允许偏差值范围
const deviationRangeShow = ref(false)
const setDeviationRange = () => {
    deviationRangeShow.value = !deviationRangeShow.value
}

//获取顶部菜单数据
const formulaMenuMap = ref({})
const formulaMenuIndex = ref(null)
const formulaMenuList = ref({})
const getTypeMapApi = async () => {
    const { data } = await mainApi.getTypeMap()
    const res = getObjValue(data)
    formulaMenuList.value = deepClone(res)
    //生成map，方便查找
    for (let key in res) {
        if (typeof(res[key]) === 'object') {
            res[key].forEach((formula)=>{
                formula.template = JSON.parse(formula.template)
                if (operatorReg.test(formula.template.ft)) {
                    formulaMenuMap.value[formula.template.ft] = formula
                } else if (startFCRegExp.test(formula.template.ft)) {
                    let regRes = formula.template.ft.match(startFCRegExp)
                    formulaMenuMap.value[regRes[0]] = formula
                }
            })
        }
    }
}

//菜单被选择
const handleFormulaMenu = (index, path) => {
    console.log(index, path)
}

//获取数据
const resultFormula = ref([])
const getWbsFormElementData = async () => {
    const { eleId } = getObjValue(dataInfo.value)
    resultFormula.value = []
    if (isNullES(eleId)) return
    const { data } = await eleApi.detail(eleId)
    const obj = getObjValue(data)
    resultFormula.value = [{
        type: 'Element',
        name: obj.eName,
        id: obj.id,
        selected: false,
        tableElementKey: obj.tableElementKey,
        children: [],
    }]
}

//被点击
const resultFormulaItem = (item) => {
    //清除右边的选中
    processFormula.value.forEach((obj) => {
        obj.selected = false
    })
    //遍历左边的选中
    const arr = resultFormula.value
    for (let i = 0; i < arr.length; i++) {
        if (item.index === arr[i].index) {
            arr[i].selected = !arr[i].selected
        } else {
            arr[i].selected = false
        }
    }
    resultFormula.value = arr
}

//是否重置函数
const isResetFun = ref(false)
const resetFunClick = () => {
    isResetFun.value = !isResetFun.value
    isScrollBar.value = !isResetFun.value
}

//tree树配置
const defaultProps = {
    label: 'title',
    children: 'children',
    isLeaf: (data) => {
        return !data.hasChildren
    },
}

//重置函数懒加载树
const treeResetFunLazyRef = ref(null)
const treeResetFunLazyExpanded = ref([])

//获取重置函数懒加载树的数据
const treeResetFunLoading = ref(false)
const treeResetFunLazyLoad = async (node, resolve) => {
    const { level, data } = node
    let parentId = level !== 0 ? data.id : 12345678910
    const { eleType, node: dataNode, tableType } = getObjValue(dataInfo.value)
    const treeNode = getObjValue(dataNode)
    if (level === 0) treeResetFunLoading.value = true
    if (!eleType) {
        //获取接口数据
        const { data } = await priApi.tabTypeLazyTreeAll({
            parentId,
            current: 1,
            size: 99999,
            hasPartFormula: treeNode.hasPartFormula,
        })
        const res = getArrValue(data.records)
        treeResetFunLoading.value = false
        resolve(res)
        //处理返回的数据
        await nextTick()
        //处理展开
        try {
            const expandId = tableType ? Number(treeNode.tableType) - 1 : Number(treeNode.parentId) - 1
            if (!isNullES(expandId) && expandId >= 0) node.childNodes[expandId].expand()
        } catch { /* empty */ }
        //处理选中
        try {
            const paramsId = treeNode.initTableId
            if (!isNullES(paramsId)) {
                treeResetFunLazyRef.value?.setCurrentKey(paramsId)
            }
        } catch { /* empty */ }
        //获取节点详情
        await getNodeDetailApi(treeNode)
    } else if (eleType) {
        resolve([])
    }
}

//重置函数懒加载树点击
const treeResetFunItemData = ref({})
const treeResetFunNodeData = ref({})
const treeResetFunLazyClick = async (data, node) => {
    treeResetFunItemData.value = data
    treeResetFunNodeData.value = node
    await getNodeDetailApi(data)
}

//重置函数树搜索
const resetFunTree = ref('')
const resetFunTreeSearch = () => {

}

//重置函数元素搜索
const resetFunEle = ref('')
const resetFunEleSearch = () => {

}

//获取节点详情
const resetFunEleData = ref([])
const getNodeDetailApi = async (item) => {
    await useClick(300)
    if (isNullES(item.initTableId)) {
        resetFunEleData.value = []
        return
    }
    if (item.hasChildren === false || item.isLinkTable === 2) {
        const { data } = await treeApi.getTableElments({
            id: item.initTableId,
        })
        resetFunEleData.value = getArrValue(data)
    } else {
        resetFunEleData.value = []
    }
}

//重置函数 元素字段被点击
const selectEleFormula = ref([])
const resetFunEleTagClick = (item) => {
    const arr = selectEleFormula.value
    let { type, name } = getObjValue(arr[arr.length - 1])
    if (type === 'Text') {
        window?.$message.warning('元素无法连续出现在输入值后面')
        return
    }
    if (type === 'Brackets' && name === ')') {
        window?.$message.warning('元素无法连续出现在右括号后面')
        return
    }
    if (arr.length === 0 || ['Operator', 'Brackets'].includes(type) || name === '(') {
        if (!isNullES(item.tableElementKey)) {
            selectEleFormula.value.push({
                type: 'Element',
                name: item.eName,
                id: item.id,
                selected: false,
                tableElementKey: item.tableElementKey,
                index: getRandom(5),
                children: [],
            })
        }
    } else {
        window?.$message.warning('当前操作不符合要求')
    }
}

//输入弹窗
const promptMessageBox = async () => {
    return new Promise(resolve => {
        ElMessageBox.prompt('', '请输入值', {
            confirmButtonText: '确定',
            cancelButtonText: '取消',
            inputErrorMessage: '请输入内容',
            inputValidator: (value) => {
                return !isNullES(value)
            },
        }).then(({ value }) => {
            resolve(value)
        }).catch(() => {
            resolve()
        })
    })
}

//重置函数 输入值
const resetFunText = async () => {
    const val = await promptMessageBox()
    if (isNullES(val)) return
    const arr = selectEleFormula.value
    if (arr.length > 0) {
        let { type, name } = getObjValue(arr[arr.length - 1])
        if (type === 'Element') {
            window?.$message.warning('输入值无法连续出现在元素后面')
            return
        }
        if (type === 'Text') {
            window?.$message.warning('输入值无法连续出现在输入值后面')
            return
        }
        if (type === 'Brackets' && name === ')') {
            window?.$message.warning('输入值无法连续出现在右括号后面')
            return
        }
    }
    selectEleFormula.value.push({
        type: 'Text',
        name: val,
        selected: false,
        index: getRandom(5),
    })
}

//重置函数 括号
const resetFunBrackets = (val) => {
    selectEleFormula.value.push({
        type: 'Brackets',
        name: val,
        selected: false,
        index: getRandom(5),
    })
}

//重置函数 运算符
const resetFunOperator = (val) => {
    const arr = selectEleFormula.value, map = formulaMenuMap.value
    if (arr.length <= 0) {
        window?.$message.warning('公式开头不能是运算符号')
        return
    }
    let { type, name } = getObjValue(arr[arr.length - 1])
    if (type === 'Operator') {
        window?.$message.warning('运算符号无法连续出现在运算符号后面')
        return
    }
    if (type === 'Brackets' && name === '(') {
        window?.$message.warning('运算符号无法连续出现在左括号后面')
        return
    }
    const obj = getObjValue(map[val])
    selectEleFormula.value.push({
        type: 'Operator',
        name: symbolReg.exec(obj.name)[1],
        selected: false,
        template: obj.template,
        index: getRandom(5),
    })
}

//重置函数 删除
const resetFunDel = () => {
    const arr = deepClone(selectEleFormula.value)
    if (arr.length <= 0) {
        window?.$message.warning('请先添加相关元素')
        return
    }
    const index = arrIndex(arr, 'selected', true)
    if (index !== -1) {
        arr.splice(index, 1)
        selectEleFormula.value = arr
    } else {
        arr.splice(arr.length - 1, 1)
        selectEleFormula.value = arr
    }
}

//重置函数 清空
const resetFunClear = () => {
    selectEleFormula.value = []
}

//被点击
const selectEleFormulaItem = (item) => {
    const arr = selectEleFormula.value
    for (let i = 0; i < arr.length; i++) {
        if (item.index === arr[i].index) {
            arr[i].selected = !arr[i].selected
        } else {
            arr[i].selected = false
        }
    }
    selectEleFormula.value = arr
}

//保存
const submitLoading = ref(false)
const submitClick = async () => {
    //重置函数
    if (isResetFun.value) {
        setProcessFormula()
    }
}

//赋值给等号右边的数组
const processFormula = ref([])
const setProcessFormula = () => {
    const arr = selectEleFormula.value
    let leftNum = 0, rightNum = 0
    arr.forEach(({ type, name }) => {
        if (type === 'Brackets') {
            if (name === '(') {
                leftNum++
            } else if (name === ')') {
                rightNum++
            }
        }
    })
    if (leftNum !== rightNum) {
        window?.$message.warning('左右括号数量不相等,请先检查是否正确')
        return
    }
    processFormula.value = deepClone(arr)
    isResetFun.value = false
    isScrollBar.value = true
}

//右边被点击
const processFormulaItem = (item) => {
    //清除左边边的选中
    resultFormula.value.forEach((obj) => {
        obj.selected = false
    })
    //遍历右边的选中
    const arr = processFormula.value
    for (let i = 0; i < arr.length; i++) {
        if (item.index === arr[i].index) {
            arr[i].selected = !arr[i].selected
        } else {
            arr[i].selected = false
        }
    }
    processFormula.value = arr
}

//关闭抽屉
const drawerClose = () => {
    isShow.value = false
    isResetFun.value = false
    isScrollBar.value = true
    selectEleFormula.value = []
    emit('close')
}
</script>

<style lang="scss">
@import '~src/styles/view/project/edit-formula';
</style>
