<template>
  <div class="relation-builder">
    <div class="w-full flex justify-between mb-10px" v-if="compact">
      <a-space :style="{ width: `calc(100% - ${isOperator ? '100' : '0'}px)`, marginBottom: '10px' }" wrap>
        <template v-for="(item, index) in items" :key="index">
          <a-input-number v-if="item.type === 'number'" v-model:value="item.value" style="width: 30px" placeholder="-" @blur="confirm" />
          <a-tag v-if="item.type === 'operand' || item.type === 'operator'" :color="tagColors[item.type]" class="expr-tag">
            {{ formatDisplay(item) }}
          </a-tag>
          <a-tag v-else-if="item.type === 'logic'" class="expr-tag">|</a-tag>
        </template>
      </a-space>
      <!-- <div class="flex flex-wrap" :style="{ width: `calc(100% - ${isOperator ? '100' : '0'}px)` }" wrap>
        <div v-for="(group, id) in splitedItems" :key="`temp${id}`" class="w-50% flex justify-start items-center mb-10px" compact>
          <template v-for="(item, index) in group" :key="index">
            <a-input-number v-if="item.type === 'number'" v-model:value="item.value" style="width: 30px" placeholder="-" @blur="confirm" />
            <span v-else-if="item.type === 'operand'" class="w-90px text-center">{{ formatDisplay(item) }}</span>
            <span v-else class="p-5px">{{ formatDisplay(item) }}</span>
          </template>
        </div>
      </div> -->
      <a-button v-if="isOperator" class="w-100px" type="primary" @click="enterAdvancedMode"> 高级编辑 </a-button>
    </div>
    <a-row v-else :gutter="8">
      <!-- 左侧：元素库 -->
      <a-col :span="12">
        <a-card title="元素库" size="small">
          <a-collapse class="relation-card" v-model:activeKey="activeKey" :bordered="false">
            <a-collapse-panel v-for="group in elementGroups" :key="group.key" :header="group.header">
              <div class="chip-container">
                <!-- @dragstart="onDragStart($event, item)" -->
                <div
                  v-for="item in group.items"
                  :key="item.value"
                  class="chip"
                  :class="`chip-${group.type}`"
                  draggable="true"
                  @click="appendItem(item)"
                >
                  {{ item.label }}
                </div>
              </div>
              <div class="extra-container">
                <div v-for="item in group.extra" :key="item.type" class="mt-8px">
                  <a-input-number v-model:value="item.value" :defaultValue="0">
                    <template #addonAfter>
                      <!-- @dragstart="onDragStart($event, item)" -->
                      <span style="cursor: pointer" draggable="true" @click="appendItem(item)"> 追加 </span>
                    </template>
                  </a-input-number>
                </div>
              </div>
            </a-collapse-panel>
          </a-collapse>
          <template #actions>
            <div class="relation-card-footer">
              <a-typography-text class="pt-6px pb-6px" type="secondary"> <InfoCircleOutlined /> 点击追加元素 </a-typography-text>
            </div>
          </template>
        </a-card>
      </a-col>

      <!-- 中间：画布 -->
      <a-col :span="12">
        <a-card title="表达式画布" size="small">
          <template #extra>
            <a-tooltip title="清空">
              <a-button size="small" danger @click="clearCanvas">
                <DeleteOutlined />
              </a-button>
            </a-tooltip>
          </template>

          <div class="relation-card">
            <!-- :class="{ 'drag-over': isDragOver }" @dragover.prevent="onDragOver" @dragleave="onDragLeave"  @drop="onDrop"-->
            <div class="canvas-container">
              <a-empty v-if="!items.length" description="从左侧点击或拖拽元素" />
              <div v-else class="expression-list">
                <a-tag v-for="(item, index) in items" :key="index" :color="tagColors[item.type]" class="expr-tag" closable @close="removeItem(index)">
                  <span class="mr-4px">{{ formatDisplay(item) }}</span>
                </a-tag>
              </div>
            </div>

            <a-divider style="margin: 12px 0" />
            <a-space direction="vertical" style="width: 100%" :size="16">
              <a-typography-text strong>当前表达式</a-typography-text>
              <span>{{ expressionString }}</span>
              <a-alert v-if="errorMessage" :message="errorMessage" type="error" show-icon closable @close="errorMessage = ''" />

              <div>
                <a-typography-text strong>快速模板</a-typography-text>
                <a-input-group compact>
                  <a-select v-model:value="selectedTemplate" :options="templateOptions" style="width: calc(100% - 100px)" />
                  <a-button class="w-100px" type="primary" @click="applyTemplate">应用模板</a-button>
                </a-input-group>
              </div>

              <div>
                <a-typography-text strong>输入表达式</a-typography-text>
                <a-input-group compact>
                  <a-input v-model:value="inputString" style="width: calc(100% - 100px)" placeholder="例如: CO > 0 && CO2 > 0" allow-clear />
                  <a-button class="w-100px" type="primary" @click="applyManualInput"> 应用到画布 </a-button>
                </a-input-group>
              </div>
            </a-space>
          </div>

          <template #actions>
            <div class="relation-card-footer" style="text-align: right">
              <a-button class="mr-10px" @click="backToCompact">普通模式</a-button>
              <a-button class="mr-10px" @click="reset">重置</a-button>
              <a-button class="mr-12px" type="primary" @click="confirm">提交</a-button>
            </div>
          </template>
        </a-card>
      </a-col>
    </a-row>
  </div>
