<template>
  <div class="node__container" ref="switchRef" @mouseleave="setNodeProperties">
    <NodeState :state="nodeOperatingStatus" :runtimes="runtimes" ref="nodeStateRef">
      <template #input>
        <JsonViewer :value="inputJsonData" copyable boxed sort theme="light" />
      </template>
      <template #output>
        <div v-if="nodeOperatingStatus != 'FAILED'">
          <JsonViewer :value="outputJsonData" copyable boxed sort theme="light" />
        </div>
        <div v-else>{{ errorInfoData }}</div>
      </template>
    </NodeState>
    <NodeTitle
      :icon="switchSvg"
      :nodeId="props.model.id"
      :nodeProperties="props.properties"
      :nodeName="props.properties?.name || '分支'"
      nodeDesc="连接多个下游分支，根据设定的条件按照顺序查找的方式来匹配运行的分支，如果匹配到某条件则只运行该条件对应的分支，否则继续匹配下一条件直至结束"
      @setNodeName="setNodeName"
    />
    <div class="condition_title_container">
      <div class="left">
        <div class="space"></div>
        <div class="title">所有条件</div>
      </div>
      <div class="right">
        <el-button
          :disabled="flowStore.disableForm"
          @click="addFormItem"
          class="addFormItem"
        >
          <el-icon :size="20"><Plus /></el-icon>
        </el-button>
      </div>
    </div>
    <div>
      <el-form
        :inline="true"
        :model="formData"
        :rules="rules"
        ref="dynamicForm"
        label-position="top"
        label-width="auto"
        :disabled="flowStore.disableForm"
      >
        <div
          class="condition"
          v-for="(params, index) in formData.nodeParams"
          :key="params.id"
          :id="params.id"
          :data-branch-anchor-id="params.id"
        >
          <div class="title__container">
            <div class="left">
              <div class="space"></div>
              <div class="title">{{ index === 0 ? "If" : "Else If" }}</div>
            </div>
            <div class="right">
              <el-button
                :disabled="flowStore.disableForm"
                circle
                size="small"
                @click="deleteFormItem(params.id, index)"
              >
                <el-icon :size="16"><Minus /></el-icon>
              </el-button>
            </div>
          </div>
          <div class="withOr">
            <div class="title">条件</div>
            <div>
              <el-select
                v-model="params.withOr"
                placeholder="Select"
                style="width: 240px"
                @focus="handleInputFocus"
                @click.stop
                @mousedown.stop
              >
                <el-option key="and" label="AND" value="and" />
                <el-option key="or" label="OR" value="or" />
              </el-select>
            </div>
          </div>
          <div class="form__container">
            <el-row v-for="(property, pIndex) in params.list" :key="`${params.id}-${pIndex}`">
              <el-form-item
                :label="pIndex === 0 ? '引用变量' : ''"
                :prop="`nodeParams.${index}.list.${pIndex}.nameType`"
              >
                <el-select
                  v-model="property.nameType"
                  @focus="handleInputFocus"
                  @keydown="handleInputKeydown"
                  @click.stop
                  @mousedown.stop
                  @change="handleTypeChange(index, pIndex)"
                >
                  <el-option label="引用" value="quote" />
                  <el-option label="输入" value="input" />
                </el-select>
                <el-form-item
                  v-if="property.nameType === 'input'"
                  :rules="[
                    {
                      required: true,
                      message: '请输入参数值',
                      trigger: 'blur',
                    },
                  ]"
                  :prop="`nodeParams.${index}.list.${pIndex}.name`"
                >
                  <el-input
                    v-model="property.name"
                    placeholder="请输入"
                    clearable
                    @focus="handleInputFocus"
                    @keydown="handleInputKeydown"
                    @click.stop
                    @mousedown.stop
                  />
                </el-form-item>
                <el-form-item
                  v-if="property.nameType === 'quote'"
                  :rules="[
                    {
                      required: true,
                      message: '请选择参数值',
                      trigger: 'blur',
                    },
                  ]"
                  :prop="`nodeParams.${index}.list.${pIndex}.nameQuote`"
                >
                  <el-cascader
                    v-model="property.nameQuote"
                    :options="quoteOptions"
                    placeholder="请选择"
                    :key="nameQuoteKey"
                    @visible-change="(val) => visibleChange(val, 'nameQuote', index, pIndex)"
                    @focus="handleInputFocus"
                    @keydown="handleInputKeydown"
                    @click.stop
                    @mousedown.stop
                  />
                </el-form-item>
              </el-form-item>
              <el-form-item
                :label="pIndex === 0 ? '选择条件' : ''"
                :prop="`nodeParams.${index}.list.${pIndex}.condition`"
                :rules="[
                  { required: true, message: '请输入变量名', trigger: 'blur' },
                ]"
              >
                <el-select
                  v-model="property.condition"
                  @focus="handleInputFocus"
                  @keydown="handleInputKeydown"
                  @click.stop
                  @mousedown.stop
                >
                  <el-option label="等于" value="equal" />
                  <el-option label="不等于" value="notEqualTo" />
                  <el-option label="为空" value="null" />
                  <el-option label="不为空" value="notNull" />
                  <el-option label="包含" value="include" />
                  <el-option label="不包含" value="notInclude" />
                  <el-option label="大于" value="greaterThan" />
                  <el-option label="大于等于" value="greaterThanOrEqual" />
                  <el-option label="小于" value="lessThan" />
                  <el-option label="小于等于" value="lessThanOrEqual" />
                </el-select>
              </el-form-item>
              <el-form-item
                :label="pIndex === 0 ? '比较值' : ''"
                :prop="`nodeParams.${index}.list.${pIndex}.type`"
              >
                <el-select
                  v-model="property.type"
                  @change="handleTypeChange(index, pIndex)"
                  @focus="handleInputFocus"
                  @keydown="handleInputKeydown"
                  @click.stop
                  @mousedown.stop
                >
                  <el-option label="引用" value="quote" />
                  <el-option label="输入" value="input" />
                </el-select>
                <el-form-item
                  v-if="property.type === 'input'"
                  :rules="[
                    {
                      required: true,
                      message: '请输入参数值',
                      trigger: 'blur',
                    },
                  ]"
                  :prop="`nodeParams.${index}.list.${pIndex}.input`"
                >
                  <el-input
                    v-model="property.input"
                    placeholder="请输入"
                    clearable
                    @focus="handleInputFocus"
                    @keydown="handleInputKeydown"
                    @click.stop
                    @mousedown.stop
                  />
                </el-form-item>
                <el-form-item
                  v-if="property.type === 'quote'"
                  :rules="[
                    {
                      required: true,
                      message: '请选择参数值',
                      trigger: 'blur',
                    },
                  ]"
                  :prop="`nodeParams.${index}.list.${pIndex}.quote`"
                >
                  <el-cascader
                    v-model="property.quote"
                    :options="quoteOptions"
                    placeholder="请选择"
                    @visible-change="(val) => visibleChange(val, 'quote', index, pIndex)"
                    @focus="handleInputFocus"
                    @keydown="handleInputKeydown"
                    @click.stop
                    @mousedown.stop
                  />
                </el-form-item>
              </el-form-item>
              <el-form-item :label="pIndex === 0 ? '操作' : ''">
                <el-button
                  :disabled="flowStore.disableForm"
                  circle
                  size="small"
                  @click="addListItem(index)"
                >
                  <el-icon :size="12"><Plus /></el-icon>
                </el-button>
                <el-button
                  :disabled="flowStore.disableForm"
                  circle
                  size="small"
                  @click="removeListItem(index, pIndex)"
                >
                  <el-icon :size="12"><Minus /></el-icon>
                </el-button>
              </el-form-item>
            </el-row>
          </div>
        </div>
      </el-form>
    </div>
    <div
      class="else"
      :id="''.concat(props.model.id, '_else')"
      :data-branch-anchor-id="''.concat(props.model.id, '_else')"
    >
      <div class="space"></div>
      <div class="title">Else</div>
    </div>
  </div>
