<template>
  <div class="p-2">
    <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
      <div v-if="showSearch" v-loading="pageLoading" class="mb-[10px]">
        <div class="stencil-app">
          <!-- 工具栏 -->
          <div class="toolbar">
            <el-button size="small" icon="ZoomIn" @click="ruleExecution">执行</el-button>
            <el-button size="small" v-if="showSaveFlag" icon="ZoomIn" @click="formulaParsing">公式解析</el-button>
            <el-button size="small" v-if="showSaveFlag" icon="ZoomIn" @click="saveGraph">保存</el-button>
            <el-button size="small" v-if="!showSaveFlag && showAudit" icon="ZoomIn" @click="auidPass">审核通过</el-button>
            <el-popover :visible="unPassVisible" placement="top" :width="400">
              <p>请录入审核不通过原因</p>
              <div>
                <el-input v-model="unPassReason" placeholder="请录入审核不通过原因" type="textarea"></el-input>
              </div>
              <div style="text-align: right; margin-top: 20px">
                <el-button size="small" text @click="unPassVisible = false">取消</el-button>
                <el-button size="small" type="primary" @click="auidUnPass"> 确认 </el-button>
              </div>
              <template #reference>
                <el-button size="small" v-if="!showSaveFlag && showAudit" icon="ZoomIn" @click="unPassVisible = true">审核不通过</el-button>
              </template>
            </el-popover>
            <el-button size="small" icon="ZoomIn" @click="callBack">返回</el-button>
          </div>
          <!-- 画布区域 -->
          <div ref="stencilContainer" class="app-stencil"></div>
          <div ref="graphContainer" class="app-content">
            <!-- 只有当 graph 初始化完成后才渲染 NodeForm -->
            <node-form
              v-if="isGraphInitialized"
              v-model:visible="isFormVisible"
              :node-data="selectedNode"
              :graph-data="graph"
              :rules-id="rulesId"
              :show-save="showSaveFlag"
              class="app-draw"
              @update:node-label="updateNodeLabel"
            />
            <execution-rule
              v-if="isGraphInitialized"
              v-model:visible="isExecution"
              :graph-data="graph"
              :rules-id="rulesId"
              class="app-draw"
              @update:dorw-node-edges="DorwNodeEdges"
            />
          </div>
        </div>
      </div>
    </transition>
  </div>
</template>

<script setup name="RuleEDefinition" lang="ts">
import NodeForm from '@/components/RuleE/NodeForm.vue';
import ExecutionRule from '@/components/RuleE/ExecutionRule.vue';
import { CreateAntVX6setupGraph } from '@/api/rule/AntVCreate';
import { ref, onMounted, getCurrentInstance } from 'vue';
import { Graph } from '@antv/x6';
import { checkParsing, getRulseMap, parsingRules, ruleAudit, save } from '@/api/rule/definition';

const isGraphInitialized = ref(false); // 新增标识 graph 是否已初始化
const showSearch = ref(true);
const pageLoading = ref(false);
const { proxy } = getCurrentInstance() as any;
const graphContainer = ref(null);
const stencilContainer = ref(null);
const isFormVisible = ref(false);
const selectedNode = ref(null);
const graph = ref(Graph);
//规则执行控制器
const isExecution = ref(false);
//操作按钮控制器
const showSaveFlag = ref(true);
const unPassVisible = ref(false);
const showAudit = ref(false);
//路由参数
const routeParams = ref<Record<string, any>>({});
const rulesId = ref(null);
const unPassReason = ref('');
onMounted(() => {
  nextTick(async () => {
    routeParams.value = proxy.$route.query;
    await initPage();
  });
});
const initPage = async () => {
  pageLoading.value = true;
  rulesId.value = routeParams.value.rulesId;
  showSaveFlag.value = routeParams.value.showSaveFlag == 'true';
  showAudit.value = routeParams.value.showSaveFlag == 'false';
  graph.value = CreateAntVX6setupGraph(graphContainer.value, stencilContainer.value, isFormVisible, selectedNode, proxy, showSaveFlag.value);
  const res = await getRulseMap(routeParams.value.rulesId);
  if (res.data.rulseJson) {
    (graph.value as unknown as Graph).fromJSON(res.data.rulseJson);
  }
  isGraphInitialized.value = true;
  pageLoading.value = false;
};
const ruleExecution = async () => {
  const res = await checkParsing(rulesId.value);
  if (res.code == 200 && res.data == true) {
    isExecution.value = true;
  } else if (res.code == 200 && res.data == false) {
    proxy?.$modal.msgError('还未做公式解析，请先做公式解析');
  } else {
    proxy?.$modal.msgError(res.msg);
  }
};

