<template>
  <!-- 根容器，用于定位和拖拽 -->
  <div class="dialog-property-grid-container" ref="targetRef" :style="style">
    <div class="property-box">
      <!-- 拖拽手柄 -->
      <div class="property-header" ref="handleRef">
        <span class="property-title">属性</span>
        <!-- 绑定点击事件触发 close 事件 -->
        <el-icon class="property-close" @click="handleClose"><Close /></el-icon>
      </div>
      <div class="property-table_wrapper">
        <el-table
          :data="internalData"
          :show-header="false"
          row-key="key"
          border
          height="100%"
          @cell-click="handleCellClick"
        >
          <!-- 属性名称列 -->
          <el-table-column
            prop="name"
            label="属性名称"
            width="180"
            class-name="property-name-column"
          >
            <template #default="{ row }">
              <div class="property-name-cell">{{ row.name }}</div>
            </template>
          </el-table-column>
          <!-- 属性值列 -->
          <el-table-column label="属性值" class-name="property-value-column">
            <template #default="{ row }">
              <div class="property-value-cell" :class="{ 'property-value-disabled': row.disabled }">
                <!-- 编辑模式 -->
                <div v-if="editingKey === row.key" class="editor-container">
                  <!-- 根据属性类型渲染不同的编辑器 -->
                  <!-- 选项类型编辑器 -->
                  <template v-if="row.type === 'select'">
                    <el-select
                      v-model="editingValue"
                      placeholder="请选择"
                      size="small"
                      @change="handleEditorChange(row, editingValue)"
                      @blur="handleSave(row, editingValue)"
                      ref="editorRef"
                    >
                      <el-option
                        v-for="item in row.options"
                        :key="item.value"
                        :label="item.label"
                        :value="item.value"
                      />
                    </el-select>
                  </template>
                  <!-- 颜色类型编辑器 -->
                  <template v-else-if="row.type === 'color'">
                    <el-color-picker
                      v-model="editingValue"
                      size="small"
                      @change="handleEditorChange(row, editingValue)"
                      @blur="handleSave(row, editingValue)"
                      ref="editorRef"
                    />
                  </template>
                  <!-- 数值类型 -->
                  <template v-else-if="row.type === 'number'">
                    <el-input-number
                      v-model="editingValue"
                      :controls="false"
                      size="small"
                      @change="handleEditorChange(row, editingValue)"
                      @blur="handleSave(row, editingValue)"
                      ref="editorRef"
                    />
                  </template>
                  <!-- 日期类型编辑器 -->
                  <template v-else-if="row.type === 'date'">
                    <el-date-picker
                      v-model="editingValue"
                      type="date"
                      placeholder="选择日期"
                      size="small"
                      @change="handleEditorChange(row, editingValue)"
                      @blur="handleSave(row, editingValue)"
                      ref="editorRef"
                      value-format="YYYY-MM-DD"
                    />
                  </template>
                  <!-- 日期时间类型编辑器 -->
                  <template v-else-if="row.type === 'datetime'">
                    <el-date-picker
                      v-model="editingValue"
                      type="datetime"
                      placeholder="选择日期时间"
                      size="small"
                      @change="handleEditorChange(row, editingValue)"
                      @blur="handleSave(row, editingValue)"
                      ref="editorRef"
                      value-format="YYYY-MM-DD HH:mm:ss"
                    />
                  </template>
                  <template v-else>
                    <!-- 默认使用 el-input -->
                    <el-input
                      v-model="editingValue"
                      size="small"
                      @change="handleEditorChange(row, editingValue)"
                      @blur="handleSave(row, editingValue)"
                      @keyup.enter="handleSave(row, editingValue)"
                      ref="editorRef"
                    />
                  </template>
                </div>

                <!-- 显示模式 -->
                <div v-else class="display-container">
                  {{ getDisplayValue(row) }}
                </div>
              </div>
            </template>
          </el-table-column>
        </el-table>
      </div>
      <!-- 底部的保存按钮 -->
      <div class="property-footer">
        <!-- 绑定点击事件触发 save 事件 -->
        <el-button type="success" size="small" @click="handleSaveButtonClick">保 存</el-button>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref, watch, nextTick, onMounted } from 'vue';
import {
  ElTable,
  ElTableColumn,
  ElInput,
  ElInputNumber,
  ElSelect,
  ElOption,
  ElColorPicker,
  ElMessage,
  ElIcon,
  ElButton,
  ElDatePicker,
} from 'element-plus';
import { Close } from '@element-plus/icons-vue';
import { useDraggable, useElementBounding, useWindowSize } from '@vueuse/core';
import { parseTime } from '@/utils/ruoyi';

