<template>
  <div class="message-editor">
    <!-- Quill 编辑区 + 右下角发送按钮 容器 -->
    <div class="quill-wrap">
      <div ref="quillEditor" class="quill-container"></div>
      <!-- 右下角发送区域 -->
      <!-- 工具栏 -->
      <div class="editor-toolbar">
        <div class="editor-toolbar-left">
          <el-button
            type="text"
            icon="el-icon-folder-opened"
            @click="handleFileClick"
            title="文件"
          />
          <el-button
            type="text"
            icon="el-icon-scissors"
            @click="handleScreenshotClick"
            title="截屏"
          />
          <el-dropdown @command="handleFontSizeChange">
            <el-button type="text" style="font-size: 18px"> A </el-button>
            <el-dropdown-menu slot="dropdown">
              <el-dropdown-item
                v-for="size in [10, 11, 12, 13, 14]"
                :key="size"
                :command="String(size)"
                :class="{ 'font-size-selected': currentFontSize === size }"
              >
                {{ size }}
              </el-dropdown-item>
            </el-dropdown-menu>
          </el-dropdown>
          <el-dropdown
            ref="atDropdown"
            @command="handleAtSelect"
            v-if="currentChat.scene == 4 && groupInfo"
          >
            <el-button type="text" style="font-size: 16px">@</el-button>
            <el-dropdown-menu
              slot="dropdown"
              style="height: 200px; overflow-y: auto"
            >
              <el-dropdown-item
                :command="{ id: 0, name: 'all' }"
                style="
                  display: flex;
                  align-items: center;
                  justify-content: space-between;
                  padding-top: 8px;
                  padding-bottom: 8px;
                "
              >
                <div style="display: flex; align-items: center; gap: 8px">
                  <el-avatar :size="38" icon="el-icon-user-solid" />
                  所有人
                </div>
              </el-dropdown-item>
              <el-dropdown-item
                :command="item"
                v-for="item in groupInfo.user_list"
                :key="item.id"
                style="
                  display: flex;
                  align-items: center;
                  justify-content: space-between;
                  padding-top: 8px;
                  padding-bottom: 8px;
                "
              >
                <div style="display: flex; align-items: center; gap: 8px">
                  <el-avatar
                    :size="38"
                    :src="
                      $store.state.user.netConfig.MINIO_ENDPOINT_HTTPS +
                      item.avatar
                    "
                  />
                  {{ item.name }}
                </div>
                <div style="color: #8492a6">
                  {{ item.role_name }}
                </div>
              </el-dropdown-item>
            </el-dropdown-menu>
          </el-dropdown>
        </div>
        <div class="editor-toolbar-right">
          <el-button
            type="text"
            icon="el-icon-video-camera"
            @click="handleTeachingClick(1)"
            title="发起教学"
            v-if="currentChat.scene == ContactsScene.GROUP"
          />
          <el-button
            type="text"
            icon="el-icon-video-camera-solid"
            @click="handleTeachingClick(9)"
            title="发起会诊"
            v-if="currentChat.scene == ContactsScene.PRIVATE"
          />
          <el-button
            type="primary"
            size="mini"
            :loading="sending"
            @click="handleSendText"
          >
            发送
          </el-button>
          <el-dropdown @command="handleSendModeChange">
            <el-button type="text">
              {{ sendModeLabel }}<i class="el-icon-arrow-down el-icon--right" />
            </el-button>
            <el-dropdown-menu slot="dropdown">
              <el-dropdown-item command="enter">Enter发送</el-dropdown-item>
              <el-dropdown-item command="ctrlEnter">
                Ctrl+Enter发送
              </el-dropdown-item>
            </el-dropdown-menu>
          </el-dropdown>
        </div>
      </div>
    </div>
    <!-- 隐藏文件上传 -->
    <input
      ref="fileInput"
      type="file"
      style="display: none"
      accept="image/*,video/*,.doc,.docx,.xls,.xlsx,.ppt,.pptx,.pdf,.zip,.rar,.txt"
      @change="(e) => handleFileChange(e)"
    />
  </div>
</template>