const saveGraph = async () => {
  pageLoading.value = true;
  const json = (graph.value as any).toJSON();
  // 校验1: 检查是否存在“开始”和“结束”节点
  const nodes = (graph.value as any).getNodes();
  let startNodeFound = false;
  let endNodeFound = false;
  let startNodeId = null;
  nodes.forEach((node) => {
    if (node.data.type === 'start') {
      startNodeFound = true;
      startNodeId = node.id;
    }
    if (node.data.type === 'end') {
      endNodeFound = true;
    }
  });
  if (!startNodeFound || !endNodeFound) {
    proxy?.$modal.msgError('图中必须包含“开始”和“结束”节点');
    pageLoading.value = false;
    return;
  }
  // 校验2: 检查所有节点都有连线
  const edges = (graph.value as any).getEdges();
  const nodeIds = nodes.map((node) => node.id);
  const connectedNodes = new Set<string>();
  edges.forEach((edge) => {
    connectedNodes.add(edge.source);
    connectedNodes.add(edge.target);
  });
  // 提取 connectedNodes 中的 cell 属性
  const connectedNodeIds = new Set<string>();
  connectedNodes.forEach((node) => {
    connectedNodeIds.add((node as any).cell);
  });
  const unconnectedNodes = nodeIds.filter((id) => !connectedNodeIds.has(id));
  if (unconnectedNodes.length > 0) {
    proxy?.$modal.msgError('存在未连接的节点');
    pageLoading.value = false;
    return;
  }
  // 校验3: 确保从“开始”节点到“结束”节点的路径是完整的
  // 检查从“开始”节点到“结束”节点的路径完整性
  const checkEndFlag = checkEnd(startNodeId);
  if (!checkEndFlag) {
    proxy?.$modal.msgError('存在从“开始”连线终点不是“结束”节点的路径');
    pageLoading.value = false;
    return;
  }
  // 校验4: 检查是否存在循环处理的节点
  if (hasCycle(graph.value)) {
    proxy?.$modal.msgError('存在循环处理的节点');
    pageLoading.value = false;
    return;
  }
  // 如果所有校验通过，保存图数据
  const res = await save(routeParams.value.rulesId, json);
  if (res.code === 200) {
    proxy?.$modal.msgSuccess('保存成功');
  } else {
    proxy?.$modal.msgError('保存失败');
  }
  pageLoading.value = false;
};
//递归计算是否所有连线都会到end节点
const checkEnd = (startNodeId: string, visitedNodes: Set<string> = new Set()): boolean => {
  // 如果当前节点是“结束”节点，则返回true
  const startNode = (graph.value as any).getCellById(startNodeId);
  if (!startNode) {
    return false;
  }
  if (startNode.data.type === 'end') {
    return true;
  }
  // 标记当前节点为已访问
  visitedNodes.add(startNodeId);
  // 获取与当前节点相连的所有边
  const outgoingEdges = (graph.value as any).getOutgoingEdges(startNode);
  if (!outgoingEdges) {
    return false;
  }
  //  console.log('outgoingEdges.length:', outgoingEdges.length);
  if (outgoingEdges.length == 0) {
    return false;
  }
  // 对每个相连的边进行递归调用，检查是否可以到达“结束”节点
  for (let edge of outgoingEdges) {
    const targetNodeId = edge.target.cell;
    // 如果目标节点已经被访问过，跳过以避免循环引用
    if (visitedNodes.has(targetNodeId)) {
      continue;
    }
    if (!checkEnd(targetNodeId, visitedNodes)) {
      return false;
    }
  }
  // 如果没有任何路径通向“结束”节点，则返回false
  return true;
};

const updateNodeLabel = (nodeData: { id: string; label: string }) => {
  const node = (graph.value as unknown as Graph).getCellById(nodeData.id);
  if (node) {
    node.setData({ ...node.getData(), label: nodeData.label });
    node.attr('label/text', nodeData.label);
  }
};

const formulaParsing = async () => {
  pageLoading.value = true;
  const res = await parsingRules(rulesId.value);
  //  console.log(res);
  if (res.code === 200 && res.data === true) {
    proxy?.$modal.msgSuccess('保存成功');
  } else {
    proxy?.$modal.msgError('保存失败');
  }
  pageLoading.value = false;
};

