<template>
  <div v-loading="loading" class="formula-editor-container">
    <!-- 工具栏 -->
    <el-row :gutter="20">
      <el-col :span="8">
        <el-card class="toolbox variables">
          <template #header>
            <div class="card-header">
              <span>变量</span>
            </div>
          </template>
          <div class="element-group" @dragover.prevent @drop.prevent>
            <el-tooltip v-for="variable in variables" :key="variable.id" :content="variable.tooltip">
              <el-tag :key="variable.id" class="element-tag" draggable="true" @dragstart="handleDragStart($event, variable)">
                {{ variable.label }}
              </el-tag>
            </el-tooltip>
          </div>
        </el-card>
      </el-col>
      <el-col :span="8">
        <el-card class="toolbox operators">
          <template #header>
            <div class="card-header">
              <span>计算符与分隔符</span>
            </div>
          </template>
          <div class="element-group" @dragover.prevent @drop.prevent>
            <el-tooltip v-for="operator in operators" :key="operator.id" :content="operator.tooltip">
              <el-tag :key="operator.id" class="element-tag" type="success" draggable="true" @dragstart="handleDragStart($event, operator)">
                {{ operator.label }}
              </el-tag>
            </el-tooltip>
          </div>
        </el-card>
      </el-col>
      <el-col :span="8">
        <el-card class="toolbox manual-tags">
          <template #header>
            <div class="card-header">
              <span>手动变量</span>
              <el-button type="primary" size="small" v-if="showSaveFlag" @click="toggleInput">新增手动变量</el-button>
            </div>
          </template>
          <div class="element-group" @dragover.prevent @drop.prevent>
            <transition name="fade">
              <div v-if="showInput" class="manual-input-wrapper">
                <el-input
                  ref="manualInputRef"
                  v-model="newManualTag"
                  placeholder="请输入数字"
                  size="mini"
                  style="width: 80px"
                  @keyup.enter="addManualTag"
                  @blur="hideInput"
                />
              </div>
            </transition>
            <el-tag
              v-for="(manualTag, index) in manualTags"
              :key="`manual_${index}`"
              class="element-tag"
              type="warning"
              draggable="true"
              @dragstart="handleDragStart($event, { id: `manual_${index}`, label: manualTag, category: 'manual', type: 'warning' })"
            >
              {{ manualTag }}
            </el-tag>
          </div>
        </el-card>
      </el-col>
    </el-row>

    <!-- 公式编辑区域 -->
    <el-row :gutter="20">
      <el-col :span="24">
        <el-card class="editor formula-editor" style="height: 50vh">
          <template #header>
            <div class="card-header">
              <span>公式编辑器</span>
              <div class="common-formulas">
                <el-tooltip v-for="formula in commonFormulas" :key="formula.id" :content="formula.tooltip">
                  <el-tag :key="formula.id" class="element-tag" type="info" draggable="true" @dragstart="handleFormulaDragStart($event, formula)">
                    {{ formula.label }}
                  </el-tag>
                </el-tooltip>
                <el-button type="primary" v-if="showSaveFlag" size="small" @click="toggleManualInput">手动录入</el-button>
              </div>
            </div>
          </template>
          <draggable
            v-if="!showManualInput"
            v-model="formulaItems"
            item-key="uniqueId"
            tag="div"
            class="formula-area"
            @start="drag = true"
            @end="drag = false"
            @drop="handleDrop"
            @dragover.prevent
          >
            <template #item="{ element, index }">
              <el-tag
                :closable="hoveredIndex === index"
                :type="element.type"
                class="element-tag"
                @close="removeItem(index)"
                @mouseenter="hoveredIndex = index"
                @mouseleave="hoveredIndex = -1"
              >
                {{ element.label }}
              </el-tag>
            </template>
          </draggable>
          <el-input v-if="showManualInput" v-model="manualInput" type="textarea" :rows="10" @blur="handleManualInputBlur"></el-input>

          <template #footer>
            <div class="card-header">
              <span>编辑后的公式</span>
            </div>
            <div>
              <p v-if="formulaString">{{ formulaString }}</p>
              <p v-else>请拖入元素构建公式。</p>
            </div>
            <div v-if="formulaIsValid" style="color: green">公式有效</div>
            <div v-else style="color: red">公式无效，请检查。</div>
          </template>
        </el-card>
      </el-col>
    </el-row>
    <el-button type="primary" size="small" style="margin-top: 20px" v-if="showSaveFlag" @click="saveCalendar">保存</el-button>
  </div>
</template>

<script setup name="CalendarNodeForm" lang="ts">
import draggable from 'vuedraggable';
import * as math from 'mathjs';
import { getCalendarRulesDecisionTreeDetail, quryDecimalParms, saveCalendarParms } from '@/api/rule/definition/index';
import { commonFormulas, operators } from '@/api/rule/definition/Options';
import { Graph } from '@antv/x6';
import { reviver } from 'mathjs';
const loading = ref(false);
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const manualInputRef = ref<ElFormInstance>();
const showManualInput = ref(false);
const manualInput = ref('');