const props = defineProps({
  /**
   * 属性配置数据
   * 数组，每个元素是一个属性对象
   * {
   *   key: string | number, // 唯一标识
   *   name: string, // 属性名称
   *   value: any, // 属性值
   *   type: 'text' | 'number' | 'select' | 'color' | 'date' | 'datetime', // 编辑器类型
   *   options?: Array<{ label: string, value: any }>, // type为select时需要
   *   checkMethod?: (newValue: any, property: object) => boolean | Promise<boolean>, // 检查方法
   *   disabled?: boolean, // 是否禁用该属性，禁用后不可编辑，默认为 false
   * }
   */
  data: {
    type: Array,
    default: () => []
  },
  /**
   * 保存按钮点击后的回调函数 (由外部 DialogPropertyGrid.js 传入)
   * 接收所有属性数据作为参数
   */
  onSaveCallback: {
      type: Function,
      // default: null
      default: () => () => {return true;} // 默认值为一个空函数
  }
});

console.log('初始化时props:', props);

// 触发事件：property-change (属性值改变), close (关闭按钮点击)
// save 事件将由 handleSaveButtonClick 内部直接调用 onSaveCallback 实现，不再 emit
const emit = defineEmits(['property-change', 'close']);

// 内部维护的数据副本，避免直接修改props
const internalData = ref([]);

// 当前正在编辑的属性的key
const editingKey = ref(null);
// 当前正在编辑的属性的值
const editingValue = ref(null);
// 编辑器组件的引用，用于focus
const editorRef = ref(null);

// 拖拽相关的 refs and state
const targetRef = ref(null); // 要拖拽的元素 (.dialog-property-grid-container)
const handleRef = ref(null); // 拖拽手柄 (.property-header)

// 获取窗口尺寸
const { width: windowWidth, height: windowHeight } = useWindowSize();
// 获取目标元素尺寸和位置
const { width: elementWidth, height: elementHeight } = useElementBounding(targetRef);

// 使用 useDraggable 实现拖拽
const { x, y, style } = useDraggable(targetRef, {
  handle: handleRef,
  initialValue: { x: 0, y: 0 }, // 初始值会在 mounted 后计算并设置
  onMove: ({ x, y }) => {
    // 计算边界
    const minX = 0;
    const minY = 0;
    // 使用 elementWidth.value 和 elementHeight.value 获取当前元素的尺寸
    const maxX = windowWidth.value - elementWidth.value;
    const maxY = windowHeight.value - elementHeight.value;

    // 限制在边界内
    const clampedX = Math.max(minX, Math.min(x, maxX));
    const clampedY = Math.max(minY, Math.min(y, maxY));

    // 返回限制后的位置
    return { x: clampedX, y: clampedY };
  },
  // 确保在拖拽时不会选择文本
  preventDefault: true,
  stopPropagation: true,
});

// 监听props.data变化，更新internalData
watch(
  () => props.data,
  (newData) => {
    // 简单的深拷贝，确保不影响原始数据
    internalData.value = newData ? newData.map(item => ({ ...item })) : [];
    // 当数据更新时，如果正在编辑的属性不在新数据中，退出编辑模式
    if (editingKey.value !== null && !internalData.value.some(item => item.key === editingKey.value)) {
        editingKey.value = null;
        editingValue.value = null;
    }
  },
  { immediate: true, deep: true }
);

// 在组件挂载后计算初始位置并设置 useDraggable 的初始值
onMounted(() => {
  nextTick(() => {
    // 确保元素已经渲染并获取到尺寸
    if (elementWidth.value > 0 && elementHeight.value > 0) {
      // 计算居中位置
      const centerX = (windowWidth.value - elementWidth.value) / 2;
      const centerY = (windowHeight.value - elementHeight.value) / 2;

      // 设置 useDraggable 的当前位置
      x.value = centerX;
      y.value = centerY;
    }
  });
});


/**
 * 处理单元格点击事件
 * @param {object} row - 当前行数据 (属性对象)
 * @param {object} column - 当前列对象
 * @param {object} cell - 当前单元格DOM元素
 * @param {Event} event - 事件对象
 */
