<template>
    <div class="hc-project-wbs-template relative h-full">
        <div class="wbs-template-segmented relative mb-14px text-center">
            <el-segmented
                v-model="templateType"
                :options="templateTypeData"
                size="large"
                @change="getWbsTreeList"
            />
        </div>
        <div v-loading="isLoading" class="hc-flex-center relative mb-14px">
            <span>选择WBS：</span>
            <el-select
                v-model="wbsId"
                placeholder="请选择WBS"
                class="w-500px"
                size="large"
                :disabled="isDisabled"
                @change="wbsChange"
            >
                <el-option-group
                    v-for="group in wbsTreeList"
                    :key="group.label"
                    :label="group.label"
                >
                    <el-option
                        v-for="item in group.data"
                        :key="item.value"
                        :label="item.label"
                        :value="item.value"
                    />
                </el-option-group>
            </el-select>
        </div>
        <div class="wbs-template-body">
            <div v-loading="leftLoading" class="left">
                <hc-card-item scrollbar :title="`${leftNum}项`">
                    <template #extra>
                        <el-checkbox
                            v-model="allChecked"
                            label="默认全部引用"
                            size="large"
                            @change="checkChang"
                        />
                    </template>
                    <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="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>
</template>

<script setup>
import { nextTick, onMounted, ref, watch } from "vue";
import { useAppStore } from "~src/store";
import { deepClone, getArrValue, getObjValue, isNullES } from "js-fast-way";
import mainApi from "~api/project/project";
import treeApi from "~api/wbs/tree";

//缓存
const store = useAppStore();

//双向绑定
const modelData = defineModel("modelValue", {
    default: {},
});

//监听数据
const formModel = ref({});
watch(
    () => modelData.value,
    (data) => {
        formModel.value = data;
    },
    { immediate: true, deep: true }
);

//监听
const userInfo = ref(store.getUserInfo);
watch(
    () => store.getUserInfo,
    (info) => {
        userInfo.value = info;
    },
    { immediate: true, deep: true }
);

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

//顶部类型
const templateType = ref(1);
const templateTypeData = [
    { value: 1, label: "质检" },
    { value: 2, label: "试验" },
    { value: 3, label: "计量" },
    { value: 5, label: "征拆" },
];

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

//获取WBS树列表
const wbsId = ref("");
const wbsTreeList = ref([]);
const isLoading = ref(false);
const getWbsTreeList = async () => {
    isLoading.value = true;
    const type = templateType.value;
    const { data } = await mainApi.findWbsTreeList(type);
    // 格式化数据
    const res = getObjValue(data);
    let arr = [
        { label: "公有库", data: [] },
        { label: "私有库", data: [] },
    ];
    const wbsInfos = getArrValue(res.wbsInfos),
        wbsPrivates = getArrValue(res.wbsTreePrivates);
    // 公有库
    wbsInfos.forEach((item) => {
        item.value = item.id;
        item.label = item.wbsName;
    });
    arr[0].data = wbsInfos;
    // 私有库
    wbsPrivates.forEach((item) => {
        item.label = item.projectName;
        item.value = item.wbsId + "," + item.projectId;
    });
    arr[1].data = wbsPrivates;
    wbsTreeList.value = arr;
    console.log(wbsTreeList.value, " wbsTreeList.value");

    //处理选中
    const form = getObjValue(formModel.value);
    wbsId.value =
        type === 1
            ? form.referenceWbsTemplateId
            : form.referenceWbsTemplateIdTrial;
    if (type === 3) wbsId.value = form.referenceWbsTemplateIdMeter;
    if (type === 5) wbsId.value = form.referenceWbsTemplateIdLar;
    if (type === -1) wbsId.value = "";

    // referenceWbsType.value = form.referenceWbsTemplateType;
    referenceWbsType.value =
        type === 1
            ? form.referenceWbsTemplateType
            : form.referenceWbsTemplateTypeTrial;
    if (type === 3) referenceWbsType.value = form.referenceWbsTemplateTypeMeter;
    if (type === 5) referenceWbsType.value = form.referenceWbsTemplateTypeLar;
    if (type === -1) referenceWbsType.value = "";
    isLoading.value = false;
    handleWbsID(wbsId.value);
    await wbsChange(wbsId.value);
};

const handleWbsID = (refId) => {
    if (refId && refId > 0) {
        let priv = {};
        if (referenceWbsType.value == "private") {
            //私有
            let list = wbsTreeList.value[1].data;
            for (let i = 0; i < list.length; i++) {
                if (list[i].pkeyId == refId) {
                    wbsId.value = list[i].wbsId + "," + list[i].projectId;
                    priv.wbsId = list[i].wbsId;
                    priv.projectId = list[i].projectId;
                    priv.value = list[i].value;
                    priv.pkeyId = list[i].pkeyId;
                    break;
                }
            }
        } else {
            //公有
            wbsId.value = refId;
        }
    }
    console.log(wbsId.value, " wbsId.value");
};
//左边树
const leftLoading = ref(false);
const leftTreeData = ref([]);