const variables = ref([]);
const props = defineProps({
  nodeData: Object,
  graphData: Graph,
  rulesId: Object,
  showSave: Boolean
});
const formData = ref({});
const nodeGraph = ref(Graph);
const fromRulesId = ref(null);

const manualTags = ref([]);
const newManualTag = ref('');
const showInput = ref(false);
const hoveredIndex = ref(-1);
const showSaveFlag = ref(true);

const formulaItems = ref<any[]>([]);
const drag = ref(false);

const formulaString = computed(() => {
  return formulaItems.value
    .map((item) => {
      if (item.category === 'variable') {
        return `{${item.fieldName}}`;
      } else if (item.category === 'formula') {
        return `${item.fieldName}`;
      } else if (item.category === 'manual') {
        return item.label.toString();
      } else {
        return item.label;
      }
    })
    .join(' ');
});

const formulaIsValid = computed(() => {
  try {
    const mathjsFormula = formulaString.value
      .replace(/\{(\w+)\}/g, '$1') // 移除大括号
      .replace(/\s+/g, ''); // 移除所有空格
    const sandbox = {};
    formulaItems.value.forEach((item) => {
      if (item.category === 'variable') {
        sandbox[item.fieldName] = 1; // 假设变量值为1，验证公式结构
      }
    });
    math.evaluate(mathjsFormula, sandbox);
    return true;
  } catch (error) {
    return false;
  }
});
onMounted(() => {
  fetchVariables();
});
async function fetchVariables() {
  try {
    const response = await quryDecimalParms(fromRulesId.value);
    variables.value = response.data.map((variable: any) => ({
      id: `var_${variable.fieldName}`,
      fieldName: variable.fieldName,
      label: variable.fieldDescription,
      tooltip: `{${variable.fieldName}}`,
      category: 'variable',
      type: 'primary'
    }));
  } catch (error) {

  }
}

function handleDragStart(event: DragEvent, element: any) {
  const uniqueId = `item_${Date.now()}_${element.id}`;
  event.dataTransfer?.setData('text/plain', JSON.stringify({ ...element, uniqueId, fromExternal: true }));
}

function handleFormulaDragStart(event: DragEvent, formula: any) {
  const uniqueId = `item_${Date.now()}_${formula.id}`;
  event.dataTransfer?.setData('text/plain', JSON.stringify({ ...formula, uniqueId, fromExternal: true }));
}

function handleDrop(event: DragEvent) {
  const data = event.dataTransfer?.getData('text/plain');
  if (data) {
    try {
      let element: any = JSON.parse(data);
      if (element.fromExternal) {
        formulaItems.value.push(element);
      }
    } catch (error) {

    }
  }
}

function removeItem(index) {
  formulaItems.value.splice(index, 1);
}

function toggleInput() {
  showInput.value = !showInput.value;
  if (showInput.value) {
    nextTick(() => {
      (manualInputRef.value as any).focus();
    });
  }
}

function hideInput() {
  showInput.value = false;
}

function addManualTag() {
  if (newManualTag.value) {
    const numericValue = Number(newManualTag.value);
    if (!isNaN(numericValue)) {
      if (!manualTags.value.includes(numericValue)) {
        manualTags.value.push(numericValue);
      }
      newManualTag.value = '';
      hideInput();
    } else {
      proxy?.$modal.msgError('请输入有效的数字。');
    }
  }
}
function toggleManualInput() {
  showManualInput.value = !showManualInput.value;
  if (showManualInput.value) {
    manualInput.value = formulaString.value;
  }
}

function handleManualInputBlur() {
  if (manualInput.value) {
    const parsedFormula = parseManualInput(manualInput.value);
    if (parsedFormula) {
      formulaItems.value = parsedFormula;
      showManualInput.value = false;
    } else {
      proxy?.$modal.msgError('无效的公式，请检查输入。');
    }
  } else {
    showManualInput.value = false;
  }
}