</template>
<script setup>
import { nextTick, onMounted, onUnmounted, reactive, ref, toRaw, watch } from "vue";
import NodeTitle from "../../components/NodeTitle.vue";
import NodeState from "../../components/NodeState.vue";
import switchSvg from "../../icon/switch.svg";
import { v4 as randomUUID } from "uuid";
import { useFlowStore } from "@/store/modules/flow";
import { Plus, Minus } from "@element-plus/icons-vue";
import { getInput, removeSwitchEdge } from "@/utils/flow";
import { useFlowEvents } from "../../composables/useFlowEvents";

const props = defineProps({
  model: Object,
  graphModel: Object,
  properties: Object,
  nowTime: Number,
});

const emits = defineEmits([
  "addAnchor",
  "removeAnchor",
  "bindRef",
  "changeAnchor",
  "syncAnchors",
]);

const switchRef = ref();
const dynamicForm = ref();
const flowStore = useFlowStore();
const rules = reactive({});
const { onFlowEvent } = useFlowEvents();

const formData = reactive({
  nodeParams: props.properties?.conditions || [],
});

const addFormItem = () => {
  addCondition(0);
};

const deleteFormItem = (id, index) => {
  if (index === 0) {
    return;
  }
  formData.nodeParams.splice(index, 1);
  emits("removeAnchor", id);
  removeSwitchEdge(props.model.id, id);
  nextTick(() => {
    scheduleAnchorSync();
  });
};

