<template>
  <div class="message-editor">
    <!-- 工具栏 -->
    <div class="editor-toolbar">
      <el-tooltip content="发送图片" placement="top">
        <el-button
          type="text"
          icon="el-icon-picture-outline"
          @click="handleSelectImage"
        />
      </el-tooltip>
      <el-tooltip content="发送视频" placement="top">
        <el-button
          type="text"
          icon="el-icon-video-camera"
          @click="handleSelectVideo"
        />
      </el-tooltip>
      <el-tooltip content="发送文件" placement="top">
        <el-button
          type="text"
          icon="el-icon-folder-opened"
          @click="handleSelectFile"
        />
      </el-tooltip>
      <el-tooltip content="截图" placement="top">
        <el-button
          type="text"
          icon="el-icon-camera"
          @click="handleScreenshot"
        />
      </el-tooltip>
      <el-divider direction="vertical" />
      <el-tooltip content="视频通话" placement="top">
        <el-button
          type="text"
          icon="el-icon-phone-outline"
          @click="handleVideoCall"
        />
      </el-tooltip>
      <el-tooltip content="@成员" placement="top">
        <el-button type="text" @click="handleShowAtPanel"> @ </el-button>
      </el-tooltip>
      <el-divider direction="vertical" />
      <el-tooltip :content="`当前字号: ${currentFontSize}px`" placement="top">
        <el-button type="text" @click="showFontSizeMenu = !showFontSizeMenu">
          <span class="font-size-icon">A</span>
        </el-button>
      </el-tooltip>
      
      <!-- 字号选择菜单 -->
      <div v-if="showFontSizeMenu" class="font-size-menu" @click.stop>
        <div
          v-for="size in fontSizeOptions"
          :key="size"
          :class="['font-size-item', { active: currentFontSize === size }]"
          @click="setFontSize(size)"
        >
          {{ size }}px
        </div>
      </div>
      
      <span class="shortcut-hint">Enter 发送 / Ctrl+Enter 换行</span>
    </div>

    <!-- 输入区 -->
    <div class="editor-input-area">
      <el-input
        ref="inputRef"
        v-model="inputText"
        type="textarea"
        :rows="4"
        :style="{ fontSize: currentFontSize + 'px' }"
        placeholder="请输入消息..."
        resize="none"
        @keydown.enter.native="handleKeydown"
        @paste.native="handlePaste"
        @keydown.at-sign.native="handleAtKeydown"
      />
    </div>

    <!-- 发送按钮 -->
    <div class="editor-footer">
      <el-button
        type="primary"
        size="small"
        :disabled="!canSend"
        :loading="sending"
        @click="handleSendText"
      >
        发送
      </el-button>
    </div>

    <!-- @成员面板 -->
    <div v-if="atPanelVisible" class="at-panel" :style="atPanelStyle">
      <div class="at-panel-header">选择要@的成员</div>
      <el-input
        v-model="atSearchKey"
        placeholder="搜索成员"
        size="small"
        prefix-icon="el-icon-search"
      />
      <div class="at-panel-list">
        <div
          v-for="user in filteredAtUsers"
          :key="user.id"
          class="at-panel-item"
          @click="handleSelectAtUser(user)"
        >
          <el-avatar :size="28" :src="user.avatar" icon="el-icon-user-solid" />
          <span class="at-user-name">{{ user.name }}</span>
        </div>
        <div v-if="!filteredAtUsers.length" class="at-panel-empty">
          无匹配成员
        </div>
      </div>
    </div>

    <!-- 隐藏的文件输入 -->
    <input
      ref="imageInput"
      type="file"
      accept="image/*"
      style="display: none"
      @change="handleFileChange($event, 'image')"
    />
    <input
      ref="fileInput"
      type="file"
      style="display: none"
      @change="handleFileChange($event, 'file')"
    />
    <input
      ref="videoInput"
      type="file"
      accept="video/*"
      style="display: none"
      @change="handleFileChange($event, 'video')"
    />
    
    <!-- 视频通话弹窗 -->
    <el-dialog
      v-if="videoCallVisible"
      title="视频通话"
      :visible.sync="videoCallVisible"
      width="400px"
      :close-on-click-modal="false"
      :show-close="false"
    >
      <div class="video-call-container">
        <div class="video-call-avatar">
          <el-avatar :size="80" icon="el-icon-user-solid" />
        </div>
        <div class="video-call-info">
          <div class="video-call-name">{{ currentChat.name || '通话中' }}</div>
          <div class="video-call-status">{{ callStatus }}</div>
        </div>
        <div class="video-call-timer" v-if="callStarted">
          {{ formatCallTime(callDuration) }}
        </div>
        <div class="video-call-buttons">
          <el-button
            type="text"
            icon="el-icon-video-off"
            @click="toggleVideo"
            :class="{ active: !videoEnabled }"
          >
            {{ videoEnabled ? '关闭摄像头' : '开启摄像头' }}
          </el-button>
          <el-button
            type="text"
            icon="el-icon-microphone"
            @click="toggleMute"
            :class="{ active: !micEnabled }"
          >
            {{ micEnabled ? '静音' : '取消静音' }}
          </el-button>
          <el-button
            type="danger"
            icon="el-icon-phone-off"
            @click="endCall"
          >
            结束通话
          </el-button>
        </div>
      </div>
    </el-dialog>
  </div>