//切换wbs树
const isDisabled = ref(false);
const referenceWbsId = ref("");
const referenceWbsType = ref("");
const wbsChange = async (val) => {
    isDisabled.value = false;
    leftLoading.value = true;
    referenceWbsId.value = val;
    //无值
    if (isNullES(val)) {
        await getRightTreeApi();
        leftLoading.value = false;
        return;
    }
    //私有库
    if (val.toString().indexOf(",") >= 0) {
        referenceWbsType.value = "private";
        let ids = val.toString().split(",");
        const { data } = await mainApi.findProjectTree({
            projectId: ids[1],
            wbsId: ids[0],
        });
        leftTreeData.value = getArrValue(data);
        leftLoading.value = false;
        await getRightTreeApi();
        return;
    }
    //公有库
    if (val.length > 0) {
        referenceWbsType.value = "public";
        const { tenant_id } = getObjValue(userInfo.value);
        const { data } = await treeApi.getAlltree({
            tenantId: tenant_id,
            type: "1",
            wbsId: val,
        });
        leftTreeData.value = getArrValue(data);
        leftLoading.value = false;
        await getRightTreeApi();
    }
};

//获取右边数据
const rightLoading = ref(false);
const rightTreeData = ref([]);
const getRightTreeApi = async () => {
    rightLoading.value = true;
    isDisabled.value = true;
    let refId = referenceWbsId.value;
    if (isNullES(refId)) {
        isDisabled.value = false;
        rightLoading.value = false;
        return;
    }
    //私有
    if (refId.toString().length > 0 && referenceWbsType.value === "private") {
        let ids = refId.toString().split(",");
        if (ids.length > 1) {
            refId = ids[0];
            let list = wbsTreeList.value[1].data;
            refId = list.filter(({ projectId }) => projectId === ids[1])[0]
                .pkeyId;
        }
    }
    //引用被删会出现 wbsType -1
    if (refId && refId > 0) {
        let priv = {};
        //私有
        if (referenceWbsType.value === "private") {
            let list = wbsTreeList.value[1].data;
            for (let i = 0; i < list.length; i++) {
                if (list[i].pkeyId === refId) {
                    refId = list[i].wbsId + "," + list[i].projectId;
                    priv.wbsId = list[i].wbsId;
                    priv.projectId = list[i].projectId;
                    priv.value = list[i].value;
                    priv.pkeyId = list[i].pkeyId;
                    break;
                }
            }
        } else {
            //公有
            refId = referenceWbsId.value;
        }
    }
    console.log(refId, "refId");

    const form = getObjValue(formModel.value);
    let recordId = formatWbsId(refId);
    const { data } = await mainApi.findProjectTree({
        projectId: form.id,
        // wbsId: refId,
        wbsId: recordId,
    });
    const projectTree = getArrValue(data);
    isDisabled.value = projectTree.length > 0;
    rightTreeData.value = projectTree;
    setRightTree();
    rightLoading.value = false;
};

//默认全部引用
const allChecked = ref(false);
const checkChang = () => {
    setCheckTreeChange();
};

//左边树被展开
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 = JSON.parse(JSON.stringify(leftTreeData.value));
        const halfKeys = left.getHalfCheckedKeys();
        const keys = left.getCheckedKeys().concat(halfKeys);
        getRightTree(allTree, keys);
        rightTreeData.value = allTree;
        setCheckTreeChange(rightTreeData.value);
    } 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();
    setCheckTreeChange(delNodes);
};

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;
    }
    if (allChecked.value) {
        tree = leftTreeRef.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]);
        }
    }
};

//格式化wbsid
const formatWbsId = (rid) => {
    let refId = rid;
    if (isNullES(refId)) {
        return refId;
    }
    if (referenceWbsType.value === "private" && refId.toString().length > 0) {
        // 私有库右边树形数据是通过 pkeyId 查询的
        let ids = refId.toString().split(",");
        if (ids.length > 1) {
            refId = ids[0];
            let list = wbsTreeList.value[1].data;
            refId = list.filter(({ projectId }) => projectId === ids[1])[0]
                .pkeyId;
            return refId;
        } else {
            return "";
        }
    } else {
        return refId;
    }
};

const rightObj = ref({});
const setCheckTreeChange = () => {
    let recordId = formatWbsId(wbsId.value);
    rightObj.value = {
        wbsId: recordId,
        data: rightTreeData.value,
    };
};

const getTreeObj = async () => {
    const form = getObjValue(formModel.value);
    const ids = await getTreeAllId("right");
    const wbs_id = wbsId.value;

    let obj = {
        wbsId: wbs_id,
        projectId: form.id,
        wbsType: templateType.value,
        wbsTreeIds: ids,
    };
    if (wbs_id.toString().indexOf(",") >= 0) {
        //私有库
        obj.referenceType = "private";
        let ids = wbs_id.toString().split(",");
        obj.wbsId = ids[0];
        obj.referencePrivateWbsProjectId = ids[1];
        obj.primaryKeyId = leftTreeData.value[0].primaryKeyId;
    } else {
        //公有库
        obj.referenceType = "public";
        obj.wbsId = wbs_id;
    }
    return obj;
};

defineExpose({
    getTreeObj,
});
</script>

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