<template>
  <div
    :class="heightClass"
    class="w-full border rounded bg-white/5"
  >
    <ClientOnly>
      <div class="relative h-full">
        <button
          v-if="flowId"
          class="absolute z-10 top-2 right-2 bg-gray-700 hover:bg-gray-600 text-white text-xs px-2 py-1 rounded"
          type="button"
          title="Reset layout"
          @click="resetLayout()"
        >
          Reset
        </button>
        <VueFlow
          ref="vueFlowRef"
          v-model:nodes="internalNodes"
          v-model:edges="internalEdges"
          :fit-view-on-init="true"
          :min-zoom="0.05"
          :max-zoom="4"
          :default-viewport="{ zoom: 0.5 }"
          class="h-full w-full"
          @node-click="onNodeClick"
        >
          <template #node-flow-loop-group="{ data }">
            <div class="loop-group-node">
              <div class="loop-group-header">
                <UIcon
                  name="i-heroicons-arrow-path-rounded-square-20-solid"
                  class="size-3.5"
                />
                <span>{{ data?.title || "For Loop" }}</span>
                <UBadge
                  size="xs"
                  color="info"
                  variant="soft"
                  :label="data?.mode || 'parallel'"
                />
              </div>
              <div
                v-if="data?.over"
                class="loop-group-line"
                :title="String(data.over)"
              >
                over {{ data.over }}
              </div>
              <div
                v-if="data?.pipeline"
                class="loop-group-line"
                :title="String(data.pipeline)"
              >
                {{ data.pipeline }}
              </div>
            </div>
          </template>

          <template #node-flow-step="{ id, data }">
            <FlowNodeCard
              :id="id"
              :data="data"
              kind="step"
              @action="onAction"
            />
            <Handle
              type="target"
              :position="Position.Left"
            />
            <Handle
              type="source"
              :position="Position.Right"
            />
          </template>

          <template #node-flow-entry="{ id, data }">
            <FlowNodeCard
              :id="id"
              :data="data"
              kind="entry"
              @action="onAction"
            />
            <Handle
              type="source"
              :position="Position.Right"
            />
          </template>

          <template #node-flow-await="{ data }">
            <FlowAwaitNode
              :data="data"
            />
            <Handle
              type="target"
              :position="Position.Left"
            />
            <Handle
              type="source"
              :position="Position.Right"
            />
          </template>

          <Background
            v-if="showBackground"
            pattern-color="#888"
            :gap="12"
          />
          <Controls v-if="showControls" />
          <MiniMap v-if="showMiniMap" />
        </VueFlow>
      </div>
    </ClientOnly>
  </div>
</template>