const quoteOptions = ref([]);
const handleTypeChange = (pIndex, index) => {
  if (formData.nodeParams[pIndex].list[index].type === "input") {
    formData.nodeParams[pIndex].list[index].quote = "";
  } else {
    formData.nodeParams[pIndex].list[index].input = "";
    const option = getInput(props.model.id, false);
    if (option) {
      quoteOptions.value = option;
    }
  }
};

const addCondition = (height) => {
  const id = randomUUID().replace(/-/g, "");
  formData.nodeParams.push({
    id,
    withOr: "and",
    list: [
      {
        name: "",
        nameQuote: "",
        nameType: "input",
        type: "input",
        input: "",
        quote: "",
      },
    ],
  });
  emits("addAnchor", height, id);

  nextTick(() => {
    scheduleAnchorSync();
  });
};

const addListItem = (pIndex, cIndex) => {
  formData.nodeParams[pIndex].list.push({
    name: "",
    nameQuote: "",
    nameType: "input",
    type: "input",
    input: "",
    quote: "",
  });
  nextTick(() => {
    scheduleAnchorSync();
  });
};

const removeListItem = (pIndex, cIndex) => {
  if (cIndex === 0) {
    return;
  }
  formData.nodeParams[pIndex].list.splice(cIndex, 1);
  nextTick(() => {
    scheduleAnchorSync();
  });
};

let anchorSyncFrame = null;
let resizeObserver = null;

const syncAnchorPositions = () => {
  const root = switchRef.value;
  if (!root) return;
  const rootRect = root.getBoundingClientRect();
  const scale = root.offsetWidth > 0 ? rootRect.width / root.offsetWidth : 1;
  const positions = [...root.querySelectorAll("[data-branch-anchor-id]")].map((element) => {
    const rect = element.getBoundingClientRect();
    return {
      id: element.dataset.branchAnchorId,
      height: Math.round(((rect.top - rootRect.top + rect.height / 2) / scale) * 100) / 100,
    };
  });
  emits("syncAnchors", positions);
};

const scheduleAnchorSync = () => {
  if (anchorSyncFrame !== null) cancelAnimationFrame(anchorSyncFrame);
  anchorSyncFrame = requestAnimationFrame(() => {
    anchorSyncFrame = null;
    syncAnchorPositions();
  });
};

const setNodeProperties = async () => {
  try {
    const valid = await dynamicForm.value.validate();
    if (valid) {
      const data = toRaw(formData);
      const properties = lf.getProperties(props.model.id);
      lf.setProperties(props.model.id, {
        ...properties,
        ...data,
      });
      emits("contentChange");
    }
  } catch (error) {
    dynamicForm.value.clearValidate();
  }
};

const setNodeName = (name) => {
  const properties = lf.getProperties(props.model.id);
  lf.setProperties(props.model.id, {
    ...properties,
    name
  });
  emits("contentChange");
}

const visibleChange = async (value, type, index, pIndex) => {
  if (value) {
    const option = getInput(props.model.id);
    if (option) {
      quoteOptions.value = option;
      const currentValue = formData.nodeParams[index].list[pIndex][type]
      if (currentValue) {
        formData.nodeParams[index].list[pIndex][type] = null
        await nextTick();
        formData.nodeParams[index].list[pIndex][type] = currentValue;
      }
    }
  }
};

const nodeOperatingStatus = ref("NORMAL");
const runtimes = ref(0);
const inputJsonData = ref({});
const outputJsonData = ref({});
const errorInfoData = ref('');

watch(
  () => props.properties,
  () => {
    if (props.properties.nodeParams && props.properties.nodeParams.length > 0) {
      formData.nodeParams = props.properties.nodeParams;
    } else {
      if (formData.nodeParams.length === 0) {
        addCondition(100);
      }
    }
    nextTick(scheduleAnchorSync);
  },
  {
    immediate: true,
    deep: true,
  }
);

const nodeStateRef = ref(null);

const closePopover = () => {
  if (nodeStateRef.value) {
    nodeStateRef.value.closePopover();
  }
}

const isEditing = ref(false)
const handleInputFocus = (e) => {
  // 阻止事件冒泡到流程画布
  e.stopPropagation()
  e.preventDefault()
}


const handleInputKeydown = (e) => {
  // 阻止事件冒泡到流程节点，避免被画布快捷键拦截
  e.stopPropagation();
  // 可选：明确放行 Ctrl+V（增强兼容性）
  if ((e.ctrlKey || e.metaKey) && e.key === "v") {
    e.returnValue = true; // 允许默认粘贴行为
  }
}