function parseManualInput(input) {
  const tokens = input.match(/\{(\w+)\}|sum|mean|max|min|abs|round|\d+|\+|-|\*|\/|\(|\)|,/g); // 匹配公式、分隔符和操作符
  if (!tokens) return null;

  const result: any[] = [];
  const tempManualTags: number[] = [];

  tokens.forEach((token, index) => {
    if (token.startsWith('{') && token.endsWith('}')) {
      const fieldName = token.slice(1, -1);
      const variable = variables.value.find((v) => v.fieldName === fieldName);
      if (variable) {
        result.push({ ...variable, uniqueId: `item_${Date.now()}_${index}`, fromExternal: true });
      } else {
        proxy?.$modal.msgError(`无效的变量: ${token}`);
        return null;
      }
    } else if (commonFormulas.value.find((f) => f.label === token.toUpperCase())) {
      const formula = commonFormulas.value.find((f) => f.label === token.toUpperCase());
      if (formula) {
        result.push({ ...formula, uniqueId: `item_${Date.now()}_${index}`, fromExternal: true });
      } else {
        proxy?.$modal.msgError(`无效的公式: ${token}`);
        return null;
      }
    } else if (['+', '-', '*', '/', '(', ')', ','].includes(token)) {
      const operator = operators.value.find((op) => op.label === token);
      if (operator) {
        result.push({ ...operator, uniqueId: `item_${Date.now()}_${index}`, fromExternal: true });
      } else {
        proxy?.$modal.msgError(`无效的操作符: ${token}`);
        return null;
      }
    } else {
      const numericValue = Number(token);
      if (!isNaN(numericValue)) {
        if (!tempManualTags.includes(numericValue)) {
          tempManualTags.push(numericValue);
        }
        result.push({
          id: `manual_${index}`,
          label: numericValue,
          category: 'manual',
          type: 'warning',
          uniqueId: `item_${Date.now()}_${index}`,
          fromExternal: true
        });
      } else {
        proxy?.$modal.msgError(`无效的输入: ${token}`);
        return null;
      }
    }
  });

  manualTags.value = [...new Set([...manualTags.value, ...tempManualTags])];
  return result;
}

function convertToJSON() {
  return JSON.stringify(formulaItems.value);
}

function loadFromJSON(json) {
  try {
    if (json !== null) {
      formulaItems.value = json;
    } else {
      formulaItems.value = null;
    }
  } catch (error) {

    proxy?.$modal.msgError('无效的JSON格式。');
  }
}

async function saveCalendar() {
  loading.value = true;
  const res = await saveCalendarParms(fromRulesId.value, 'calculation', formData.value.id, formulaString.value, convertToJSON());
  if (res.code === 200) {
    proxy?.$modal.msgSuccess('保存成功');
  } else {
    proxy?.$modal.msgError(res.msg);
  }
  loading.value = false;
}

async function updateFromProps() {
  loading.value = true;
  const { nodeData, graphData, rulesId, showSave } = props;
  formData.value = nodeData || {};
  (nodeGraph.value as unknown as Graph) = graphData;
  fromRulesId.value = rulesId;
  showSaveFlag.value = showSave;
  const res = await getCalendarRulesDecisionTreeDetail(fromRulesId.value, formData.value.id);
  if (res.code === 200) {
    loadFromJSON(res.data.nodeData);
  } else {
    proxy?.$modal.msgError(res.msg);
  }
  loading.value = false;
}

watch(formulaItems, () => {
  if (formulaItems.value != null && formulaItems.value.length > 0) {
    const lastItem = formulaItems.value[formulaItems.value.length - 1];
    if (lastItem.category === 'manual' && !manualTags.value.includes(lastItem.label)) {
      manualTags.value.push(lastItem.label);
    }
  }
});

// 使用深度监听来捕捉 props 内部属性的变化
watch(
  () => ({ nodeData: props.nodeData, graph: props.graphData, rulesId: props.rulesId, showSave: props.showSave}),
  ({ nodeData, graph, rulesId, showSave }) => {
    updateFromProps();
  },
  { deep: true, immediate: true } // 添加 immediate 选项以确保首次渲染时也执行监听器
);
</script>

<style scoped>
.formula-editor-container {
  padding: 20px;
}

.toolbox {
  margin-bottom: 20px;
}

.element-group {
  display: flex;
  flex-wrap: wrap;
  gap: 5px;
}

.editor {
  height: 50vh;
}

.formula-area {
  display: flex;
  flex-wrap: wrap;
  gap: 2px;
  padding: 10px;
  height: 150px;
  background-color: #f5f7fa;
  border: 1px dashed #ccc;
}

.card-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.common-formulas {
  margin-top: 10px;
  display: flex;
  gap: 5px;
}

.el-input {
  width: 100%;
  margin-top: 10px;
}

/* 统一 Tag 样式 */
.element-tag {
  margin: 2px;
}

/* 将关闭按钮放置在 Tag 的右上角 */
.el-tag .el-icon-close {
  position: absolute;
  top: -6px;
  right: -4px;
  display: none;
}

.el-tag:hover .el-icon-close {
  display: inline-block;
}

.fade-enter-active,
.fade-leave-active {
  transition: opacity 0.3s;
}

.fade-enter,
.fade-leave-to {
  opacity: 0;
}

.card-footer {
  padding: 10px;
  text-align: center;
  border-top: 1px solid #ccc;
}
</style>