const handleCellClick = (row, column, cell, event) => {
  // 如果属性被禁用，则不进行任何操作
  if (row.disabled) {
    return;
  }

  // 只处理属性值列的点击
  if (column.className.includes('property-value-column')) {
    // 如果当前有正在编辑的属性且不是当前点击的属性，先保存当前编辑的属性
    if (editingKey.value !== null && editingKey.value !== row.key) {
      const previousRow = internalData.value.find(item => item.key === editingKey.value);
      if (previousRow && !previousRow.disabled) {
         // 使用当前 editingValue 进行保存
        handleSave(previousRow, editingValue.value);
      }
    }

    // 开始编辑当前点击的属性
    startEditing(row);
  } else if (editingKey.value !== null) {
     // 如果点击了非属性值列，且有属性正在编辑，则保存当前编辑的属性
     const previousRow = internalData.value.find(item => item.key === editingKey.value);
      if (previousRow && !previousRow.disabled) {
         // 使用 current editingValue 进行保存
        handleSave(previousRow, editingValue.value);
      }
  }
};

/**
 * 开始编辑某个属性
 * @param {object} row - 要编辑的属性对象
 */
const startEditing = (row) => {
  // 如果属性被禁用，则不开始编辑
  if (row.disabled) {
      return;
  }

  // 如果已经是当前属性，则不重复开始编辑
  if (editingKey.value === row.key) {
      return;
  }

  editingKey.value = row.key;
  editingValue.value = row.value;

  // 等待DOM更新后聚焦编辑器
  nextTick(() => {
    // 根据编辑器类型尝试聚焦
    if (editorRef.value) {
       // 尝试访问内部 input 元素进行聚焦
       const inputElement = editorRef.value.$refs?.input || editorRef.value.$refs?.wrapper?.querySelector('input');
       if (inputElement && inputElement.focus) {
           inputElement.focus();
       } else if (editorRef.value.focus) { // 对于有 focus 方法的组件本身
           editorRef.value.focus();
       }
    }
  });
};

/**
 * 编辑器值变化时更新 editingValue
 * @param {object} row - 当前属性对象
 * @param {any} newValue - 编辑器的新值
 */
const handleEditorChange = (row, newValue) => {
  // 如果属性被禁用，不处理 change 事件
  if (row.disabled) {
      return;
  }

  // 对于select和color-picker，change事件通常意味着编辑完成，可以直接触发保存
  if (row.type === 'select' || row.type === 'color' || row.type === 'date' || row.type === 'datetime') {
     handleSave(row, newValue);
  } else {
     // 对于input和number，change/input更新editingValue，blur/enter触发保存
     editingValue.value = newValue;
  }
};


/**
 * 保存属性值（触发验证并更新 internalData），由单元格编辑触发
 * @param {object} row - 当前属性对象
 * @param {any} finalValue - 最终的值（来自 editingValue）
 */
const handleSave = async (row, finalValue) => {
  // 确保当前正在编辑的是这一行，避免重复保存或保存错误行
  if (editingKey.value !== row.key) {
      return;
  }

  // 如果属性被禁用，不保存（无需执行后续流程）
  if (row.disabled) {
      editingKey.value = null; // 退出编辑模式
      editingValue.value = null;
      return;
  }

  const property = internalData.value.find(item => item.key === row.key);
  if (!property) return; // 找不到属性，异常情况

  let isValid = true;
  let validationMessage = '';

  // 执行检查方法
  if (property.checkMethod) {
    try {
      // 检查方法可能是同步或异步的
      isValid = await property.checkMethod(finalValue, property);
      if (typeof isValid !== 'boolean') {
          console.error(`checkMethod for key "${row.key}" did not return a boolean.`);
          isValid = false; // 如果返回值不是boolean，视为验证失败
          validationMessage = `属性 "${row.name}" 的检查方法返回了非布尔值。`;
      }
    } catch (error) {
      console.error(`Error during checkMethod for key "${row.key}":`, error);
      isValid = false;
      validationMessage = `属性 "${row.name}" 检查时发生错误：${error.message}`;
    }
  }

  if (isValid) {
    // 验证成功，更新值
    property.value = finalValue;
    // 触发事件通知父组件值已改变 (实时变化)
    emit('property-change', row.key, finalValue, property);
    // 退出编辑模式
    editingKey.value = null;
    editingValue.value = null;
    return true; // 表示保存成功
  } else {
    // 验证失败
    ElMessage.error(validationMessage || `属性 "${row.name}" 的值无效。`);
    // 停留在编辑模式，让用户修改
    return false; // 表示保存失败
  }
};

/**
 * 处理保存按钮点击事件
 * 触发 save 事件，并传递所有属性数据
 */