</template>

<script>
import { mapGetters } from "vuex";
import { sendPrivateMessage, sendMultiChatMessage } from "@/api/message";
import {
  MessageType,
  ContactsScene,
  MinioPaths,
  MqttTopics,
} from "@/utils/constants";
import { takeScreenshot } from "@/utils/screenshot";

export default {
  name: "MessageEditor",

  data() {
    return {
      inputText: "",
      sending: false,
      atPanelVisible: false,
      atSearchKey: "",
      atPanelStyle: {},
      atUsers: [],
      selectedAtUsers: [],
      maxFileSize: 100 * 1024 * 1024, // 100MB
      currentFontSize: 14,
      fontSizeOptions: [12, 14, 16, 18, 20, 24],
      showFontSizeMenu: false,
      videoCallVisible: false,
      callStatus: "正在呼叫...",
      callStarted: false,
      callDuration: 0,
      callTimer: null,
      videoEnabled: true,
      micEnabled: true,
    };
  },

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

    canSend() {
      return (
        this.inputText.trim().length > 0 && this.currentChat && !this.sending
      );
    },

    filteredAtUsers() {
      const key = this.atSearchKey.trim().toLowerCase();
      if (!key) return this.atUsers;
      return this.atUsers.filter((u) => u.name.toLowerCase().includes(key));
    },
  },

  watch: {
    currentChat: {
      immediate: true,
      handler(chat) {
        if (chat && chat.scene === ContactsScene.GROUP) {
          this.loadGroupMembers();
        } else {
          this.atUsers = [];
        }
        this.inputText = "";
        this.selectedAtUsers = [];
      },
    },
    showFontSizeMenu(val) {
      if (val) {
        document.addEventListener("click", this.handleClickOutside);
      } else {
        document.removeEventListener("click", this.handleClickOutside);
      }
    },
  },

  beforeDestroy() {
    document.removeEventListener("click", this.handleClickOutside);
    this.stopCallTimer();
  },

  methods: {
    handleClickOutside(e) {
      const toolbar = this.$el.querySelector(".editor-toolbar");
      if (toolbar && !toolbar.contains(e.target)) {
        this.showFontSizeMenu = false;
      }
    },

    handleKeydown(e) {
      if (e.ctrlKey || e.shiftKey) {
        return;
      }
      e.preventDefault();
      this.handleSendText();
    },

    handleAtKeydown() {
      this.handleShowAtPanel();
    },

    async handleSendText() {
      const text = this.inputText.trim();
      if (!text || !this.currentChat) return;

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

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

        const content = {
          type: MessageType.TEXT,
          scene: this.currentChat.scene,
          target_id: this.currentChat.id,
          source_id: this.userInfo.id,
          payload: text,
          at_users: atUserIds,
          timestamp,
          message_id: messageId,
        };

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

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

        this.inputText = "";
        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;
      }
    },

    handleSelectImage() {
      this.$refs.imageInput.click();
    },

    handleSelectFile() {
      this.$refs.fileInput.click();
    },

    handleSelectVideo() {
      this.$refs.videoInput.click();
    },