onMounted(() => {
  emits("addAnchor", 0, "".concat(props.model.id, "_else"));

  emits("bindRef", dynamicForm.value);
  nextTick(() => {
    scheduleAnchorSync();
    resizeObserver = new ResizeObserver(scheduleAnchorSync);
    if (switchRef.value) resizeObserver.observe(switchRef.value);
  });

  onFlowEvent("changeNodeState", (data) => {
    if (data.nodeId === props.model.id) {
      nodeOperatingStatus.value = data.status;
      if (data.endTime && data.startTime) {
        runtimes.value = data.endTime - data.startTime;
      }
      let inputData = {};
      let output = {};
      errorInfoData.value = data?.message || ''
      try {
        inputData = JSON.parse(data.paramsIn) || {};
        output = JSON.parse(data.paramsOut) || {};
      } catch (error) {
        inputData = data.paramsIn || {};
        output = data.paramsOut || {};
      }
      inputJsonData.value = inputData;
      outputJsonData.value = output;

      emits("contentChange");
    }
  });

  onFlowEvent("contentChange", (data) => {
    if (data.id === props.model.id) {
      nodeOperatingStatus.value = "NORMAL";
      inputJsonData.value = {};
      outputJsonData.value = {};

      emits("contentChange");
    }
  });
});

onUnmounted(() => {
  resizeObserver?.disconnect();
  if (anchorSyncFrame !== null) cancelAnimationFrame(anchorSyncFrame);
});

defineExpose({ closePopover })
</script>
<style lang="scss" scoped>
.node__container {
  width: 100%;
  height: auto;
  background: #fff;
  padding: 16px;
  cursor: default;
  border: 1px solid #dfe4ec;
  border-left: 4px solid var(--node-accent, #b7791f);
  border-radius: 8px;
  box-shadow: 0 8px 24px rgba(31, 41, 55, 0.09);
  position: relative;
  box-sizing: border-box;
  transition: border-color 0.16s ease, box-shadow 0.16s ease;

  .condition_title_container {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-top: 14px;
    padding-top: 12px;
    border-top: 1px solid #e8ebf0;

    .left {
      display: flex;
      align-items: center;

      .space {
        width: 3px;
        height: 15px;
        background: var(--node-accent, #b7791f);
        border-radius: 3px;
      }

      .title {
        margin-left: 8px;
        color: #344054;
        font-size: 13px;
        font-weight: 650;
      }
    }

    .el-button {
      width: 28px;
      height: 28px;
      padding: 0;
      border-color: #dfe4ec;
      border-radius: 5px;
    }
  }

  .condition {
    width: 100%;
    height: auto;
    margin: 8px 0;
    padding: 11px 12px 5px;
    border: 1px solid #e4e8ef;
    border-radius: 7px;
    background-color: #f8fafc;
    box-sizing: border-box;
    position: relative;

    &::after {
      content: "";
      width: 17px;
      position: absolute;
      top: 50%;
      right: -18px;
      border-top: 1px solid var(--node-accent, #b7791f);
      pointer-events: none;
    }

    .title__container {
      display: flex;
      align-items: center;
      justify-content: space-between;

      .left {
        display: flex;
        align-items: center;

        .space {
          width: 3px;
          height: 14px;
          background: #3978c5;
          border-radius: 3px;
        }

        .title {
          margin-left: 8px;
          color: #344054;
          font-size: 12px;
          font-weight: 650;
        }
      }

      .el-button {
        width: 26px;
        height: 26px;
        padding: 0;
        border-radius: 5px;
      }
    }

    .withOr {
      display: flex;
      align-items: center;
      gap: 10px;
      margin: 9px 0 7px;

      .title {
        color: #7a8494;
        font-size: 12px;
      }

      :deep(.el-select) { width: 120px !important; }
    }

    :deep(.form__container) {
      .el-form-item {
        margin-right: 12px;
        margin-bottom: 8px;
      }

      .el-input {
        width: 105px;
      }

      .el-select {
        width: 105px;
      }

      .el-cascader {
        width: 105px;
      }
    }
  }

  .else {
    display: flex;
    align-items: center;
    min-height: 40px;
    padding: 8px 12px;
    border: 1px solid #e4e8ef;
    border-radius: 7px;
    background-color: #f8fafc;
    position: relative;

    &::after {
      content: "";
      width: 17px;
      position: absolute;
      top: 50%;
      right: -18px;
      border-top: 1px solid var(--node-accent, #b7791f);
      pointer-events: none;
    }

    .space {
      width: 3px;
      height: 14px;
      background: #697386;
      border-radius: 3px;
    }

    .title {
      margin-left: 8px;
      color: #344054;
      font-size: 12px;
      font-weight: 650;
    }
  }
}
</style>