</template>

<script lang="ts" setup>
  import { ref, computed, watch, h } from 'vue';
  import { cloneDeep } from 'lodash-es';
  import { message, Modal } from 'ant-design-vue';
  import { DeleteOutlined } from '@ant-design/icons-vue';

  // 类型定义
  interface Item {
    type: 'operand' | 'operator' | 'logic' | 'number' | 'leftParen' | 'rightParen';
    value: string;
    label?: string;
  }

  interface ElementGroup {
    key: string;
    header: string;
    type: string;
    items: Item[];
    extra: Item[];
  }

  // 常量配置
  const isOperator = ref(false);
  const activeKey = ref<string[]>(['gas', 'operator', 'logic', 'number', 'paren']);

  const templateOptions = ref([
    { label: '压差预警1', value: '20<=sourcePressureChange && sourcePressureChange<=40' },
    { label: '压差预警2', value: '40<sourcePressureChange && sourcePressureChange<=60' },
    { label: '压差预警3', value: '60<sourcePressureChange && sourcePressureChange<=80' },
    { label: '压差预警4', value: '80<sourcePressureChange' },
    { label: '火灾预警1', value: '((coRzl<=20||coZf<=0.5*coAvg)&&coVal<=10)||o2Val<=5&&temperatureDifference<2&&co2Val<0.5' },
    {
      label: '火灾预警2',
      value:
        '((coRzl>20&&coRzl<=50)||(0.5*coAvg<coZf&&coZf<=coAvg)||(coVal>10&&coVal<=50)||(temperatureDifference>=2&&temperatureDifference<=4))&&co2Val<0.5',
    },
    {
      label: '火灾预警3',
      value:
        '((coRzl>50&&coRzl<=100)||(coAvg<coZf&&coZf<=2*coAvg)||(coVal>=50&&coVal<=100)||(temperatureDifference>4&&temperatureDifference<=10))&&co2Val<0.5',
    },
    { label: '火灾预警4', value: 'coRzl>100||2*coAvg<coZf||coVal>100||temperatureDifference>10||(co2Val>=0.5&&co2Trend)' },
    { label: '闭外火灾预警1', value: 'temperatureDifference<2||ch4Val<0.5||coVal<5||o2Val<20' },
    { label: '闭外火灾预警2', value: 'temperatureDifference>=2&&temperatureDifference<=4||ch4Val>=0.5&&ch4Val<=1||coVal>=5&&coVal<10' },
    {
      label: '闭外火灾预警3',
      value: 'temperatureDifference>4&&temperatureDifference<=10&&temperature>=26||ch4Val>=1&&ch4Val<1.5||coVal>=10&&coVal<24||c2h4Val>0&&c2h2Val==0',
    },
    { label: '闭外火灾预警4', value: 'temperatureDifference>10&&temperature>=30||ch4Val>=1.5&&ch4Val<2||coVal>=24||c2h2Val>0' },
    {
      label: 'OPEN',
      value:
        '(temperature<30||-3<temperature-fireAirTemperature&&temperature-fireAirTemperature<3)&&o2Val<5&&c2h4Val<0.001&&c2h2Val<0.001&&coVal<0.001&&(temperature<25||-3<temperature-fireWaterTemperature&&temperature-fireWaterTemperature<3)&&stableDays>30',
    },
  ]);

  const elementGroups: ElementGroup[] = [
    {
      key: 'gas',
      header: '监测变量',
      type: 'operand',
      items: [
        { type: 'operand', value: 'sourcePressureChange', label: '压差变化' },
        { type: 'operand', value: 'coRzl', label: 'CO日增率' },
        { type: 'operand', value: 'coZf', label: 'CO增幅' },
        { type: 'operand', value: 'coAvg', label: 'CO平均值' },
        { type: 'operand', value: 'coVal', label: 'CO值' },
        { type: 'operand', value: 'co2Val', label: 'CO2值' },
        { type: 'operand', value: 'co2Trend', label: 'CO2存在上升趋势' },
        { type: 'operand', value: 'o2Val', label: 'O2值' },
        { type: 'operand', value: 'ch4Val', label: 'CH4值' },
        { type: 'operand', value: 'c2h4Val', label: 'C2H4值' },
        { type: 'operand', value: 'c2h2Val', label: 'C2H2值' },
        { type: 'operand', value: 'temperature', label: '温度' },
        { type: 'operand', value: 'fireAirTemperature', label: '气温' },
        { type: 'operand', value: 'fireWaterTemperature', label: '水温' },
        { type: 'operand', value: 'temperatureDifference', label: '温差' },
        { type: 'operand', value: 'stableDays', label: '稳定天数' },
      ],
      extra: [],
    },
    {
      key: 'operator',
      header: '计算符',
      type: 'operator',
      items: [
        { type: 'operator', value: '>', label: '>' },
        { type: 'operator', value: '>=', label: '≥' },
        { type: 'operator', value: '<', label: '<' },
        { type: 'operator', value: '<=', label: '≤' },
        { type: 'operator', value: '==', label: '=' },
        { type: 'operator', value: '+', label: '+' },
        { type: 'operator', value: '-', label: '-' },
        { type: 'operator', value: '*', label: '*' },
        { type: 'operator', value: '/', label: '/' },
      ],
      extra: [],
    },
    {
      key: 'logic',
      header: '逻辑符',
      type: 'logic',
      items: [
        { type: 'logic', value: '&&', label: '且' },
        { type: 'logic', value: '||', label: '或' },
      ],
      extra: [],
    },
    {
      key: 'paren',
      header: '括号',
      type: 'paren',
      items: [
        { type: 'leftParen', value: '(', label: '(' },
        { type: 'rightParen', value: ')', label: ')' },
      ],
      extra: [],
    },
    {
      key: 'number',
      header: '数值',
      type: 'number',
      items: [
        { type: 'number', value: '0', label: '0' },
        { type: 'number', value: '10', label: '10' },
        { type: 'number', value: '20', label: '20' },
        { type: 'number', value: '30', label: '30' },
        { type: 'number', value: '40', label: '40' },
        { type: 'number', value: '50', label: '50' },
        { type: 'number', value: '60', label: '60' },
        { type: 'number', value: '70', label: '70' },
        { type: 'number', value: '80', label: '80' },
        { type: 'number', value: '90', label: '90' },
        { type: 'number', value: '100', label: '100' },
      ],
      extra: [{ type: 'number', value: '0', label: '追加自定义值' }],
    },
  ];

  const tagColors: Record<string, string> = {
    operand: 'blue',
    operator: 'green',
    logic: 'orange',
    number: 'purple',
    leftParen: 'default',
    rightParen: 'default',
  };

  const displayMap: Record<string, string> = {
    '&&': '且',
    '||': '或',
    '>=': '≥',
    '<=': '≤',
    '==': '=',
    sourcePressureChange: '压差变化',
    coRzl: 'CO日增率',
    coZf: 'CO增幅',
    coAvg: 'CO平均值',
    coVal: 'CO值',
    co2Val: 'CO2值',
    co2Trend: 'CO2存在上升趋势',
    o2Val: 'O2值',
    ch4Val: 'CH4值',
    c2h4Val: 'C2H4值',
    c2h2Val: 'C2H2值',
    temperature: '温度',
    fireAirTemperature: '气温',
    fireWaterTemperature: '水温',
    temperatureDifference: '温差',
    stableDays: '稳定天数',
  };

  // Props 和 Emits
  const props = defineProps<{ modelValue: string }>();
  const emit = defineEmits<{
    (e: 'update:modelValue', value: string): void;
    (e: 'change', value: string): void;
    (e: 'confirm', value: string): void;
  }>();

  // Reactive 状态
  const compact = ref<boolean>(true);
  const inputString = ref<string>('');
  const items = ref<Item[]>([]);
  const manualInput = ref<string>('');
  const errorMessage = ref<string>('');
  const selectedTemplate = ref<string>('');

  // Computed
  const expressionString = computed(() => items.value.map((i) => i.value).join(' '));
  // const splitedItems = computed(() => {
  //   return items.value.reduce(
  //     (arr: Item[][], ele) => {
  //       console.log('debug rr', arr, ele);
  //       if (ele.type === 'logic') {
  //         arr.push([]);
  //       }
  //       if (['operand', 'operator', 'number'].includes(ele.type)) {
  //         last(arr)!.push(ele);
  //       }
  //       return arr;
  //     },
  //     [[]]
  //   );
  // });

  // 工具函数
  const buildOperandSet = (): Set<string> => {
    const set = new Set<string>();
    elementGroups.forEach((group) => {
      if (group.type === 'operand') group.items.forEach((item) => set.add(item.value));
    });
    return set;
  };

  const formatDisplay = (item: Item): string => {
    if (item.type === 'number') return item.value;
    return displayMap[item.value] || item.value;
  };

  const parseExpression = (str: string): Item[] => {
    if (!str?.trim()) return [];
    const operandSet = buildOperandSet();
    const operandPattern = [...operandSet].map((v) => v.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')).join('|');
    const regex = new RegExp(`(${operandPattern}|==|>=|<=|&&|\\|\\||-?\\d+(?:\\.\\d+)?|[>+\\-*/<()])`, 'g');
    const rawTokens = str.match(regex) || [];
    const tokens = rawTokens.map((t) => t.trim()).filter((t) => t !== '');

    const items: Item[] = [];
    for (const token of tokens) {
      if (token === '(') {
        items.push({ type: 'leftParen', value: '(' });
        continue;
      }
      if (token === ')') {
        items.push({ type: 'rightParen', value: ')' });
        continue;
      }
      if (token === '&&' || token === '||') {
        items.push({ type: 'logic', value: token });
        continue;
      }
      if (['>', '>=', '<', '<=', '==', '+', '-', '*', '/'].includes(token)) {
        items.push({ type: 'operator', value: token });
        continue;
      }
      if (operandSet.has(token)) {
        items.push({ type: 'operand', value: token });
        continue;
      }
      if (/^-?\d+(?:\.\d+)?$/.test(token)) {
        items.push({ type: 'number', value: token });
        continue;
      }
    }

    return items;
  };

  // 初始化：将表达式字符串同步到画布与内部状态
  const initializeFromExpression = (expr: string): void => {
    const parsed = parseExpression(expr);
    items.value = parsed.length ? parsed : [];
    // 同步简易模式输入框（如果处于简易模式，显示最新表达式）
    inputString.value = expr;
    manualInput.value = ''; // 清空手动输入区
    errorMessage.value = '';
  };

  // 画布操作（追加、删除、清空、插入括号）
  const appendItem = (item: Item): void => {
    items.value.push(cloneDeep(item));
    syncAfterChange();
  };

  const removeItem = (index: number): void => {
    items.value.splice(index, 1);
    syncAfterChange();
  };

  const clearCanvas = (): void => {
    items.value = [];
    syncAfterChange();
  };

  // 画布变更后同步：更新简易模式输入框，并向上通知（但不提交）
  const syncAfterChange = (): void => {
    const expr = expressionString.value;
    inputString.value = expr;
  };

  // 拖拽逻辑
  // const isDragOver = ref<boolean>(false);
  // const onDragStart = (e: DragEvent, item: Item): void => {
  //   e.dataTransfer?.setData('text/plain', JSON.stringify(item));
  // };
  // const onDragOver = (e: DragEvent): void => {
  //   e.preventDefault();
  //   isDragOver.value = true;
  // };
  // const onDragLeave = (): void => {
  //   isDragOver.value = false;
  // };
  // const onDrop = (e: DragEvent): void => {
  //   e.preventDefault();
  //   isDragOver.value = false;
  //   try {
  //     const data = e.dataTransfer?.getData('text/plain');
  //     if (!data) return;
  //     const item: Item = JSON.parse(data);
  //     let droppedItem = cloneDeep(item);
  //     const container = e.currentTarget as HTMLElement;
  //     const tags = [...container.querySelectorAll('.expr-tag')] as HTMLElement[];
  //     let index = tags.length;
  //     const mouseX = e.clientX;
  //     for (let i = 0; i < tags.length; i++) {
  //       const rect = tags[i].getBoundingClientRect();
  //       if (mouseX < rect.left + rect.width / 2) {
  //         index = i;
  //         break;
  //       }
  //     }
  //     items.value.splice(index, 0, droppedItem);
  //     syncAfterChange();
  //   } catch {
  //     message.error('拖拽失败');
  //   }
  // };

  // 校验与优先级处理
  const validateExpression = (expr: string): { valid: boolean; message?: string } => {
    if (!expr?.trim()) return { valid: false, message: '表达式不能为空' };
    // 括号匹配
    let count = 0;
    for (const char of expr) {
      if (char === '(') count++;
      if (char === ')') count--;
      if (count < 0) return { valid: false, message: '括号不匹配' };
    }
    if (count !== 0) return { valid: false, message: '括号不匹配' };

    // 基本语法：检查操作符是否孤立（简单启发）
    const tokens = parseExpression(expr);
    if (tokens.length === 0) return { valid: false, message: '无法解析表达式' };
    for (let i = 0; i < tokens.length - 1; i++) {
      const cur = tokens[i];
      const next = tokens[i + 1];
      if (cur.type === 'operand' && (next.type === 'number' || next.type === 'operand')) {
        return { valid: false, message: `监测变量 ${cur.value} 位置可能不正确` };
      }
      if (cur.type === 'operator' && (next.type === 'operator' || next.type === 'logic' || next.type === 'rightParen')) {
        return { valid: false, message: `运算符 ${cur.value} 后缺少操作数` };
      }
      if (cur.type === 'logic' && (next.type === 'logic' || next.type === 'rightParen')) {
        return { valid: false, message: `逻辑符 ${cur.value} 位置可能不正确` };
      }
      if (cur.type === 'number' && (next.type === 'operand' || next.type === 'number')) {
        return { valid: false, message: `数值 ${cur.value} 位置可能不正确` };
      }
    }
    return { valid: true };
  };

  /**
   * 基于 items 为混合优先级表达式自动添加括号
   * 仅在最外层 || 分隔的段中，对未加括号且包含 && 的段添加括号
   */
  const addParenthesesForAnd = (_expr: string): string => {
    const tokens = items.value;
    if (!tokens.length) return _expr;

    // 1. 计算每个 token 在整体表达式中的嵌套深度
    const depths: number[] = [];
    let depth = 0;
    for (const t of tokens) {
      if (t.type === 'leftParen') {
        depths.push(depth);
        depth++;
      } else if (t.type === 'rightParen') {
        depth--;
        depths.push(depth);
      } else {
        depths.push(depth);
      }
    }

    // 2. 按最外层 (depth === 0) 的 || 切分成段
    const segments: Item[][] = [];
    let current: Item[] = [];
    for (let i = 0; i < tokens.length; i++) {
      if (tokens[i].type === 'logic' && tokens[i].value === '||' && depths[i] === 0) {
        if (current.length) segments.push(current);
        current = [];
      } else {
        current.push(tokens[i]);
      }
    }
    if (current.length) segments.push(current);

    // 3. 辅助：判断段是否已被一整对括号包裹
    const isEnclosed = (seg: Item[]): boolean => {
      if (seg.length < 2) return false;
      if (seg[0].type !== 'leftParen' || seg[seg.length - 1].type !== 'rightParen') return false;
      let bal = 0;
      for (let i = 1; i < seg.length - 1; i++) {
        if (seg[i].type === 'leftParen') bal++;
        else if (seg[i].type === 'rightParen') bal--;
        if (bal < 0) return false;
      }
      return bal === 0;
    };

    // 4. 辅助：判断段内是否存在最外层 (深度为0) 的 &&
    const hasTopLevelAnd = (seg: Item[]): boolean => {
      let d = 0;
      for (const t of seg) {
        if (t.type === 'leftParen') d++;
        else if (t.type === 'rightParen') d--;
        else if (t.type === 'logic' && t.value === '&&' && d === 0) return true;
      }
      return false;
    };

    // 5. 重建表达式，对需要的段添加括号
    return segments
      .map((seg) => {
        const str = seg.map((i) => i.value).join(' ');
        if (!isEnclosed(seg) && hasTopLevelAnd(seg)) {
          return `( ${str} )`;
        }
        return str;
      })
      .join(' || ');
  };

  /**
   * 判断 items 最外层（depth=0）是否同时存在 && 和 ||
   */
  const checkTopLevelMixed = (): boolean => {
    let depth = 0;
    let hasAnd = false;
    let hasOr = false;
    for (const item of items.value) {
      if (item.type === 'leftParen') {
        depth++;
      } else if (item.type === 'rightParen') {
        depth--;
      } else if (item.type === 'logic' && depth === 0) {
        if (item.value === '&&') hasAnd = true;
        else if (item.value === '||') hasOr = true;
      }
    }
    return hasAnd && hasOr;
  };

  // 提交逻辑
  const confirm = async (): Promise<void> => {
    const expr = expressionString.value;
    const validation = validateExpression(expr);
    if (!validation.valid) {
      errorMessage.value = validation.message || '表达式不合法';
      return;
    }
    errorMessage.value = '';

    // 基于 items 判断最外层是否存在未加括号的 && 与 || 混合
    const hasMixed = checkTopLevelMixed();
    let finalExpr = expr;

    if (hasMixed) {
      await new Promise<void>((resolve) => {
        const originalExpr = expr;
        const suggestedExpr = addParenthesesForAnd(expr);

        Modal.confirm({
          title: '运算符优先级提醒',
          content: h('div', [
            h('p', '表达式最外层同时包含“且(&&)”和“或(||)”，程序将优先计算“且(&&)”。'),
            h('p', { style: { margin: '8px 0' } }, [
              h('strong', '原表达式：'),
              h('code', { style: { backgroundColor: '#f5f5f5', padding: '2px 6px', borderRadius: '4px' } }, originalExpr),
            ]),
            h('p', { style: { margin: '8px 0' } }, [
              h('strong', '建议表达式：'),
              h('code', { style: { backgroundColor: '#f6ffed', padding: '2px 6px', borderRadius: '4px' } }, suggestedExpr),
            ]),
            h('p', '是否自动添加括号以明确优先级？'),
          ]),
          okText: '自动添加',
          cancelText: '保持原样',
          onOk: () => {
            finalExpr = suggestedExpr;
            // 同步到画布（仅当用户选择自动添加时才更新画布）
            const parsed = parseExpression(finalExpr);
            if (parsed.length) items.value = parsed;
            resolve();
          },
          onCancel: () => resolve(),
        });
      });
    }

    // 统一提交
    emit('update:modelValue', finalExpr);
    emit('change', finalExpr);
    emit('confirm', finalExpr);
    inputString.value = finalExpr;
    message.success('已更新');
  };

  // 重置
  const reset = (): void => {
    items.value = [];
    inputString.value = '';
    manualInput.value = '';
    errorMessage.value = '';
    emit('update:modelValue', '');
    emit('change', '');
  };

  // 进入高级模式
  const enterAdvancedMode = (): void => {
    // 将当前 modelValue 初始化到画布
    initializeFromExpression(props.modelValue);
    compact.value = false;
  };

  // 返回简易模式
  const backToCompact = async (): Promise<void> => {
    const currentExpr = expressionString.value;
    if (currentExpr === props.modelValue) {
      compact.value = true;
      return;
    }
    Modal.confirm({
      title: '确认返回',
      content: '画布内容已修改，是否应用变更？',
      okText: '应用',
      cancelText: '放弃',
      onOk: async () => {
        await confirm(); // 内部会校验、询问优先级、提交
        compact.value = true;
      },
      onCancel: () => {
        // 放弃变更：恢复为原始 modelValue
        initializeFromExpression(props.modelValue);
        compact.value = true;
      },
    });
  };

  const applyTemplate = (): void => {
    if (!selectedTemplate.value) return;
    initializeFromExpression(selectedTemplate.value);
    selectedTemplate.value = '';
    message.success('模板已应用');
  };

  const applyManualInput = (): void => {
    const expr = manualInput.value.trim();
    if (!expr) return;
    const validation = validateExpression(expr);
    if (!validation.valid) {
      errorMessage.value = validation.message || '表达式不合法';
      return;
    }
    initializeFromExpression(expr);
    errorMessage.value = '';
    message.success('已应用');
  };

  watch(
    () => props.modelValue,
    (newVal) => {
      if (newVal !== undefined) {
        inputString.value = newVal;
        // 如果当前处于高级模式，也同步画布
        // if (!compact.value) {
        const parsed = parseExpression(newVal);
        items.value = parsed.length ? parsed : [];
        // }
      }
    },
    { immediate: true }
  );

  // 暴露校验方法供表单 rules 使用
  defineExpose({ validate: () => validateExpression(props.modelValue) });
</script>

<style scoped lang="less">
  .relation-builder {
    // :deep(.ant-card) {
    //   height: 100%;
    // }
    // :deep(.ant-card-body) {
    //   height: calc(100% - 57px);
    //   overflow-y: auto;
    // }
    .relation-card {
      height: 680px;
      overflow-y: auto;
    }
    .relation-card-footer {
      height: 30px;
    }

    .chip-container {
      display: flex;
      flex-wrap: wrap;
      gap: 4px;
    }
    .chip {
      display: inline-block;
      padding: 4px 12px;
      border-radius: 4px;
      font-size: 14px;
      cursor: grab;
      user-select: none;
      border: 1px solid @border-color-base;
      background: @white;
      transition: all 0.2s;
      &:hover {
        // transform: translateY(-2px);
        box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
      }
      &:active {
        cursor: grabbing;
      }
      &.chip-operand {
        background: #e6f7ff;
        border-color: #91d5ff;
        color: #0050b3;
      }
      &.chip-operator {
        background: #f6ffed;
        border-color: #b7eb8f;
        color: #135200;
      }
      &.chip-logic {
        background: #fff7e6;
        border-color: #ffd591;
        color: #ad4e00;
      }
      &.chip-number {
        background: #f9f0ff;
        border-color: #d3adf7;
        color: #531dab;
      }
      &.chip-paren {
        background: #f0f0f0;
        border-color: #bfbfbf;
        font-weight: bold;
      }
    }

    .canvas-container {
      min-height: 200px;
      max-height: 400px;
      overflow-y: auto;
      border: 2px dashed #d9d9d9;
      border-radius: 8px;
      padding: 16px;
      background: #fafafa;
      transition: all 0.2s;
      &.drag-over {
        border-color: #1890ff;
        background: #e6f7ff;
      }
      .expression-list {
        display: flex;
        flex-wrap: wrap;
        align-items: center;
        gap: 8px;
      }
    }

    .expr-tag {
      font-size: 14px;
      padding: 6px 12px;
      margin: 0;
      // :deep(.anticon-close) {
      //   margin-left: 6px;
      //   &:hover {
      //     color: #ff4d4f;
      //   }
      // }
    }
  }
</style>