<script setup>
import { computed, ref, watch, nextTick } from "#imports";
import { Position, Handle } from "@vue-flow/core";
import FlowNodeCard from "./NodeCard.vue";
import FlowAwaitNode from "./AwaitNode.vue";
import { useFlowLayout } from "../../composables/useFlowLayout";
const props = defineProps({
  flow: { type: null, required: false },
  heightClass: { type: String, required: false },
  showControls: { type: Boolean, required: false },
  showMiniMap: { type: Boolean, required: false },
  showBackground: { type: Boolean, required: false },
  stepStates: { type: Object, required: false },
  flowStatus: { type: String, required: false }
});
const heightClass = computed(() => props.heightClass || "h-80");
const emit = defineEmits(["nodeSelected", "nodeAction"]);
const flowId = computed(() => props.flow?.id);
const vueFlowRef = ref(null);
const { nodes, edges } = useFlowLayout(props);
const internalNodes = ref([]);
const internalEdges = ref([]);
function storageKey(flowId2) {
  return flowId2 ? `flow-layout:${flowId2}` : "flow-layout:unknown";
}
function applySavedPositions(nodesIn, flowId2) {
  if (!flowId2) return nodesIn;
  try {
    const raw = localStorage.getItem(storageKey(flowId2));
    if (!raw) return nodesIn;
    const saved = JSON.parse(raw);
    const byId = new Map(saved.map((s) => [s.id, s]));
    nodesIn.forEach((n) => {
      const s = byId.get(n.id);
      if (s) n.position = { x: s.x, y: s.y };
    });
  } catch {
  }
  return nodesIn;
}
function savePositionsDebounced(flowId2) {
  if (!flowId2) return;
  const payload = internalNodes.value.map(
    (n) => ({ id: n.id, x: n.position.x, y: n.position.y })
  );
  try {
    localStorage.setItem(storageKey(flowId2), JSON.stringify(payload));
  } catch {
  }
}
watch(() => props.flow, (f) => {
  if (!f) {
    internalNodes.value = [];
    internalEdges.value = [];
    return;
  }
  const builtNodes = nodes.value.map((n) => ({
    id: n.id,
    position: { ...n.position },
    data: { ...n.data },
    type: n.type,
    style: n.style,
    sourcePosition: n.sourcePosition,
    targetPosition: n.targetPosition
  }));
  const builtEdges = edges.value.map((e) => ({ id: e.id, source: e.source, target: e.target, label: e.label, animated: e.animated }));
  applySavedPositions(builtNodes, f.id);
  internalNodes.value = builtNodes;
  internalEdges.value = builtEdges;
  setTimeout(() => {
    if (vueFlowRef.value) {
      vueFlowRef.value.fitView({ padding: 0.2, duration: 200 });
    }
  }, 100);
}, { immediate: true, deep: false });
watch([() => props.stepStates, () => props.flowStatus], () => {
  if (!props.flow) return;
  const latestNodes = nodes.value;
  const positionMap = new Map(internalNodes.value.map((n) => [n.id, n.position]));
  const updatedNodes = latestNodes.map((n) => ({
    id: n.id,
    position: positionMap.get(n.id) || { ...n.position },
    data: { ...n.data },
    // Create new data object reference
    type: n.type,
    style: n.style,
    sourcePosition: n.sourcePosition,
    targetPosition: n.targetPosition
  }));
  internalNodes.value = updatedNodes;
  const builtEdges = edges.value.map((e) => ({ id: e.id, source: e.source, target: e.target, label: e.label, animated: e.animated }));
  internalEdges.value = builtEdges;
}, { deep: true });
watch(internalNodes, () => savePositionsDebounced(props.flow?.id), { deep: true });
function onNodeClick(evt) {
  const id = evt?.node?.id || evt?.id;
  if (id) emit("nodeSelected", { id });
}
function onAction(payload) {
  emit("nodeAction", payload);
}
function resetLayout() {
  const id = flowId.value;
  if (!id) return;
  try {
    localStorage.removeItem(storageKey(id));
  } catch {
  }
  const freshNodes = nodes.value.map((n) => ({
    id: n.id,
    position: { x: n.position.x, y: n.position.y },
    data: { ...n.data },
    type: n.type,
    style: n.style,
    sourcePosition: n.sourcePosition,
    targetPosition: n.targetPosition
  }));
  internalNodes.value = freshNodes;
  nextTick(() => {
    if (vueFlowRef.value) {
      vueFlowRef.value.fitView({
        padding: 0.2,
        includeHiddenNodes: false,
        duration: 300
      });
    }
  });
}
</script>

<style scoped>
:deep(.vue-flow__node){background:transparent;border:none;box-shadow:none;display:inline-block;overflow:visible;padding:0}:deep(.vue-flow__node-input){border:none}:deep(.vue-flow__handle){background-color:#94a3b8;border:2px solid #fff;height:8px;width:8px}.dark :deep(.vue-flow__handle){border-color:#1e293b}:deep(.vue-flow__handle-left){left:-4px}:deep(.vue-flow__handle-right){right:-4px}:deep(.vue-flow__node.selected),:deep(.vue-flow__node:focus){border:none;box-shadow:none;outline:none}.loop-group-node{background:rgba(236,254,255,.55);border:1px dashed rgba(14,116,144,.45);border-radius:12px;display:flex;flex-direction:column;gap:4px;height:100%;padding:10px 12px;width:100%}.dark .loop-group-node{background:rgba(8,47,73,.35);border-color:rgba(34,211,238,.4)}.loop-group-header{align-items:center;color:#0e7490;display:flex;font-size:11px;font-weight:600;gap:6px}.dark .loop-group-header{color:#67e8f9}.loop-group-line{color:#082f49;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:10px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dark .loop-group-line{color:#cffafe}
</style>