handleScreenshot() {
  takeScreenshot(
    async (blob) => {
      // ==============================
      // 生成位图数据（核心）
      // ==============================
      const file = new File([blob], `screenshot_${Date.now()}.png`, { type: "image/png" });
      const dataUrl = URL.createObjectURL(blob);

      // ==============================
      // 预览 + 编辑弹窗（Element UI）
      // ==============================
      this.$msgbox({
        title: "截图预览",
        dangerouslyUseHTMLString: true,
        message: `<img src="${dataUrl}" style="width:100%;max-height:60vh;object-fit:contain;border-radius:6px">`,
        showCancelButton: true,
        cancelButtonText: "取消",
        confirmButtonText: "发送",
        showClose: true,
        customClass: "screenshot-preview-dialog",
        showConfirmButton: true,
        showCancelButton: true,
        closeOnClickModal: false,
        buttonSize: "small",
        callback: (action) => {
          if (action === "confirm") {
            // ==============================
            // 分享：直接发送
            // ==============================
            this.sendFileMessage(file, "image");
          } else {
            URL.revokeObjectURL(dataUrl);
          }
        }
      }).then(() => {});

      // ==============================
      // 复制到剪贴板（自动）
      // ==============================
      try {
        const item = new ClipboardItem({ "image/png": blob });
        navigator.clipboard.write([item]);
        this.$message.success("已复制到剪贴板");
      } catch (e) {}

      // ==============================
      // 保存到本地（自动）
      // ==============================
      const a = document.createElement("a");
      a.href = dataUrl;
      a.download = `截图_${new Date().getTime()}.png`;
      a.click();
      URL.revokeObjectURL(dataUrl);
    },
    () => {
      this.$message.info("已取消截图");
    }
  ).catch((err) => {
    this.$message.error(err.message);
  });
},

    handleVideoCall() {
      if (!this.currentChat) {
        this.$message.warning("请先选择聊天对象");
        return;
      }
      this.videoCallVisible = true;
      this.callStatus = "正在呼叫...";
      this.callStarted = false;
      this.callDuration = 0;
      this.videoEnabled = true;
      this.micEnabled = true;

      setTimeout(() => {
        this.callStatus = "通话中";
        this.callStarted = true;
        this.startCallTimer();
      }, 2000);
    },

    startCallTimer() {
      this.callTimer = setInterval(() => {
        this.callDuration++;
      }, 1000);
    },

    stopCallTimer() {
      if (this.callTimer) {
        clearInterval(this.callTimer);
        this.callTimer = null;
      }
    },

    formatCallTime(seconds) {
      const mins = Math.floor(seconds / 60);
      const secs = seconds % 60;
      return `${mins.toString().padStart(2, "0")}:${secs.toString().padStart(2, "0")}`;
    },

    toggleVideo() {
      this.videoEnabled = !this.videoEnabled;
    },

    toggleMute() {
      this.micEnabled = !this.micEnabled;
    },

    endCall() {
      this.stopCallTimer();
      this.videoCallVisible = false;
      this.$message.info("通话已结束");
    },

    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 timestamp = Date.now();
      const fileName = this.generateFileName(file.name);
      const objectName = this.getObjectPath(fileName);

      const localUrl = URL.createObjectURL(file);
      const payload = {
        file_name: file.name,
        file_size: file.size,
        object_name: objectName,
        mime_type: file.type,
        url: localUrl,
      };

      const content = {
        type: this.getMessageTypeByFileType(type, file),
        scene: this.currentChat.scene,
        target_id: this.currentChat.id,
        source_id: this.userInfo.id,
        payload: type === "image" ? localUrl : payload,
        at_users: [],
        timestamp,
        message_id: messageId,
      };

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

      try {
        await this.uploadToMinIO(file, objectName);

        const serverPayload = {
          ...payload,
          url: objectName,
        };

        const body = {
          topic: this.getTopic(),
          client_id: this.getClientId(),
          target_id: this.currentChat.id,
          content: JSON.stringify({
            ...content,
            payload: type === "image" ? objectName : serverPayload,
          }),
        };

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

    extractAtUsers(text) {
      const ids = [];
      this.selectedAtUsers.forEach((user) => {
        if (text.includes("@" + user.name)) {
          ids.push(user.id);
        }
      });
      return ids;
    },

    handleShowAtPanel() {
      if (!this.currentChat || this.currentChat.scene !== ContactsScene.GROUP)
        return;
      const inputEl = this.$refs.inputRef.$refs.textarea;
      if (inputEl) {
        const rect = inputEl.getBoundingClientRect();
        this.atPanelStyle = {
          bottom: "80px",
          left: "20px",
        };
      }
      this.atPanelVisible = true;
      this.atSearchKey = "";
    },

    handleSelectAtUser(user) {
      this.inputText += "@" + user.name + " ";
      this.selectedAtUsers.push(user);
      this.atPanelVisible = false;
      this.$refs.inputRef.focus();
    },

    async loadGroupMembers() {
      this.atUsers = [];
    },

    setAtUsers(users) {
      this.atUsers = users || [];
    },

    setFontSize(size) {
      this.currentFontSize = size;
      this.showFontSizeMenu = false;
      this.$message.info(`字号已设置为 ${size}px`);
    },
  },
};
</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;
    }

    &.active {
      color: #f56c6c;
    }
  }

  .font-size-icon {
    font-size: 16px;
    font-weight: bold;
    color: #606266;
  }

  .shortcut-hint {
    margin-left: auto;
    font-size: 12px;
    color: #c0c4cc;
  }
}

