<template>
  <WlPopup
    class="department-selector-wrap"
    data-weiling-mobile-ui-bc-department-selector-popup
    v-model="popupVisible"
    :style="{ height: '90%' }"
    position="bottom"
    round
    @closed="onClose"
  >
    <div class="popup-content">
      <DepartmentHeader
        :showBack="showBack"
        :isAllChecked="isSelectAllBool"
        @onBack="onBack"
        @onClose="onClose"
        @onChooseAll="onChooseAll"
      />
      <div class="main-wrap">
        <DepartmentList
          v-model:isSelectAll="isSelectAllBool"
          :list="currentList"
          :selectedList="checkedListArr"
          @onChoose="onChoose"
          @onMore="onMore"
        />
      </div>
      <!-- 多选平铺end -->
      <DepartmentFooter :list="checkedListArr" @onConfirm="onConfirm" />
    </div>
  </WlPopup>
</template>

<script lang="ts">
export default {
  name: "BCDepartmentSelectorPopup",
};
</script>

<script setup lang="ts">
/**
 * 返回不删，只是切换下标
 * 清空选中列表的数据，把子的递归清除
 */
import useStack from "./hooks/useStack";
import Store from "@mobileUI/store/index";
import useHandleData from "./hooks/useHandleData";
import useCheckedData from "./hooks/useCheckedData";
import { ref, toRaw, watchEffect, watch, computed } from "vue";
import WlPopup from "@mobileUI/components/WlPopup/src/index.vue";
import DepartmentList from "./components/DepartmentList/index.vue";
import DepartmentFooter from "./components/DepartmentFooter/index.vue";
import DepartmentHeader from "./components/DepartmentHeader/index.vue";
import {
  TDepartmentList,
  TCheckedStatus,
} from "@mobileUI/typings/BCDepartmentSelectorPopup";

const { onGetData } = useHandleData();
const { stack, showBack, currentList, onChangeStack, onPopStack, onAddStack } =
  useStack();
const {
  checkedList,
  checkedIds,
  onAddCheckdList,
  onGetCheckedList,
  onSetCheckedbyIds,
} = useCheckedData();

type Props = {
  show: boolean;
  envData: TEnv.TEnvData;
  defaultData?: TDepartmentList[];
};

const props = withDefaults(defineProps<Props>(), {
  show: false,
  envData: null,
  defaultData: () => [],
});

const emit = defineEmits<{
  (e: "onClose");
  (e: "update:show", val: boolean);
  (e: "onConfirm", val: TDepartmentList[]); //确认按钮
}>();

const popupVisible = ref(false);
const isAllChecked = ref(false);
const originTreeData = ref<TDepartmentList[]>(null);
const checkedListArr = ref(props.defaultData);
const isSelectAllBool = ref(false);

const checkedListIds = computed(() =>
  checkedListArr.value.map((res) => res.id),
);

const onGetIndex = (list, id) => {
  return (list ?? []).findIndex((ele) => ele.id === id);
};

const onJudgeExist = (list, id) => {
  return onGetIndex(list, id) !== -1;
};

/***
 * @description: 获取外部传入的默认列表处理之后的数据
 * @param {*} list 处理之后的列表数据
 * @param {*} selectVal 默认选中值
 * @return {*} 页面里面使用的选择的数据
 */
const onGetDefauleData = (list, selectVal) => {
  if (!list?.length) return [];
  let data = [];
  list.forEach((element) => {
    const { id = "", children = [] } = element;
    if (onJudgeExist(selectVal, id)) {
      data.push(element);
    } else {
      const childSelect = onGetDefauleData(children, selectVal);
      data = [...data, ...childSelect];
    }
  });
  return data;
};

watch(
  () => [props.defaultData, originTreeData.value],
  () => {
    if (props.defaultData?.length !== 0) {
      let data = onGetDefauleData(
        toRaw(originTreeData.value),
        props.defaultData,
      );
      // 如果列表里面没有找到，那么就表示多余的数据是当前人没有权限操作的部门，需要额外添加
      if (props.defaultData?.length !== data.length) {
        const unEmpowerData = (props.defaultData ?? []).filter(
          (ele) => !onJudgeExist(data, ele.id),
        );
        data = data.concat(unEmpowerData);
      }
      checkedListArr.value = data;
    }
  },
);

/***
 * @description: 取消全选
 * @param {*} list 取消选择的列表
 * @param {*} selectedList 当前选择的数据
 * @return {*} 处理之后选择的数据列表
 */
const unSelectAll = (list, selectedList) => {
  if (list.length === 0) return;
  for (const iterator of list) {
    selectedList = unSelect(iterator, selectedList, originTreeData.value);
  }
  return selectedList;
};
/***
 * @description: 拉平字节点
 * @param {*} list
 * @return {*}
 */
// const onFlatChild = (list) => {
//   let childrenList = list;
//   list.forEach((element) => {
//     const { children = [] } = element;
//     const data = onFlatChild(children);
//     childrenList = [...childrenList, ...data];
//   });
//   return childrenList;
// };
/***
 * @description: 选择分组
 * @param {*} item 被选择的分组
 * @param {*} selectedList 当前已经被选择的分组列表
 * @return {*} 新的选择列表
 */