// 检查图中是否存在环
const hasCycle = (g: Graph): boolean => {
  const visited = new Set<string>();
  const recursionStack = new Set<string>();
  const visit = (nodeId: string): boolean => {
    if (recursionStack.has(nodeId)) {
      return true; // 存在环
    }
    if (visited.has(nodeId)) {
      return false; // 已经访问过，没有环
    }
    visited.add(nodeId);
    recursionStack.add(nodeId);
    const node = g.getCellById(nodeId);
    const outgoingEdges = g.getOutgoingEdges(node);
    if (outgoingEdges) {
      for (let edge of outgoingEdges) {
        const targetNodeId = edge.getTargetCellId();
        if (visit(targetNodeId)) {
          return true;
        }
      }
    }
    recursionStack.delete(nodeId);
    return false;
  };
  const nodes = g.getNodes();
  for (let node of nodes) {
    const nodeId = node.id;
    if (visit(nodeId)) {
      return true;
    }
  }
  return false;
};

const DorwNodeEdge = (Node: Node<Node.Properties>, exeList: any) => {
  const Edges = (graph.value as unknown as Graph).getOutgoingEdges(Node);
  const edge = Edges.find((edge) => exeList.some((exe) => exe.hanldRule === edge.getTargetNode().id));
  if (!edge) {
    const endNode = (graph.value as unknown as Graph).getNodes().find((node) => node.getData()?.type === 'end');
    //如果存在Node和endNode相连的边，则标注红色
    const edges = (graph.value as unknown as Graph).getEdges();
    const edge1 = edges.find((edge) => edge.getTargetNode().id === endNode.id && edge.getSourceCell().id === Node.id);
    if (edge1) {
      edge1.attr({
        line: { stroke: '#b91818', strokeWidth: 3 }
      });
    }
  } else {
    edge.attr({
      line: { stroke: '#b91818', strokeWidth: 3 }
    });
    const NextNode = (graph.value as unknown as Graph).getCellById(edge.getTargetNode().id);
    DorwNodeEdge(NextNode, exeList);
  }
};

const DorwNodeEdges = (resultList) => {
  const exeList = resultList.exeList;
  const headNode = (graph.value as unknown as Graph).getNodes().find((node) => node.getData()?.type === 'start');
  DorwNodeEdge(headNode,exeList);
};

/**
 * 规则审核通过
 */
const auidPass = () => {
  ruleAudit(true, rulesId.value, '').then((res) => {
    if (res.code === 200) {
      proxy?.$modal.msgSuccess('审核通过');
      proxy.$tab.closePage(proxy.$route);
      proxy.$router.go(-1);
    } else {
      proxy?.$modal.msgError('审核失败');
    }
  });
};

/**
 * 规则审核不通过
 */
const auidUnPass = () => {
  ruleAudit(false, rulesId.value, unPassReason.value).then((res) => {
    if (res.code === 200) {
      proxy?.$modal.msgSuccess('操作成功');
      proxy.$tab.closePage(proxy.$route);
      proxy.$router.go(-1);
    } else {
      proxy?.$modal.msgError('审核失败');
    }
  });
};

const callBack = () => {
  proxy.$tab.closePage(proxy.$route);
  proxy.$router.go(-1);
};


</script>

<style lang="scss" scoped>
.stencil-app {
  display: flex;
  padding: 0;
  font-family: sans-serif;
  height: 90vh; /* 调整高度 */
}
.toolbar {
  position: absolute; /* 固定工具栏位置 */
  top: 10px; /* 距离顶部的距离 */
  left: 220px; /* 距离左侧的距离 */
  z-index: 10; /* 确保工具栏在画布上方 */
  display: flex;
  align-items: center;
  background: #fff;
  padding: 5px;
  border-radius: 4px;
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1);

  button {
    margin-right: 5px;
    padding: 6px 12px;
    border: none;
    background: #0078d7;
    color: #fff;
    border-radius: 4px;
    cursor: pointer;

    &:hover {
      background: #005bb5;
    }
  }
}

.app-stencil {
  position: relative;
  width: 200px;
  border: 1px solid #f0f0f0;
  background-color: #f8f8f8; /* 浅灰色背景 */
  padding: 10px; /* 内边距 */
  margin-right: 10px; /* 右侧外边距 */
  height: 100%;
}

.app-content {
  flex: 1;
  height: 100%;
  background-color: #ffffff; /* 白色背景 */
  border-left: 1px solid #f0f0f0; /* 左侧边框 */
  padding: 10px; /* 内边距 */
}

.app-draw {
  flex: 1;
  width: 400px;
}
</style>