<script>
import { mapGetters } from "vuex";
import Quill from "quill";
import "quill/dist/quill.core.css";
import "quill/dist/quill.snow.css";
import { sendPrivateMessage, sendMultiChatMessage } from "@/api/message";
import { uploadFile } from "@/utils/requestMinio";
import { takeScreenshot } from "@/utils/screenshot";
import {
  MessageType,
  ContactsScene,
  MinioPaths,
  MqttTopics,
} from "@/utils/constants";
import { meetingModes } from "@/api/videoCommunication";
export default {
  name: "MessageEditor",
  props: {
    groupInfo: Object,
  },

  data() {
    return {
      MessageType,
      ContactsScene,
      quill: null,
      currentRange: null,
      sending: false,
      maxFileSize: 100 * 1024 * 1024,
      sendMode: this.getSystemSendMode(),
      fontSizeMap: {
        10: "small",
        11: "small",
        12: false,
        13: "large",
        14: "large",
      },
      currentFontSize: 14,
      // 记录被@的用户
      selectedAtUsers: [],
      meetingModes: meetingModes(),
      // Quill初始化重试次数
      quillInitRetryCount: 0,
      // 存储编辑器中的文件信息
      editorFiles: [],
      maxQuillInitRetries: 20,
    };
  },

  computed: {
    ...mapGetters(["currentChat", "userInfo", "config"]),

    canSend() {
      const text = this.quill ? this.quill.getText().trim() : "";
      return text.length > 0 && this.currentChat && !this.sending;
    },

    sendModeLabel() {
      return this.sendMode === "enter" ? "Enter发送" : "Ctrl+Enter发送";
    },
  },

  mounted() {
    this.$nextTick(() => {
      this.initQuill();
    });
    document.addEventListener("keydown", this.handleGlobalKeydown);
    window.addEventListener(
      "systemSettingsChanged",
      this.handleSettingsChanged
    );
    this.loadSendModeFromSettings();
  },

  beforeDestroy() {
    if (this.quill) {
      this.quill = null;
    }
    document.removeEventListener("keydown", this.handleGlobalKeydown);
    window.removeEventListener(
      "systemSettingsChanged",
      this.handleSettingsChanged
    );
  },

  watch: {
    sendMode(newMode) {
      this.saveSendModeToSettings(newMode);
    },
  },

  methods: {
    getSystemSendMode() {
      try {
        const settings = localStorage.getItem("systemSettings");
        if (settings) {
          const parsed = JSON.parse(settings);
          if (parsed.basicForm && parsed.basicForm.sendKey) {
            const savedKey = parsed.basicForm.sendKey;
            if (savedKey === "Ctrl+Enter") {
              return "ctrlEnter";
            } else if (savedKey === "Enter") {
              return "enter";
            }
          }
        }
      } catch (e) {
        console.error("读取系统设置失败:", e);
      }
      return "ctrlEnter";
    },

    loadSendModeFromSettings() {
      const mode = this.getSystemSendMode();
      if (mode !== this.sendMode) {
        this.sendMode = mode;
        this.refreshQuillBindings();
      }
    },

    saveSendModeToSettings(mode) {
      try {
        const settings = localStorage.getItem("systemSettings");
        const parsed = settings ? JSON.parse(settings) : {};
        if (!parsed.basicForm) {
          parsed.basicForm = {};
        }
        parsed.basicForm.sendKey = mode === "ctrlEnter" ? "ctrl" : "enter";
        localStorage.setItem("systemSettings", JSON.stringify(parsed));
      } catch (e) {
        console.error("保存发送模式失败:", e);
      }
    },

    handleSettingsChanged(e) {
      if (e.detail && e.detail.settings) {
        this.loadSendModeFromSettings();
      }
    },

    // 初始化Quill
    initQuill() {
      const editorDom = this.$refs.quillEditor;
      if (!editorDom) {
        this.quillInitRetryCount++;
        if (this.quillInitRetryCount <= this.maxQuillInitRetries) {
          console.warn(
            `Quill container not found, retrying... (${this.quillInitRetryCount}/${this.maxQuillInitRetries})`
          );
          setTimeout(() => {
            this.initQuill();
          }, 100);
        } else {
          console.error("Quill container not found after maximum retries");
        }
        return;
      }

      this.quillInitRetryCount = 0;
      if (this.quill) return;

      // 初始化时注入键盘绑定
      this.quill = new Quill(editorDom, {
        theme: "snow",
        placeholder: "请输入消息...",
        modules: {
          toolbar: false,
          keyboard: {
            bindings: this.getQuillKeyBindings(), // 抽离绑定配置，支持动态更新
          },
        },
        readOnly: false,
      });

      const toolbar = this.quill.getModule("toolbar");
      if (toolbar.container) {
        toolbar.container.style.display = "none";
      }

      this.quill.on("selection-change", (range) => {
        this.currentRange = range;
      });

      this.quill.on("text-change", (delta, oldDelta, source) => {
        if (source === "user") {
          this.handleTextChange(delta);
        }
      });

      this.quill.root.addEventListener("paste", this.handlePaste, true);

      // ========= 删除原来这里的 keydown 监听，改用 bindings 控制 =========
    },
    // 根据当前 sendMode 返回 Quill 按键规则
    getQuillKeyBindings() {
      const self = this;
      if (this.sendMode === "enter") {
        // Enter发送模式：Enter=发送，Ctrl/Cmd+Enter=换行，Shift+Enter=换行
        return {
          enter: {
            key: "Enter",
            handler() {
              self.handleSendText();
            },
          },
          ctrlEnter: {
            key: "Enter",
            ctrlKey: true,
            metaKey: true,
            handler(range) {
              const quill = self.quill;
              quill.insertText(range.index, "\n");
              quill.setSelection(range.index + 1);
            },
          },
          shiftEnter: {
            key: "Enter",
            shiftKey: true,
            handler(range) {
              const quill = self.quill;
              quill.insertText(range.index, "\n");
              quill.setSelection(range.index + 1);
            },
          },
        };
      } else {
        // Ctrl+Enter发送模式：Enter=换行，Shift+Enter=换行，Ctrl/Cmd+Enter=发送
        return {
          enter: {
            key: "Enter",
            shiftKey: null,
            handler(range) {
              const quill = self.quill;
              quill.insertText(range.index, "\n");
              quill.setSelection(range.index + 1);
            },
          },
          shiftEnter: {
            key: "Enter",
            shiftKey: true,
            handler(range) {
              const quill = self.quill;
              quill.insertText(range.index, "\n");
              quill.setSelection(range.index + 1);
            },
          },
          ctrlEnter: {
            key: "Enter",
            ctrlKey: true,
            metaKey: true,
            handler() {
              self.handleSendText();
            },
          },
        };
      }
    },

    // 切换发送模式后，刷新Quill键盘绑定
    refreshQuillBindings() {
      if (!this.quill) return;
      const keyboard = this.quill.getModule("keyboard");
      // 清空旧绑定，替换新规则
      keyboard.bindings = this.getQuillKeyBindings();
    },
    handleGlobalKeydown(e) {
      if ((e.ctrlKey || e.metaKey) && e.key === "Enter") {
        const tag = document.activeElement.tagName;
        if (["INPUT", "TEXTAREA", "SELECT"].includes(tag)) return;

        const text = this.quill ? this.quill.getText().trim() : "";
        if (!text || this.sending) return;

        // 仅在 ctrlEnter 模式下全局快捷键生效
        if (this.sendMode !== "ctrlEnter") return;

        e.preventDefault();
        this.handleSendText();
      }
    },

    // 处理文本变化，检测@符号输入
    handleTextChange(delta) {
      try {
        if (
          !this.currentChat ||
          this.currentChat.scene !== ContactsScene.GROUP
        ) {
          return;
        }
        if (!this.groupInfo) return;

        if (delta.ops) {
          delta.ops.forEach((op) => {
            if (op.insert && typeof op.insert === "string") {
              const atIndex = op.insert.lastIndexOf("@");
              if (atIndex !== -1 && atIndex === op.insert.length - 1) {
                this.showAtDropdown();
              }
            }
          });
        }
      } catch (e) {
        console.warn("handleTextChange error:", e);
      }
    },

    // 显示@成员下拉框
    showAtDropdown() {
      try {
        const dropdownEl = this.$refs.atDropdown;
        if (dropdownEl && dropdownEl.$el) {
          dropdownEl.$el.click();
        }
      } catch (e) {
        console.warn("showAtDropdown error:", e);
      }
    },

    clearEditor() {
      if (this.quill) {
        this.quill.setText("");
      }
      this.editorFiles = [];
    },

    // 字号切换 - 调整消息显示区域的文字大小
    handleFontSizeChange(size) {
      this.currentFontSize = parseInt(size);
      this.$emit("font-size-change", this.currentFontSize);
    },

    // 发送方式切换
    handleSendModeChange(mode) {
      this.sendMode = mode;
      // 切换后刷新键盘规则立即生效
      this.refreshQuillBindings();
    },

    // 文件按钮
    handleFileClick() {
      this.$refs.fileInput.click();
    },

    // 截屏
    async handleScreenshotClick() {
      try {
        await takeScreenshot(
          async (blob) => {
            try {
              const fileName = `screenshot_${Date.now()}.png`;
              const objectName = this.getObjectPath(fileName);

              await this.ensureMinioInitialized();
              const config = this.$store.getters.config;
              const bucket = config.MINIO_BUCKET_FILE || "remote-file-test";

              const result = await uploadFile(
                bucket,
                objectName,
                blob,
                {},
                (percent) => {}
              );

              const uploadedPath = bucket + "/" + result.objectName;
              // 创建文件对象用于 insertFileToEditor
              const screenshotFile = new File([blob], fileName, {
                type: "image/png",
              });
              await this.insertFileToEditor(screenshotFile, uploadedPath);
              this.$message.success("截图已插入到编辑器");
            } catch (e) {
              this.$message.error("截图上传失败: " + e.message);
            }
          },
          () => {
            this.$message.info("已取消截图");
          }
        );
      } catch (e) {
        this.$message.error("截图失败: " + e.message);
      }
    },

    // ========== 核心：选中@成员 插入富文本 ==========
    handleAtSelect(user) {
      if (!this.quill || !user) return;
      const index = this.currentRange
        ? this.currentRange.index
        : this.quill.getLength();
      const insertText = `@${user.name}`;
      this.quill.insertText(index, insertText);
      this.quill.formatText(index, insertText.length, {
        color: "#409eff",
        fontWeight: "500",
      });
      this.quill.setSelection(index + insertText.length);
      const hasUser = this.selectedAtUsers.find((u) => u.id === user.id);
      if (!hasUser) {
        this.selectedAtUsers.push(user);
      }
    },

    handleTeachingClick(meetingType) {
      const targetMode = this.meetingModes.find(
        (item) => item.type === meetingType
      );
      console.log(targetMode);
      // 正常跳转
      this.$router.push({
        name: targetMode.routeName,
        query: {
          name: this.userInfo.group,
          roomId_id: this.generateRoomId(targetMode.type, this.userInfo.id),
        },
      });
    },
    generateRoomId(meetingType, id) {
      // 1. id固定3位，不足左侧补0
      const idStr = String(id).padStart(3, "0");
      // 拼接 = 会议类型 + 3位id + 前缀
      const roomId = meetingType + idStr + this.config.MEETING_PREFIX;
      return roomId;
    },

    // 提取@用户ID（发送接口使用）
    extractAtUsers(html) {
      const ids = [];
      this.selectedAtUsers.forEach((user) => {
        if (html.includes(`@${user.name}`)) {
          ids.push(user.id);
        }
      });
      return ids;
    },

    // 发送消息
    async handleSendText() {
      if (!this.quill || !this.currentChat) return;
      const html = this.quill.root.innerHTML;
      const textContent = this.quill.getText().trim();

      // 检查是否有内容可以发送（文本或文件）
      const hasText = textContent.replace(/\s+/g, "").length > 0;
      const files = this.extractFilesFromEditor();

      if (!hasText && files.length === 0) {
        this.$message.warning("请输入内容或上传文件");
        return;
      }

      this.sending = true;

      try {
        const messages = this.parseEditorContent(html, textContent);

        for (let i = 0; i < messages.length; i++) {
          const messageData = messages[i];
          const messageId = this.generateMessageId();

          this.$emit("send-message", {
            ...messageData,
            is_self: true,
            sending: true,
            message_id: messageId,
          });

          const body = {
            client_id: this.getClientId(),
            message: messageData,
            target_id: this.currentChat.id,
            topic: this.getTopic(),
          };

          if (this.currentChat.scene === ContactsScene.PRIVATE) {
            await sendPrivateMessage(body);
          } else if (this.currentChat.scene === ContactsScene.GROUP) {
            await sendMultiChatMessage(body);
          }

          this.$emit("update-message-status", messageId, { sending: false });
        }

        this.clearEditor();
        this.selectedAtUsers = [];
      } catch (e) {
        this.$message.error("发送失败: " + (e.message || "未知错误"));
      } finally {
        this.sending = false;
      }
    },

    // 解析编辑器内容，分离文本和文件
    parseEditorContent(html, textContent) {
      const messages = [];
      const atUserIds = this.extractAtUsers(html);

      const textOnly = textContent.replace(/\s+/g, "").length > 0;
      const files = this.extractFilesFromEditor();

      if (textOnly) {
        messages.push({
          at_users: atUserIds,
          message_id: 0,
          payload: {
            content: textContent,
            file_duration: 0,
            file_ico: "",
            file_name: "",
            file_path: "",
            file_size: 0,
            file_type: "",
          },
          scene: this.currentChat.scene,
          source_id: this.userInfo.id,
          target_id: this.currentChat.id,
          timestamp: 0,
          type: "text",
        });
      }

      files.forEach((file) => {
        const msgType = this.getMessageType(file.type);

        messages.push({
          at_users: [],
          message_id: 0,
          payload: {
            content: "",
            file_duration: 0,
            file_ico: file.icon,
            file_name: file.name,
            file_path: file.path,
            file_size: file.size || 0,
            file_type: file.type,
          },
          scene: this.currentChat.scene,
          source_id: this.userInfo.id,
          target_id: this.currentChat.id,
          timestamp: 0,
          type: msgType,
        });
      });

      return messages;
    },

    // 从编辑器中提取所有文件信息
    extractFilesFromEditor() {
      const files = [];
      if (!this.quill) return files;

      const config = this.$store.getters.config;
      const endpoint = config.MINIO_ENDPOINT_HTTPS || "";

      this.quill.root.querySelectorAll("img").forEach((img) => {
        const src = img.src;
        if (src.startsWith(endpoint)) {
          const filePath = src.replace(endpoint, "");
          const fileName = filePath.split("/").pop();
          files.push({
            name: fileName,
            path: filePath,
            type: "image",
            size: 0,
            icon: "",
          });
        }
      });

      this.quill.root.querySelectorAll(".file-card").forEach((card) => {
        const fileIndex = card.getAttribute("data-file-index");
        if (fileIndex !== null && this.editorFiles[fileIndex]) {
          files.push(this.editorFiles[fileIndex]);
        }
      });

      return files;
    },

    // 根据文件类型获取消息类型
    getMessageType(fileType) {
      switch (fileType) {
        case "image":
          return "image";
        case "video":
          return "video";
        case "audio":
          return "audio";
        default:
          return "file";
      }
    },

    // 文件相关逻辑
    async handleFileChange(e) {
      const files = e.target.files;
      if (!files || !files.length) return;
      const file = files[0];
      e.target.value = "";

      if (file.size > this.maxFileSize) {
        this.$message.warning("文件大小不能超过100MB");
        return;
      }

      if (!this.currentChat) {
        this.$message.warning("请先选择聊天对象");
        return;
      }

      try {
        await this.ensureMinioInitialized();
        const fileName = file.name;
        const objectName = this.getObjectPath(fileName);

        const config = this.$store.getters.config;
        const bucket = config.MINIO_BUCKET_FILE || "remote-file-test";

        const result = await uploadFile(
          bucket,
          objectName,
          file,
          {},
          (percent) => {}
        );

        const uploadedPath = bucket + "/" + result.objectName;

        // 所有文件都插入到编辑器
        await this.insertFileToEditor(file, uploadedPath);
        this.$message.success("文件上传成功");
      } catch (e) {
        this.$message.error("文件上传失败: " + e.message);
      }
    },
    // 直接发送文件消息
    async sendFileMessageDirect(file, filePath) {
      if (!this.currentChat) return;
      const messageId = this.generateMessageId();

      const fileType = this.getFileType(file);
      const messageType = file.type.startsWith("video/") ? "video" : "file";

      const message = {
        at_users: [],
        message_id: messageId,
        payload: {
          content: "",
          file_duration: 0,
          file_ico: this.getFileIcon(fileType),
          file_name: file.name,
          file_path: filePath,
          file_size: file.size,
          file_type: fileType,
        },
        scene: this.currentChat.scene,
        source_id: this.userInfo.id,
        target_id: this.currentChat.id,
        timestamp: Date.now(),
        type: messageType,
        is_self: true,
        sending: true,
      };

      this.$emit("send-message", message);

      try {
        const body = {
          client_id: this.getClientId(),
          message: {
            at_users: [],
            message_id: 0,
            payload: {
              content: "",
              file_duration: 0,
              file_ico: this.getFileIcon(fileType),
              file_name: file.name,
              file_path: filePath,
              file_size: file.size,
              file_type: fileType,
            },
            scene: this.currentChat.scene,
            source_id: this.userInfo.id,
            target_id: this.currentChat.id,
            timestamp: 0,
            type: messageType,
          },
          target_id: this.currentChat.id,
          topic: this.getTopic(),
        };

        if (this.currentChat.scene === ContactsScene.PRIVATE) {
          await sendPrivateMessage(body);
        } else if (this.currentChat.scene === ContactsScene.GROUP) {
          await sendMultiChatMessage(body);
        }

        this.$emit("update-message-status", messageId, { sending: false });
      } catch (e) {
        this.$message.error("发送文件失败: " + e.message);
        this.$emit("update-message-status", messageId, {
          sending: false,
          sendFailed: true,
        });
      }
    },
    // 获取文件类型
    getFileType(file) {
      const ext = file.name.split(".").pop().toLowerCase();
      const imageExts = ["jpg", "jpeg", "png", "gif", "bmp", "webp"];
      const videoExts = ["mp4", "webm", "ogg", "mov", "avi"];
      const docExts = ["doc", "docx"];
      const excelExts = ["xls", "xlsx"];
      const pptExts = ["ppt", "pptx"];

      if (imageExts.includes(ext)) return "image";
      if (videoExts.includes(ext)) return "video";
      if (docExts.includes(ext)) return ext;
      if (excelExts.includes(ext)) return ext;
      if (pptExts.includes(ext)) return ext;
      if (ext === "pdf") return "pdf";
      if (ext === "zip" || ext === "rar") return ext;
      if (ext === "txt") return "txt";
      return "file";
    },

    async handlePaste(e) {
      const items = e.clipboardData.items;
      if (!items) return;
      for (let i = 0; i < items.length; i++) {
        const item = items[i];
        if (item.type.indexOf("image") !== -1) {
          const file = item.getAsFile();
          if (file) {
            e.preventDefault();
            await this.sendFileMessage(file, "image");
            return;
          }
        }
      }
    },

    async sendFileMessage(file, type) {
      if (!this.currentChat) return;
      const messageId = this.generateMessageId();
      console.log("sendFileMessage", file);
      const fileName = file.name;
      const objectName = this.getObjectPath(fileName);

      const fileType =
        type === "image"
          ? "image"
          : type === "video"
          ? "video"
          : type === "audio"
          ? "audio"
          : file.name.split(".").pop().toLowerCase() || "file";

      const localPayload = {
        content: "",
        file_duration: 0,
        file_ico: "",
        file_name: file.name,
        file_path: objectName,
        file_size: file.size,
        file_type: fileType,
      };

      const message = {
        at_users: [],
        message_id: 0,
        payload: localPayload,
        scene: this.currentChat.scene,
        source_id: this.userInfo.id,
        target_id: this.currentChat.id,
        timestamp: 0,
        type: type === "image" ? "image" : "file",
      };

      this.$emit("send-message", {
        ...message,
        is_self: true,
        sending: true,
        isUploading: true,
        message_id: messageId,
      });

      try {
        await this.uploadToMinIO(file, objectName);
        const body = {
          client_id: this.getClientId(),
          message: {
            at_users: [],
            message_id: 0,
            payload: {
              content: "",
              file_duration: 0,
              file_ico: type === "image" ? "" : this.getFileIcon(fileType),
              file_name: file.name,
              file_path: objectName,
              file_size: file.size,
              file_type: fileType,
            },
            scene: this.currentChat.scene,
            source_id: this.userInfo.id,
            target_id: this.currentChat.id,
            timestamp: 0,
            type: type === "image" ? "image" : "file",
          },
          target_id: this.currentChat.id,
          topic: this.getTopic(),
        };

        if (this.currentChat.scene === ContactsScene.PRIVATE) {
          await sendPrivateMessage(body);
        } else if (this.currentChat.scene === ContactsScene.GROUP) {
          await sendMultiChatMessage(body);
        }

        this.$emit("update-message-status", messageId, {
          sending: false,
          isUploading: false,
          payload: type === "image" ? objectName : serverPayload,
        });

        if (type === "image" && this.quill) {
          const index = this.currentRange
            ? this.currentRange.index
            : this.quill.getLength();
          this.quill.insertEmbed(index, "image", objectName);
          this.quill.setSelection(index + 1);
        }
      } catch (e) {
        this.$message.error("发送文件失败: " + e.message);
        this.$emit("update-message-status", messageId, {
          sending: false,
          sendFailed: true,
          isUploading: false,
        });
      }
    },

    insertImageToEditor(imagePath) {
      if (!this.quill) return;
      const index = this.currentRange
        ? this.currentRange.index
        : this.quill.getLength();
      const imageUrl =
        this.$store.state.user.netConfig.MINIO_ENDPOINT_HTTPS + imagePath;
      console.log(imageUrl);
      this.quill.insertEmbed(index, "image", imageUrl);
      this.quill.setSelection(index + 1);
    },

    insertFileToEditor(file, filePath) {
      if (!this.quill) return;

      const index = this.currentRange
        ? this.currentRange.index
        : this.quill.getLength();

      const fileType = this.getFileType(file);
      const fileInfo = {
        name: file.name,
        path: filePath,
        type: fileType,
        size: file.size,
        icon: this.getFileIcon(fileType),
      };

      if (!this.editorFiles) {
        this.editorFiles = [];
      }
      this.editorFiles.push(fileInfo);

      if (fileType === "image") {
        const imageUrl =
          this.$store.state.user.netConfig.MINIO_ENDPOINT_HTTPS + filePath;
        this.quill.insertEmbed(index, "image", imageUrl);
      } else {
        const fileSize = this.formatFileSize(file.size);
        const fileHtml = `<div class="file-card" data-file-index="${
          this.editorFiles.length - 1
        }">
          <div class="file-icon-wrapper">
            <img src="${fileInfo.icon}" class="file-icon" />
          </div>
          <div class="file-info">
            <div class="file-name">${file.name}</div>
            <div class="file-size">${fileSize}</div>
          </div>
          <div class="file-remove" onclick="this.parentElement.remove()">
            <i class="el-icon-close"></i>
          </div>
        </div>`;
        this.quill.clipboard.dangerouslyPasteHTML(index, fileHtml);
      }
      this.quill.setSelection(index + 1);
    },

    formatFileSize(bytes) {
      if (bytes === 0) return "0 B";
      const k = 1024;
      const sizes = ["B", "KB", "MB", "GB"];
      const i = Math.floor(Math.log(bytes) / Math.log(k));
      return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + " " + sizes[i];
    },

    getFileType(file) {
      const fileName = file.name.toLowerCase();
      const ext = fileName.split(".").pop();

      if (
        file.type.startsWith("image/") ||
        ["jpg", "jpeg", "png", "gif", "bmp", "svg"].includes(ext)
      ) {
        return "image";
      }
      if (
        file.type.startsWith("video/") ||
        ["mp4", "webm", "ogg", "mov", "avi"].includes(ext)
      ) {
        return "video";
      }
      if (
        file.type.startsWith("audio/") ||
        ["mp3", "wav", "ogg"].includes(ext)
      ) {
        return "audio";
      }
      if (["zip", "rar", "7z", "tar", "gz"].includes(ext)) {
        return "zip";
      }
      if (["doc", "docx"].includes(ext)) {
        return "doc";
      }
      if (["xls", "xlsx"].includes(ext)) {
        return "xls";
      }
      if (["ppt", "pptx"].includes(ext)) {
        return "ppt";
      }
      if (ext === "pdf") {
        return "pdf";
      }
      if (ext === "txt") {
        return "txt";
      }
      return "other";
    },

    ensureMinioInitialized() {
      const config = this.$store.getters.config;
      if (!config || !config.MINIO_ENDPOINT) {
        return this.$store.dispatch("GetNetConfig");
      }
      return Promise.resolve();
    },

    async uploadToMinIO(file, objectName) {
      return new Promise((resolve, reject) => {
        const reader = new FileReader();
        reader.onload = async () => {
          try {
            const formData = new FormData();
            formData.append("file", file);
            formData.append("object_name", objectName);
            const { default: request } = await import("@/utils/request");
            await request({
              url: "/api/v1/common/upload",
              method: "post",
              data: formData,
              headers: { "Content-Type": "multipart/form-data" },
            });
            resolve();
          } catch (err) {
            reject(err);
          }
        };
        reader.onerror = reject;
        reader.readAsArrayBuffer(file);
      });
    },

    getMessageTypeByFileType(type, file) {
      if (type === "image") return MessageType.IMAGE;
      if (type === "video") return MessageType.VIDEO;
      if (file.type.startsWith("audio/")) return MessageType.AUDIO;
      return MessageType.FILE;
    },

    generateMessageId() {
      return (
        "msg_" + Date.now() + "_" + Math.random().toString(36).substr(2, 9)
      );
    },

    getObjectPath(fileName) {
      let sceneDir;
      switch (this.currentChat.scene) {
        case ContactsScene.GROUP:
          sceneDir = MinioPaths.FILE_MULTICHAT;
          break;
        case ContactsScene.NOTIFY:
          sceneDir = MinioPaths.FILE_SYSTEM_NOTIFY;
          break;
        case ContactsScene.PRIVATE:
          sceneDir = MinioPaths.FILE_PRIVATE;
          break;
        default:
          sceneDir = MinioPaths.FILE_PRIVATE;
          break;
      }
      const sourceId = this.userInfo.id;
      const targetId = this.currentChat.id;
      return `${sceneDir}${sourceId}-${targetId}/${fileName}`;
    },

    getTopic() {
      if (this.currentChat.scene === ContactsScene.PRIVATE) {
        return MqttTopics.PRIVATE_CHAT + this.userInfo.id;
      }
      return MqttTopics.MULTI_CHAT + this.currentChat.id;
    },

    getClientId() {
      return MqttTopics.CLIENT_ID_PREFIX + this.userInfo?.id;
    },

    getFileIcon(fileType) {
      const iconMap = {
        doc: ":/message/image/Message/file_icon/doc.svg",
        docx: ":/message/image/Message/file_icon/docx.svg",
        xls: ":/message/image/Message/file_icon/xls.svg",
        xlsx: ":/message/image/Message/file_icon/xlsx.svg",
        ppt: ":/message/image/Message/file_icon/ppt.svg",
        pptx: ":/message/image/Message/file_icon/pptx.svg",
        pdf: ":/message/image/Message/file_icon/pdf.svg",
        zip: ":/message/image/Message/file_icon/zip.svg",
        rar: ":/message/image/Message/file_icon/rar.svg",
        txt: ":/message/image/Message/file_icon/txt.svg",
        video: ":/message/image/Message/file_icon/video.svg",
        audio: ":/message/image/Message/file_icon/audio.svg",
      };
      return iconMap[fileType] || "";
    },
  },
};
</script>