const onSelectItem = (item, selectedList) => {
  const { childrenIds } = item;
  const data = [];
  if (selectedList.length !== 0) {
    // 过滤掉子节点已经被选择的节点
    for (const iterator of selectedList) {
      if (
        !childrenIds.includes(iterator.id) &&
        !checkedListIds.value.includes(item.id)
      ) {
        data.push(iterator);
      }
    }
  }
  data.push(item);
  return data;
};
/***
 * @description: 全选
 * @param {*} list 选择列表
 * @param {*} selectedList 当前选中的列表
 * @return {*} 新的选择列表
 */
const selectAll = (list, selectedList) => {
  console.log("选择所有的", list, selectedList);
  const [item] = list;
  const { parentIds = [] } = item;
  const [parent] = parentIds;
  // 如果当前节点的父节点已经被选择了，那么就不需要选择
  if (onJudgeExist(selectedList, parent)) return selectedList;
  for (const iterator of list) {
    selectedList = onSelectItem(iterator, selectedList);
  }
  return selectedList;
};
/***
 * @description: 依据查询获取node
 * @param {*} list 列表
 * @param {*} id 需要查找的id
 * @return {*} 查找到的node节点
 */
const getNode = (list, id) => {
  for (const iterator of list) {
    if (id === iterator.id) {
      return iterator;
    }
    const { children = [] } = iterator;
    const data = getNode(children, id);
    if (data) {
      return data;
    }
  }
  return null;
};
/***
 * @description: 取消选择
 * @param {*} item 取消选择的节点
 * @param {*} selectedList 当前的选择列表
 * @param {*} list 总列表
 * @return {*} 新的选择列表
 */
const unSelect = (item, selectedList, list) => {
  const { id = "", parentIds = [] } = item;
  const index = onGetIndex(selectedList, id);
  // 如果当前元素在选择列表里面，那么直接删除即可
  if (index !== -1) {
    return [...selectedList.slice(0, index), ...selectedList.slice(index + 1)];
  }
  // 如果没有在当前列表里面，那么需要查找到是哪个父节点在选择列表里面，
  // 然后从最高层的父节点开始增加选择列表
  //当节点的id在当前节点的父节点时，表示这个节点不能被选择，
  //不在item的父节点parentIds时，表示是兄弟节点，那么需要默认选中，因为是最上层的父节点被选中的
  // 到了最后一层，是当前节点所在的列表，那么除了当前节点外，其他节点都需要被默认选中
  let parentId = "",
    parentIndex = 0;
  //查找到是哪个父节点在选择列表里面，将其作为基准节点
  for (const iterator of parentIds) {
    const i = onGetIndex(selectedList, iterator);
    if (i !== -1) {
      // 最高层被选中的父节点已经不是选中状态了，所以需要删除这个节点
      parentId = iterator;
      selectedList.splice(i, 1);
      break;
    }
    // 如果没有在选择列表里面，那么表示选择的父节点还在上层
    parentIndex++;
  }
  // 获取最上层的父节点，后面的children都从开始一级一级取
  const parentNode = getNode(list, parentId);
  let { children = [] } = parentNode;
  for (let i = parentIndex; i >= 0; i--) {
    // 如果到了最后一层，那么就表示到了item这一层的数据，因此判断条件改为 非item的都被选中
    if (i === 0) {
      children.forEach((ele) => {
        if (ele.id !== id) {
          selectedList.push(ele);
        }
      });
    } else {
      // 获取到item对应这一层的父id
      const pId = parentIds[i - 1];
      let nextIndex = 0;
      // 如果节点是当前节点的父节点，那么就不能被选中
      children.forEach((element, index) => {
        if (element.id !== pId) {
          selectedList.push(element);
        } else {
          nextIndex = index;
        }
      });
      const nextChild = children[nextIndex];
      if (nextChild) {
        children = nextChild.children;
      }
    }
  }
  return selectedList;
};

//全选/取消全选
const onChooseAll = (bool) => {
  if (bool) {
    checkedListArr.value = selectAll(currentList.value, checkedListArr.value);
  } else {
    checkedListArr.value = unSelectAll(currentList.value, checkedListArr.value);
  }
};

//修改全选状态
const onChangeChooseAllStatus = () => {
  isAllChecked.value = currentList.value.every(
    (item) => item.checkedStatus === "checked",
  );
};

//选择部门
const onChoose = (item: TDepartmentList, status: string) => {
  if (status === "checked") {
    checkedListArr.value = unSelect(
      item,
      checkedListArr.value,
      originTreeData.value,
    );
  } else {
    checkedListArr.value = onSelectItem(item, checkedListArr.value);
  }
};

//获取当前列表的上一级父item
const getParentItem = () => {
  const parentId = currentList.value[0].pid;
  const parentList = stack.value[stack.value.length - 2];
  const parentItem = parentList.filter((res) => res.id === parentId);
  return parentItem.length > 0 ? parentItem[0] : {};
};