const handleSaveButtonClick = async () => {
    // 如果当前有正在编辑的属性，先尝试保存它
    if (editingKey.value !== null) {
        const currentRow = internalData.value.find(item => item.key === editingKey.value);
        if (currentRow && !currentRow.disabled) {
            // 使用当前 editingValue 进行保存，并等待其完成
            const saveSuccess = await handleSave(currentRow, editingValue.value);
            // 如果 handleSave 验证失败，则不触发 save 和 close
            if (!saveSuccess) {
                 return;
            }
        }
    }

    // 调用外部传入的保存回调，传递当前所有属性数据
    // 传递 internalData 的深拷贝，避免外部修改影响组件内部状态
    if (typeof props.onSaveCallback === 'function') {
        props.onSaveCallback(JSON.parse(JSON.stringify(internalData.value)));
    }

    // 触发 close 事件，通知外部关闭弹窗
    emit('close');
};

/**
 * 处理关闭按钮点击事件
 * 触发 close 事件
 */
const handleClose = () => {
    // 如果当前有正在编辑的属性，先退出编辑模式
    if (editingKey.value !== null) {
        editingKey.value = null;
        editingValue.value = null;
    }
    // 触发 close 事件, 通知外部关闭弹窗
    emit('close');
};


/**
 * 获取属性在显示模式下的展示值
 * 对于select类型，显示label；其他类型直接显示value
 * @param {object} row - 属性对象
 * @returns {string} - 显示的值
 */
const getDisplayValue = (row) => {
  if (row.type === 'select' && row.options) {
    const option = row.options.find(opt => opt.value === row.value);
    return option ? option.label : row.value; // 如果找不到匹配的option，显示原始值
  } else if (row.type === 'date' && row.value) { // 日期类型显示逻辑
    try {
      const date = new Date(row.value);
      if (!isNaN(date.getTime())) { // 检查是否是有效日期
        return parseTime(date, '{y}-{m}-{d}'); // 使用 parseTime 格式化日期
      }
    } catch (e) {
      console.error("Error formatting date for display:", e);
    }
    return row.value; // 格式化失败时返回原始值
  } else if (row.type === 'datetime' && row.value) { // 新增：日期时间类型显示逻辑
    try {
      const date = new Date(row.value);
      if (!isNaN(date.getTime())) { // 检查是否是有效日期时间
        return parseTime(date, '{y}-{m}-{d} {h}:{i}:{s}'); // 使用 parseTime 格式化日期时间
      }
    } catch (e) {
      console.error("Error formatting datetime for display:", e);
    }
    return row.value; // 格式化失败时返回原始值
  }
  // 对于其他类型，直接显示值，null或undefined显示空字符串
  return row.value !== null && row.value !== undefined ? row.value : '';
};

// 暴露 updateData 方法给外部 DialogPropertyGrid.js 调用
defineExpose({
    updateData(newData, newOnSaveCallback) {
        // 直接更新 props.data 会触发 watch 监听器更新 internalData
        // 但 props 是只读的，不能直接修改。
        // 更好的方式是让外部直接修改 data ref，或者通过一个内部方法来更新 internalData
        // 这里我们让外部直接调用 updateData 方法来更新 internalData 和 onSaveCallback
        internalData.value = newData ? newData.map(item => ({ ...item })) : [];
        // 更新保存回调
        // 注意：这里直接修改了 props.onSaveCallback，这在严格模式下是不允许的。
        // 更安全的做法是让外部传入一个新的回调，或者在 DialogPropertyGrid.js 中管理回调。
        // 为了简化，我们假设外部传入的回调是响应式的或者每次都传入新的。
        // 如果需要严格遵守 Vue 规则，应该在 DialogPropertyGrid.js 的 wrapperComponent 中管理回调。
        // 考虑到这里的场景是命令式调用，且组件生命周期由外部管理，直接更新 internalData 和回调是可行的。
        // 如果需要更新 props，应该在外部 wrapperComponent 中通过 ref 来传递 props。
        // 让我们调整一下，让外部 wrapperComponent 管理 data 和 onSaveCallback 的 ref，并传递给 PropertyGrid。
        // PropertyGrid 只需要 watch data prop。
        // onSaveCallback 也可以作为 prop 传递。
    }
});

