<template>
  <div class="message-editor">
    <!-- 工具栏 -->
    <div class="editor-toolbar">
      <el-tooltip content="文件" placement="top">
        <el-button
          type="text"
          icon="el-icon-folder-opened"
          @click="handleFileClick"
        />
      </el-tooltip>

      <el-tooltip content="截屏" placement="top">
        <el-button
          type="text"
          icon="el-icon-scissors"
          @click="handleScreenshotClick"
        />
      </el-tooltip>

      <!-- 字号下拉 -->
      <el-dropdown @command="handleFontSizeChange">
        <el-button type="text"> A </el-button>
        <el-dropdown-menu slot="dropdown">
          <el-dropdown-item command="10">10px</el-dropdown-item>
          <el-dropdown-item command="11">11px</el-dropdown-item>
          <el-dropdown-item command="12">12px</el-dropdown-item>
          <el-dropdown-item command="13">13px</el-dropdown-item>
          <el-dropdown-item command="14">14px</el-dropdown-item>
        </el-dropdown-menu>
      </el-dropdown>
      <!-- @成员下拉 仅群聊显示 -->
      <el-dropdown @command="handleAtSelect" v-if="currentChat.scene == 4">
        <el-button type="text"> @ </el-button>
        <el-dropdown-menu
          slot="dropdown"
          style="height: 200px; overflow-y: auto"
        >
          <el-dropdown-item
            command="{ id: '0', name: '所有人' }"
            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>

      <el-tooltip content="发起教学" placement="top">
        <el-button
          type="text"
          icon="el-icon-video-camera"
          @click="handleTeachingClick"
        />
      </el-tooltip>

      <el-tooltip content="发起会诊" placement="top">
        <el-button
          type="text"
          icon="el-icon-video-camera-solid"
          @click="handleConsultClick"
        />
      </el-tooltip>
    </div>

    <!-- Quill 编辑区 + 右下角发送按钮 容器 -->
    <div class="quill-wrap">
      <div ref="quillEditor" class="quill-container"></div>
      <!-- 右下角发送区域 -->
      <div class="send-area">
        <el-button
          type="primary"
          size="small"
          :disabled="!canSend"
          :loading="sending"
          @click="handleSendText"
        >
          发送
        </el-button>
        <el-dropdown @command="handleSendModeChange">
          <el-button type="text" size="small">
            <span class="send-mode-text">{{ sendModeLabel }}</span>
            <i class="el-icon-arrow-down el-icon--right"></i>
          </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>

    <!-- 隐藏文件上传 -->
    <input
      ref="fileInput"
      type="file"
      style="display: none"
      @change="(e) => handleFileChange(e, 'file')"
    />
  </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 {
  MessageType,
  ContactsScene,
  MinioPaths,
  MqttTopics,
} from "@/utils/constants";

