<template>
  <div class="runtime-flow-page">
    <div class="runtime-toolbar">
      <div class="instance-state">
        实例状态：<span :class="instStatus">{{ stateMap[instStatus] || instStatus }}</span>
      </div>
      <el-button @click="centerView">居中</el-button>
      <el-button @click="fitGraph">适应屏幕</el-button>
      <el-button v-if="['RUNNING', 'PAUSED'].includes(instStatus)" type="danger" plain @click="stopFlow">停止</el-button>
      <el-button v-if="instStatus === 'RUNNING'" type="warning" plain @click="pauseFlow">暂停</el-button>
      <el-button v-if="instStatus === 'PAUSED'" type="success" plain @click="restartFlow">恢复</el-button>
    </div>

    <VueFlow
      id="runtime-flow"
      class="runtime-canvas"
      :nodes-draggable="false"
      :nodes-connectable="false"
      :edges-updatable="false"
      :elements-selectable="true"
      :delete-key-code="null"
      :min-zoom="0.1"
      :max-zoom="3"
      :zoom-on-double-click="false"
      @init="loadFlow"
      @pane-click="closeNodeDetails"
    >
      <template #node-runtime-node="nodeProps">
        <RuntimeNode v-bind="nodeProps" />
      </template>
      <template #node-runtime-group="nodeProps">
        <RuntimeGroup v-bind="nodeProps" />
      </template>
      <Background color="#d9dee8" :gap="24" :size="1" />
      <Controls position="bottom-right" :show-interactive="false" />
    </VueFlow>
  </div>
</template>

<script setup>
import { onUnmounted, ref } from "vue";
import { VueFlow, useVueFlow } from "@vue-flow/core";
import { Background } from "@vue-flow/background";
import { Controls } from "@vue-flow/controls";
import "@vue-flow/core/dist/style.css";
import "@vue-flow/core/dist/theme-default.css";
import "@vue-flow/controls/dist/style.css";
import RuntimeNode from "./RuntimeNode.vue";
import RuntimeGroup from "./RuntimeGroup.vue";
import { convertNodeRedToVueFlow, updateDerivedNodeStates } from "@/utils/convertNodeRedToVueFlow";
import { getFlowRuntimeLog } from "@/api/test/log";
import { pauseInst, resumeInst, stopInst } from "@/api/device/terminal";
import { ElMessage } from "element-plus";

const runtimeFlow = useVueFlow("runtime-flow");
const queryParams = new URLSearchParams(window.location.search);
const instId = queryParams.get("instId") || "";
const taskId = queryParams.get("taskId") || "";
const itemId = queryParams.get("itemId") || "03e0842c2fd7ab7575636a473aeefc89";

const instStatus = ref("RUNNING");
const stateMap = {
  SUCCESS: "已完成",
  RUNNING: "执行中",
  FAILED: "失败",
  PAUSED: "已暂停",
  STOPPED: "已终止",
};
let pollTimer = null;
let initialized = false;

const query = () => ({ instId, taskId, itemId });
const getProperties = (id) => runtimeFlow.findNode(id)?.data?.properties || {};
const setProperties = (id, patch) => {
  const node = runtimeFlow.findNode(id);
  if (!node) return;
  runtimeFlow.updateNodeData(id, {
    ...node.data,
    properties: { ...node.data.properties, ...patch },
  }, { replace: true });
};

const schedulePoll = () => {
  clearTimeout(pollTimer);
  pollTimer = window.setTimeout(getLog, 2000);
};

const getLog = async () => {
  const res = await getFlowRuntimeLog(query());
  if (res.code !== 200) return;
  const records = (res.data || []).filter((item) => item.nodeType);
  if (!records.length) {
    if (["RUNNING", "PAUSED"].includes(instStatus.value)) schedulePoll();
    return;
  }

  const states = new Map();
  records.forEach((item) => {
    if (["inject", "start"].includes(item.nodeType)) {
      states.set(item.nodeId, { state: "success", nodeType: item.nodeType, input: item.params });
      return;
    }
    const current = states.get(item.nodeId) || { nodeType: item.nodeType };
    if (item.paramsType === "INPUT") {
      current.state = item.instStatus.toLowerCase();
      current.input = item.instStatus === "FAILED" ? item.params : item.message;
    } else {
      current.state = item.instStatus === "RUNNING" ? "success" : item.instStatus.toLowerCase();
      current.output = item.instStatus === "FAILED" ? item.message : item.params;
    }
    states.set(item.nodeId, current);
  });

  states.forEach((value, id) => setProperties(id, value));
  updateDerivedNodeStates(runtimeFlow.getNodes.value, getProperties, setProperties);

  const last = records.at(-1);
  instStatus.value = last.instStatus || instStatus.value;
  if (last.nodeType !== "end" && !["FAILED", "STOPPED", "SUCCESS"].includes(last.instStatus)) schedulePoll();
};

const loadFlow = async () => {
  if (initialized) return;
  initialized = true;
  const { nodes, edges } = await convertNodeRedToVueFlow(itemId);
  runtimeFlow.setNodes(nodes);
  runtimeFlow.setEdges(edges);
  await nextTick();
  await runtimeFlow.fitView({ padding: 0.16, duration: 300 });
  await getLog();
};

const getInstDetail = async () => {
  const res = await getFlowRuntimeLog(query());
  const last = res.code === 200 ? (res.data || []).at(-1) : null;
  if (last?.instStatus) instStatus.value = last.instStatus;
};

const runControl = async (request, successMessage) => {
  const res = await request(instId);
  if (res.code === 200) {
    ElMessage.success(successMessage);
    await getInstDetail();
    if (["RUNNING", "PAUSED"].includes(instStatus.value)) schedulePoll();
  } else {
    ElMessage.error(res.msg);
  }
};

const stopFlow = () => runControl(stopInst, "停止成功");
const pauseFlow = () => runControl(pauseInst, "暂停成功");
const restartFlow = () => runControl(resumeInst, "恢复成功");
const fitGraph = () => runtimeFlow.fitView({ padding: 0.16, duration: 300 });
const centerView = () => runtimeFlow.fitView({ padding: 0.3, duration: 300 });
const closeNodeDetails = () => {
  const nowTime = Date.now();
  runtimeFlow.getNodes.value.forEach((node) => setProperties(node.id, { nowTime }));
};

onMounted(getInstDetail);
onUnmounted(() => clearTimeout(pollTimer));
</script>

<style scoped lang="scss">
.runtime-flow-page {
  width: 100%;
  height: 100%;
  min-height: 620px;
  position: relative;
  overflow: hidden;
  background: #f5f7fa;
}

.runtime-toolbar {
  position: absolute;
  z-index: 10;
  top: 16px;
  right: 16px;
  min-height: 48px;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 10px;
  border: 1px solid #e1e6ee;
  border-radius: 8px;
  background: rgba(255, 255, 255, 0.96);
  box-shadow: 0 8px 24px rgba(20, 33, 61, 0.1);

  :deep(.el-button + .el-button) { margin-left: 0; }
}

.instance-state {
  margin-right: 8px;
  color: #5a6472;
  font-size: 14px;
  font-weight: 600;
  .RUNNING, .PAUSED { color: #d48806; }
  .SUCCESS { color: #2b8a3e; }
  .FAILED, .STOPPED { color: #c92a2a; }
}

.runtime-canvas {
  width: 100%;
  height: 100%;
}
</style>
