<template>
  <div class="full">
    <div class="header">
      <div class="label">
        <span v-if="isCreatePool">{{ $t('工况库.新增') }}</span
        ><span v-else>{{ $t('工况库.编辑') }}</span
        >{{ $t('工况库.工况清单库') }}：
      </div>
      <div class="content">
        <span size="large" type="success" v-if="isCreatePool"> {{ poolName }}</span>
        <span size="large" type="primary" v-else> {{ poolName }}</span>
      </div>
      <div class="legend-tooltip">
        <div class="legend-item">
          <span class="legend-color added"></span>
          <span class="legend-label">{{ $t('通用.新增') }}</span>
        </div>
        <div class="legend-item">
          <span class="legend-color updated"></span>
          <span class="legend-label">{{ $t('通用.编辑') }}</span>
        </div>
        <div class="legend-item">
          <span class="legend-color deleted"></span>
          <span class="legend-label">{{ $t('通用.删除') }}</span>
        </div>
      </div>
    </div>
    <div class="body">
      <loadCaseTable
        :editMode="false"
        ref="treeTableRef"
        readonly
        :tableName="TABLE_NAME.TASK_POOL"
        :data="mergedPreviewTree"
        :hasOperationColumn="false"
        :showCheckBox="false"
        :rowClassName="rowClassName"
      >
      </loadCaseTable>
    </div>
  </div>
</template>

<script setup lang="ts">
import { nextTick, onMounted, ref, watchEffect } from 'vue';
import loadCaseTable from '@/components/common/treeCaseTable/loadCaseTable.vue';
import type { VxeTablePropTypes } from 'vxe-table';
import { TABLE_NAME } from '@/utils/enum/tableName';

interface Props {
  data: any;
}

const props = withDefaults(defineProps<Props>(), {
  data: {},
});

enum PreviewAction {
  Added = 'added',
  Updated = 'updated',
  Deleted = 'deleted',
}

const poolName = ref();
const approveContents = ref<any>(null);

const mergedPreviewTree = ref<any>([]);
const isCreatePool = ref(false);

const buildMapById = (list: any[] = []) => {
  const map: Record<string, any> = {};
  const walk = (nodes: any[]) => {
    (nodes || []).forEach((n) => {
      if (n?.fakeId) map[n.fakeId] = n;
      if (n.children) walk(n.children);
    });
  };
  walk(list);
  return map;
};

const cloneNode = (node: any) => JSON.parse(JSON.stringify(node));

const collectDeletedNodes = (original: any[] = [], removeIds: string[] = []) => {
  const origMap = buildMapById(original);
  const parentMap: Record<string, string | null> = {};
  const childrenOrder: Record<string, string[]> = {};
  const rootOrder: string[] = [];

  const walk = (nodes: any[], parentId: string | null) => {
    (nodes || []).forEach((n: any) => {
      if (!n || !n.fakeId) return;
      const id = n.fakeId;
      if (parentId === null) rootOrder.push(id);
      parentMap[id] = parentId;
      childrenOrder[id] = (n.children || []).map((c: any) => c.fakeId).filter(Boolean);
      if (n.children) walk(n.children, id);
    });
  };
  walk(original, null);

  const removedSet = new Set(removeIds.filter(Boolean));
  const topRemoved = Array.from(removedSet).filter((id) => {
    let p = parentMap[id];
    while (p) {
      if (removedSet.has(p)) return false;
      p = parentMap[p];
    }
    return true;
  });

  const cloneAndMark = (node: any) => {
    const n = cloneNode(node);
    const markRec = (x: any) => {
      if (!x) return;
      delete x._X_ROW_KEY;
      delete x._X_ROW_CHILD;
      x._previewAction = PreviewAction.Deleted;
      if (x.children) x.children.forEach((c: any) => markRec(c));
    };
    markRec(n);
    return n;
  };

  const entries: { node: any; parentId: string | null; rootIndex: number; siblingIndex: number }[] =
    [];
  topRemoved.forEach((id) => {
    const node = origMap[id];
    if (!node) return;
    const parentId = parentMap[id] ?? null;
    const rootIndex = rootOrder.indexOf(id);
    const siblingIndex = parentId ? (childrenOrder[parentId] || []).indexOf(id) : rootIndex;
    entries.push({ node: cloneAndMark(node), parentId, rootIndex, siblingIndex });
  });

  entries.sort((a, b) => {
    const ai = a.rootIndex >= 0 ? a.rootIndex : 0;
    const bi = b.rootIndex >= 0 ? b.rootIndex : 0;
    return ai - bi;
  });

  return { entries, rootOrder, childrenOrder };
};

const rowClassName: VxeTablePropTypes.RowClassName<any> = ({ row }) => {
  if (!row) return '';
  if (isCreatePool.value) {
    return 'preview-added';
  }
  if (row._previewAction === PreviewAction.Added) {
    return 'preview-added';
  } else if (row._previewAction === PreviewAction.Updated) {
    return 'preview-updated';
  } else if (row._previewAction === PreviewAction.Deleted) {
    return 'preview-deleted';
  }
  return '';
};