.font-size-menu {
  position: absolute;
  top: 40px;
  right: 20px;
  background: #fff;
  border-radius: 8px;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
  padding: 4px 0;
  z-index: 100;

  .font-size-item {
    padding: 8px 16px;
    font-size: 13px;
    color: #303133;
    cursor: pointer;
    white-space: nowrap;

    &:hover {
      background: #f5f7fa;
    }

    &.active {
      background: #ecf5ff;
      color: #409eff;
      font-weight: 500;
    }
  }
}

.editor-input-area {
  .el-textarea {
    ::v-deep .el-textarea__inner {
      background: #f5f7fa;
      border: none;
      border-radius: 8px;
      padding: 10px 12px;
      line-height: 1.5;

      &:focus {
        background: #fff;
        box-shadow: 0 0 0 1px #409eff;
      }
    }
  }
}

.editor-footer {
  display: flex;
  justify-content: flex-end;
  margin-top: 8px;
}

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

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

  .el-input {
    padding: 8px 12px;
  }

  .at-panel-list {
    max-height: 200px;
    overflow-y: auto;

    .at-panel-item {
      display: flex;
      align-items: center;
      gap: 8px;
      padding: 8px 12px;
      cursor: pointer;
      transition: background 0.2s;

      &:hover {
        background: #f5f7fa;
      }

      .at-user-name {
        font-size: 13px;
        color: #303133;
      }
    }

    .at-panel-empty {
      padding: 16px;
      text-align: center;
      font-size: 13px;
      color: #c0c4cc;
    }
  }
}

.video-call-container {
  text-align: center;
  padding: 30px 0;

  .video-call-avatar {
    margin-bottom: 16px;
  }

  .video-call-info {
    margin-bottom: 16px;

    .video-call-name {
      font-size: 18px;
      font-weight: 500;
      color: #303133;
      margin-bottom: 4px;
    }

    .video-call-status {
      font-size: 14px;
      color: #67c23a;
    }
  }

  .video-call-timer {
    font-size: 24px;
    font-weight: 600;
    color: #409eff;
    margin-bottom: 24px;
    letter-spacing: 2px;
  }

  .video-call-buttons {
    display: flex;
    justify-content: center;
    gap: 24px;

    .el-button {
      font-size: 14px;
      padding: 10px 20px;

      &.active {
        color: #f56c6c;
      }
    }
  }
}
</style>