// 重新思考：让 PropertyGrid 接收 data 和 onSaveCallback 作为 props 是最标准的做法。
// DialogPropertyGrid.js 的 wrapperComponent 负责维护 data 和 onSaveCallback 的 ref，并传递给 PropertyGrid。
// 当 show 被调用时，wrapperComponent 更新这些 ref，从而更新 PropertyGrid 的 props。
// PropertyGrid 内部 watch data prop。
// onSaveCallback prop 直接在 handleSaveButtonClick 中调用。
// close 事件仍然 emit，由 wrapperComponent 监听并清理。

// 移除 defineExpose({ updateData ... })
// 移除 props 中的 onSaveCallback 定义，改为在 emit('save') 后由外部处理。
// 恢复 emit('save')

</script>

<style lang="scss" scoped>
/* 根容器样式，用于定位和拖拽 */
.dialog-property-grid-container {
  position: fixed; /* 固定定位 */
  z-index: 1000; /* 确保在其他内容之上 */
  /* 初始位置由 useDraggable 计算并设置 */
  /* top: 50%; */
  /* left: 50%; */
  /* transform: translate(-50%, -50%); /* 居中 */
}

.property-box {
  width: 400px;
  height: 320px;
  background-color: rgba(7, 111, 111, 0.9); /* 稍微不透明一点 */
  display: flex;
  flex-direction: column;
  border-radius: 4px; /* 添加圆角 */
  overflow: hidden; /* 隐藏超出部分的圆角 */
  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1); /* 添加阴影 */
  /* 移除遮罩相关的样式 */
}

  .property-header {
    flex: none;
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 8px 12px;
    background-color: #076f6f;
    border-bottom: 1px solid #dcdfe6;
    color: #d3fff4;
    cursor: grab; /* 拖拽手柄鼠标样式 */

    &:active {
        cursor: grabbing; /* 拖拽中鼠标样式 */
    }

    .property-title {
        font-weight: bold;
    }

    .property-close {
      cursor: pointer;
      font-size: 18px;
      color: #d3fff4;
      transition: color 0.3s;

      &:hover {
        color: #ffffff; /* 悬停时变为白色 */
      }
    }
  }
  .property-table_wrapper {
    flex: auto;
    margin: 8px;
    height: 0; /* flex: auto 需要一个基础高度 */
    background-color: #fff; /* 表格区域背景色 */
    border-radius: 4px;
    overflow: hidden; /* 确保表格内容在容器内 */
  }
  .property-footer {
    flex: none; /* 不伸缩 */
    text-align: right;
    padding: 8px 20px; /* 调整内边距 */
    background-color: rgba(7, 111, 111, 0.9); /* 与头部背景色一致 */
  }


/* 可以添加一些样式来优化显示和编辑体验 */
/* ... (保留原有的表格和编辑器样式) ... */

/* 调整 Element Plus 组件在小尺寸下的样式 */
.editor-container .el-input,
.editor-container .el-input-number,
.editor-container .el-select,
.editor-container .el-color-picker,
.editor-container .el-color-picker {
  width: 100%; /* 使编辑器宽度填充父容器 */
}

/* 隐藏 el-input-number 的控制按钮 */
.editor-container .el-input-number.is-controls-right .el-input__wrapper {
    padding-right: 0;
    padding-left: 8px; /* 留一点左边距 */
}
.editor-container .el-input-number__controls {
    display: none;
}

/* 悬停效果 */
/* 注意：Element Plus 表格默认有悬停背景，这里可以覆盖或调整 */
.el-table__row:hover .property-value-cell {
    background-color: #ecf5ff; /* 悬停时浅蓝色背景 */
}

.el-table__row:hover .property-value-cell.property-value-disabled {
    cursor: not-allowed; /* 显示禁止图标 */
    background-color: transparent !important; /* 确保不显示默认的悬停背景 */
}

/* 正在编辑的单元格样式 */
.el-table__row .property-value-cell .editor-container {
    /* 可以添加一个边框或背景色来突出显示正在编辑的单元格 */
    /* outline: 1px solid var(--el-color-primary); */
    /* background-color: #ecf5ff; */
}

/* 调整 Element Plus 表格的背景色，使其与 property-table_wrapper 背景色一致 */
.property-table_wrapper .el-table {
    background-color: transparent; /* 使表格背景透明，显示 wrapper 的背景 */
}
/* 调整表格行的背景色，使其在非悬停时透明 */
.property-table_wrapper .el-table__row {
    background-color: transparent;
}
/* 调整单元格背景色，使其在非悬停时透明 */
.property-table_wrapper .el-table td.el-table__cell,
.property-table_wrapper .el-table th.el-table__cell.is-leaf {
    background-color: transparent;
}
</style>