const initPreviewData = () => {
  mergedPreviewTree.value = [];
  approveContents.value = JSON.parse(props.data?.approveContents || '{}');
  const approvePreviewInfo = approveContents.value?.approvePreviewInfo || {};
  const finalFullData = approvePreviewInfo.finalFullData || [];
  const originalFullData = approvePreviewInfo.originalFullData || [];
  const insertRecords = approvePreviewInfo.insertRecords || [];
  const updateRecords = approvePreviewInfo.updateRecords || [];
  const removeRecords = approvePreviewInfo.removeRecords || [];
  const previewData = cloneNode(finalFullData);

  const markTree = (nodes: any[]) => {
    (nodes || []).forEach((n) => {
      delete n._X_ROW_KEY;
      delete n._X_ROW_CHILD;
      if (!n) return;
      if ((insertRecords || []).some((x: any) => x.fakeId === n.fakeId)) {
        n._previewAction = PreviewAction.Added;
      } else if ((updateRecords || []).some((x: any) => x.fakeId === n.fakeId)) {
        n._previewAction = PreviewAction.Updated;
      }
      if (n.children) markTree(n.children);
    });
  };
  markTree(previewData);

  const removeIds = (removeRecords || []).map((r: any) => r.fakeId || r);
  const {
    entries: deletedEntries,
    rootOrder,
    childrenOrder,
  } = collectDeletedNodes(originalFullData, removeIds);

  const findNodeRef = (nodes: any[], id: string): any | null => {
    for (const n of nodes || []) {
      if (!n) continue;
      if (n.fakeId === id) return n;
      if (n.children) {
        const r = findNodeRef(n.children, id);
        if (r) return r;
      }
    }
    return null;
  };

  const existsInPreview = (id: string) => !!findNodeRef(previewData, id);

  deletedEntries.forEach(({ node, parentId, rootIndex, siblingIndex }) => {
    if (!node || !node.fakeId) return;
    if (existsInPreview(node.fakeId)) return;

    if (parentId && existsInPreview(parentId)) {
      const parentRef = findNodeRef(previewData, parentId);
      if (!parentRef.children) parentRef.children = [];
      const origSiblings = childrenOrder[parentId] || [];
      const beforeOrig = origSiblings.slice(0, Math.max(0, siblingIndex));
      const insertPos = beforeOrig.reduce((cnt, sid) => {
        return cnt + (parentRef.children.some((c: any) => c.fakeId === sid) ? 1 : 0);
      }, 0);
      parentRef.children.splice(insertPos, 0, node);
    } else {
      const beforeRoots = rootOrder.slice(0, Math.max(0, rootIndex));
      const insertPos = beforeRoots.reduce((cnt, rid) => {
        return cnt + (previewData.some((n: any) => n.fakeId === rid) ? 1 : 0);
      }, 0);
      previewData.splice(insertPos, 0, node);
    }
  });

  mergedPreviewTree.value = previewData;
  poolName.value = approveContents.value?.poolBrief?.poolName;
  isCreatePool.value = Boolean(approvePreviewInfo.isCreate);
  expandAllFun();
};
const treeTableRef = ref();
const getVxeRef = () => {
  return treeTableRef?.value?.loadcaseTableRef?.TreeTableRef?.treeTableRef;
};
const expandAllFun = () => {
  nextTick(() => {
    getVxeRef()?.setAllTreeExpand(true);
  });
};
onMounted(() => {
  if (props.data) {
    initPreviewData();
  }
});
watchEffect(() => {
  if (props.data) {
    initPreviewData();
  }
});
</script>
<style lang="scss" scoped>
.full {
  width: 100%;
  height: 100%;
  display: flex;
  flex-direction: column;
}

.header {
  height: 20px;
  display: flex;
  align-items: center;
  justify-content: flex-start;

  .label {
    font-weight: 600;
  }

  .content {
    margin-left: var(--padding-small);
  }

  .tip {
    margin-left: var(--padding-small);
    color: #999;
    cursor: pointer;
  }
}

.body {
  flex: 1;
  overflow: auto;
}

.empty {
  color: #999;
  font-size: 12px;
}

ul > li {
  margin-bottom: 6px;
}

:deep(.preview-added) {
  background-color: var(--el-color-success-light-7);
}

:deep(.preview-updated) {
  background-color: var(--el-color-primary-light-7);
}

:deep(.preview-deleted) {
  background-color: var(--el-color-danger-light-7);
}

.legend-tooltip {
  display: flex;
  flex-direction: row;
  gap: 20px;
  padding: 6px 8px;
  flex: 1;
  margin-left: auto;
  justify-content: flex-end;
}

.legend-item {
  display: flex;
  align-items: center;
  gap: 8px;
  white-space: nowrap;
}

.legend-color {
  width: 24px;
  height: 12px;
  border-radius: 2px;
  display: inline-block;
}

.legend-color.added {
  background-color: var(--el-color-success-light-7);
}

.legend-color.updated {
  background-color: var(--el-color-primary-light-7);
}

.legend-color.deleted {
  background-color: var(--el-color-danger-light-7);
}

.legend-label {
  font-size: 12px;
  color: var(--el-text-color-secondary);
}
</style>