export default {
  name: "MessageEditor",
  props: {
    groupInfo: Object,
  },

  data() {
    return {
      quill: null,
      currentRange: null,
      sending: false,
      maxFileSize: 100 * 1024 * 1024,
      sendMode: "enter",
      fontSizeMap: {
        10: "small",
        11: "small",
        12: false,
        13: "large",
        14: "large",
      },
      // 记录被@的用户
      selectedAtUsers: [],
    };
  },

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

    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.initQuill();
  },

  beforeDestroy() {
    this.quill = null;
  },

  methods: {
    // 初始化Quill
    initQuill() {
      const editorDom = this.$refs.quillEditor;
      this.quill = new Quill(editorDom, {
        theme: "snow",
        placeholder: "请输入消息...",
        modules: {
          toolbar: false,
        },
        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.root.addEventListener("paste", this.handlePaste, true);

      // 回车发送逻辑
      this.quill.root.addEventListener("keydown", (e) => {
        if (this.sendMode === "enter") {
          if (e.key === "Enter" && !e.ctrlKey && !e.shiftKey) {
            e.preventDefault();
            this.handleSendText();
          }
        } else {
          if (e.key === "Enter" && (e.ctrlKey || e.metaKey)) {
            e.preventDefault();
            this.handleSendText();
          }
        }
      });
    },

    clearEditor() {
      if (this.quill) {
        this.quill.setText("");
      }
    },

    // 字号切换
    handleFontSizeChange(size) {
      const quillSize = this.fontSizeMap[size];
      if (this.quill) {
        this.quill.format("size", quillSize);
        this.$refs.quillEditor.style.fontSize = size + "px";
      }
    },

    // 发送方式切换
    handleSendModeChange(mode) {
      this.sendMode = mode;
    },

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

    // 截屏
    handleScreenshotClick() {
      this.$emit("open-screenshot");
    },

    // ========== 核心：选中@成员 插入富文本 ==========
    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.setSelection(index + insertText.length);
      // 记录被@用户（去重）
      const hasUser = this.selectedAtUsers.find((u) => u.id === user.id);
      if (!hasUser) {
        this.selectedAtUsers.push(user);
      }
    },

    handleTeachingClick() {
      this.$emit("open-teaching");
    },

    handleConsultClick() {
      this.$emit("open-consult");
    },

    // 提取@用户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 text = this.quill.getText().trim();
      if (!text) return;

      this.sending = true;
      const messageId = this.generateMessageId();
      const timestamp = Date.now();

      try {
        const atUserIds = this.extractAtUsers(html);

        const message = {
          at_users: atUserIds,
          message_id: 0,
          payload: {
            content: text,
            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",
        };

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

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

        this.clearEditor();
        this.selectedAtUsers = [];

        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,
        });
      } finally {
        this.sending = false;
      }
    },

    // 文件相关逻辑
    async handleFileChange(e, type) {
      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;
      }
      await this.sendFileMessage(file, type);
    },

    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();
      const fileName = this.generateFileName(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,
        });
      }
    },

    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)
      );
    },

    generateFileName(originalName) {
      const ext = originalName.split(".").pop();
      const timestamp = Date.now();
      const random = Math.random().toString(36).substr(2, 6);
      return `${timestamp}_${random}.${ext}`;
    },

    getObjectPath(fileName) {
      const prefix =
        this.currentChat.scene === ContactsScene.GROUP
          ? MinioPaths.FILE_MULTICHAT
          : MinioPaths.FILE_PRIVATE;
      return prefix + 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;
  border-top: 1px solid #ebeef5;
  padding: 10px 16px;
  position: relative;
}

.editor-toolbar {
  display: flex;
  align-items: center;
  gap: 4px;
  margin-bottom: 8px;

  .el-button {
    font-size: 18px;
    padding: 4px 8px;
    color: #606266;

    &:hover {
      color: #409eff;
    }
  }
}

.quill-wrap {
  position: relative;
}

.quill-container {
  height: 100px;
  padding-right: 100px;
  box-sizing: border-box;

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

  ::v-deep .ql-editor {
    min-height: 100%;
  }
}

.send-area {
  position: absolute;
  right: 8px;
  bottom: 8px;
  display: flex;
  align-items: center;
  gap: 8px;

  .send-mode-text {
    font-size: 12px;
    color: #909399;
  }
}

.at-panel {
  position: absolute;
  bottom: 80px;
  left: 20px;
  width: 240px;
  background: #fff;
  border-radius: 8px;
  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
  z-index: 999;
  padding: 8px 0;

  .at-panel-header {
    padding: 0 12px 8px;
    font-size: 13px;
    color: #909399;
    border-bottom: 1px solid #ebeef5;
  }

  .at-panel-list {
    max-height: 200px;
    overflow-y: auto;
    margin-top: 8px;
  }

  .at-panel-item {
    padding: 8px 12px;
    cursor: pointer;
    font-size: 14px;

    &:hover {
      background: #f5f7fa;
    }
  }

  .at-panel-empty {
    padding: 12px;
    text-align: center;
    font-size: 13px;
    color: #c0c4cc;
  }
}
</style>