<style lang="scss" scoped>
.message-editor {
  background: #fff;
  padding: 10px 16px;
  .quill-wrap {
    display: flex;
    flex-direction: column;
    border: 1px solid #e4e7ed;
    border-radius: 4px;
    gap: 8px;

    .quill-container {
      height: 100px;
      min-height: 100px;
      overflow-y: auto;
      box-sizing: border-box;

      ::v-deep .ql-container {
        height: 100%;
        font-size: 14px;
      }

      ::v-deep .ql-editor {
        min-height: 100%;
        padding: 8px;

        img {
          max-width: 100%;
          height: auto;
          display: block;
          margin: 4px 0;
          border-radius: 4px;
        }
      }

      ::v-deep .ql-toolbar {
        display: none;
      }
    }
    .editor-toolbar {
      display: flex;
      align-items: center;
      justify-content: space-between;
      width: 100%;
    }

    .editor-toolbar-left,
    .editor-toolbar-right {
      display: flex;
      align-items: center;
      gap: 12px;

      .el-button {
        margin: 0;
        padding: 4px 8px;
      }
    }
  }
}

.file-card {
  display: inline-flex;
  align-items: center;
  background: #f5f7fa;
  border: 1px solid #e4e7ed;
  border-radius: 8px;
  padding: 8px 12px;
  margin: 4px 4px 4px 0;
  cursor: pointer;
  transition: all 0.2s ease;

  &:hover {
    background: #eef2f7;
    border-color: #c0c4cc;
  }

  .file-icon-wrapper {
    width: 32px;
    height: 32px;
    border-radius: 6px;
    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
    display: flex;
    align-items: center;
    justify-content: center;
    margin-right: 10px;
    flex-shrink: 0;

    .file-icon {
      width: 18px;
      height: 18px;
      object-fit: contain;
      filter: brightness(0) invert(1);
    }
  }

  .file-info {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;

    .file-name {
      font-size: 13px;
      color: #303133;
      font-weight: 500;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
      max-width: 180px;
    }

    .file-size {
      font-size: 11px;
      color: #909399;
    }
  }

  .file-remove {
    width: 20px;
    height: 20px;
    border-radius: 50%;
    background: #ccc;
    display: flex;
    align-items: center;
    justify-content: center;
    margin-left: 10px;
    cursor: pointer;
    opacity: 0;
    transition: all 0.2s ease;

    i {
      font-size: 12px;
      color: #fff;
    }

    &:hover {
      background: #f56c6c;
    }
  }

  &:hover .file-remove {
    opacity: 1;
  }
}

.el-dropdown-menu {
  .font-size-selected {
    color: #009393;
    font-weight: 700;
  }
}
</style> 