/**
 * 每次返回需要检查每一级的状态
 * 返回上一级选中状态要改变，要添加到checkList。
 * 但是不用显示出来，所以在pre-check/checked的状态下，showInCheckedList改成false
 * 1. 如果当前层级的checkedStatus个别为pre-check
 * 那上一级的checkedStatus设置为pre-check
 * 1. 如果当前层级的checkedStatus都为checked
 * 那上一级的checkedStatus也设置为checked
 * 2. 如果当前层级的checkedStatus个别为checked
 * 那上一级的checkedStatus也设置为pre-check
 * 4. 如果当前层级的checkedStatus全部为no-check
 * 那上一级的checkedStatus设置为no-check
 */
const onSetParentCheckedStatus = () => {
  if (stack.value.length <= 1) return;
  const currentListLen = currentList.value.length;
  const parentItem = getParentItem();
  let order = currentList.value.length - 1;
  let parentStatus: TCheckedStatus = "no-check";
  let noCheckedCount = 0;
  let showInCheckedList = true;
  while (order >= 0) {
    const cur = currentList.value[order];
    if (cur.checkedStatus === "pre-check") {
      break;
    } else if (cur.checkedStatus === "no-check") {
      noCheckedCount++;
    }
    order--;
  }
  if (noCheckedCount === currentListLen) {
    parentStatus = "no-check";
  } else {
    parentStatus = "pre-check";
    showInCheckedList = false;
  }
  parentItem.checkedStatus = parentStatus;
  parentItem.showInCheckedList = showInCheckedList;
  //如果是半选就添加到选中列表
  if (["pre-check", "checked"].includes(parentStatus))
    onAddCheckdList([parentItem]);
};

/**
 * 获取下一级数据，需要检查下一级的选中状态
 * 1. 如果defaultData有传的情况下
 * 因为事先会处理树形结构修改checkedStatus的状态
 * 1. 如果选中的层级的checkedStatus是checked
 * 那就把下一层的checkedStatus全部设置为checked
 * 2. 如果选中的层级的checkedStatus是no-check
 * 那就把下一层的checkedStatus全部设置为no-check
 * 3. 如果选中的层级的checkedStatus是pre-check
 * 那当前层级的checkedStatus可能是pre-check，也可能是checked
 * 所以可以通过checkedList里来查找保存的状态就可以
 */
const onGetMoreData = (item: TDepartmentList): TDepartmentList[] => {
  return (item.children ?? []).reduce((acc, res) => {
    let status = "no-check",
      showInCheckedList = true;
    if (item.checkedStatus === "checked") {
      status = "checked";
      showInCheckedList = false;
    } else if (item.checkedStatus === "pre-check") {
      const idx = (checkedIds.value ?? []).findIndex((id) => res.id === id);
      status = idx === -1 ? "no-check" : checkedList.value[idx].checkedStatus;
    }
    return acc.concat({
      ...res,
      showInCheckedList,
      checkedStatus: status,
    });
  }, []);
};

const onMore = (item: TDepartmentList) => {
  isSelectAllBool.value = false;
  const moreList = onGetMoreData(item);
  onPushData(moreList);
  onChangeChooseAllStatus();
  /**
   * 1. 获取列表中checkedStatus为checked的项
   * 2. 然后添加到checkedList
   */
  onAddCheckdList(onGetCheckedList(moreList));
};

//多选情况下返回选择的用户对象列表
const onConfirm = (list) => {
  emit("onConfirm", toRaw(list));
};

const onPushData = (list: TDepartmentList[]) => onAddStack(list);

const onBack = () => {
  if (stack.value.length < 2) return;
  onSetParentCheckedStatus();
  onPopStack();
  onChangeChooseAllStatus();
};

const onClose = () => {
  emit("onClose");
  emit("update:show", false);
  popupVisible.value = false;
};

//设置默认选项
const onSetDefaultData = () => {
  if ((props.defaultData ?? []).length === 0) return;
  const filterData: TDepartmentList[] = props.defaultData.map((res) => {
    return { ...res, checkedStatus: "checked", showInCheckedList: true };
  });
  onAddCheckdList(filterData);
  const ids = filterData.map((res) => res.id);
  //修改当前列表的选中状态
  onChangeStack(onSetCheckedbyIds(originTreeData.value, ids));
  onChangeChooseAllStatus();
};

Store.sid = props.envData.sid;
Store.token = props.envData.token;
Store.corp_id = props.envData.corp_id;
Store.node_env = props.envData.node_env;
Store.card_resource = props.envData.card_resource;

watchEffect(() => {
  popupVisible.value = props.show;
});

onGetData().then((data: TDepartmentList[]) => {
  onPushData(data);
  originTreeData.value = data;
});

const setDefaultDataComputed = computed(() => {
  return originTreeData.value && props.defaultData;
});

watch(
  () => setDefaultDataComputed.value,
  () => onSetDefaultData(),
);
</script>

<style lang="scss" scoped>
.department-selector-wrap[data-weiling-mobile-ui-bc-department-selector-popup] {
  .popup-content {
    height: 100%;
    display: flex;
    flex-direction: column;
    background: #fff;

    .main-wrap {
      flex: 1;
      @extend %overflow-auto;
    }
  }
}
</style>
