<template>
  <div class="decoration-chat">
    <div class="chat-header">
      <el-button text @click="handleBack" class="back-btn">
        <el-icon><ArrowLeft /></el-icon>
      </el-button>
      <span class="chat-title">{{ ownerName || "联系业主" }}</span>
    </div>

    <div ref="chatContainerRef" class="chat-content" @scroll="handleScroll">
      <div v-if="loading" class="loading-wrap">
        <el-icon class="is-loading">
          <Loading />
        </el-icon>
        <span>加载中...</span>
      </div>
      <div v-else class="message-list">
        <div v-for="(msg, index) in messages" :key="msg.id || index" :class="['message-item', isMine(msg) ? 'mine' : 'other']">
          <el-avatar class="msg-avatar" :src="isMine(msg) ? myAvatar : ownerAvatar" :size="40">
            <!-- <span class="avatar-fallback">{{ (isMine(msg) ? myName : ownerName).slice(0, 1) }}</span> -->
          </el-avatar>
          <div class="msg-body">
            <div class="msg-time">
              {{ msg.createdTime }}
            </div>
            <div class="msg-bubble">
              <!-- type 1、2、8 正常展示 -->
              <template v-if="[1, 2, 8].includes(Number(msg.type))">
                <!-- 文本 type=1 -->
                <div v-if="msg.type === 1 || msg.type === '1'" class="msg-text">
                  {{ msg.content || msg.text }}
                </div>
                <!-- 图片 type=2 -->
                <el-image
                  v-else-if="msg.type === 2 || msg.type === '2'"
                  :src="msg.content || msg.text"
                  fit="cover"
                  class="msg-image"
                  :preview-src-list="[msg.content || msg.text]"
                />
                <!-- 视频 type=8 -->
                <video
                  v-else-if="msg.type === 8 || msg.type === '8'"
                  :src="msg.content || msg.text"
                  class="msg-video"
                  controls
                  preload="metadata"
                />
              </template>
              <!-- 其他 type 显示提示 -->
              <div v-else class="msg-text msg-tip">此消息请去商家App查看</div>
            </div>
          </div>
        </div>
      </div>
    </div>

    <div class="chat-input-bar">
      <input ref="imageInputRef" type="file" accept="image/*" class="hidden-file-input" @change="handleImageSelect" />
      <input ref="videoInputRef" type="file" accept="video/*" class="hidden-file-input" @change="handleVideoSelect" />
      <div class="input-row">
        <div class="tool-btns">
          <el-tooltip content="图片" placement="top">
            <el-button text :disabled="sending || uploading" @click="triggerImageInput" class="tool-btn">
              <el-icon :size="22">
                <Picture />
              </el-icon>
            </el-button>
          </el-tooltip>
          <el-tooltip content="视频" placement="top">
            <el-button text :disabled="sending || uploading" @click="triggerVideoInput" class="tool-btn">
              <el-icon :size="22">
                <VideoPlay />
              </el-icon>
            </el-button>
          </el-tooltip>
        </div>
        <el-input
          v-model="inputText"
          type="textarea"
          :rows="2"
          :maxlength="500"
          show-word-limit
          placeholder="请输入消息"
          resize="none"
          @keydown.enter.exact.prevent="handleSend"
        />
        <el-button type="primary" :loading="sending" @click="handleSend" class="send-btn"> 发送 </el-button>
      </div>
      <div v-if="uploading" class="uploading-tip">上传中...</div>
    </div>
  </div>
</template>

<script setup lang="ts" name="decorationChat">
import { ref, computed, onMounted, onBeforeUnmount, nextTick, watch } from "vue";
import { useRoute, useRouter } from "vue-router";
import { ElMessage } from "element-plus";
import { ArrowLeft, Loading, Picture, VideoPlay } from "@element-plus/icons-vue";
import { useWebSocketStore } from "@/stores/modules/websocket";
import { getChatRecord, messageRead, socketStatus, uploadChatFile } from "@/api/modules/storeDecoration";
import { localGet } from "@/utils";

const route = useRoute();
const router = useRouter();
const socketStore = useWebSocketStore();

// WebSocket 基础地址（与商家端一致）
const WS_BASE = (import.meta.env.VITE_WS_BASE || "ws://120.26.186.130:8000/alienStore/socket/").replace(/\/$/, "");

// 会话信息
const sendId = ref("");
const receiverId = ref("");
const ownerName = ref("");
const ownerAvatar = ref("");
const requirementId = ref("");

const messages = ref<any[]>([]);
const loading = ref(true);
const sending = ref(false);
const uploading = ref(false);
const inputText = ref("");
const chatContainerRef = ref<HTMLElement>();
const imageInputRef = ref<HTMLInputElement | null>(null);
const videoInputRef = ref<HTMLInputElement | null>(null);
let cleanMessageFn: (() => void) | null = null;
let statusTimer: ReturnType<typeof setInterval> | null = null;

const userInfo = computed(() => localGet("geeker-user")?.userInfo || {});

// 自己头像与名称（用于气泡旁头像）
const myAvatar = computed(
  () =>
    userInfo.value?.headImg ||
    userInfo.value?.avatar ||
    userInfo.value?.userImage ||
    "http://localhost:5173/static/activity/avatar.svg"
);

const isMine = (msg: any) => String(msg.senderId || "") === String(sendId.value);

const handleBack = () => router.go(-1);

const scrollToBottom = () => {
  nextTick(() => {
    const el = chatContainerRef.value;
    if (el) el.scrollTop = el.scrollHeight;
  });
};

const handleSend = async () => {
  const text = inputText.value?.trim();
  if (!text || !receiverId.value) return;
  if (!socketStore.isConnected) {
    ElMessage.warning("连接已断开，请稍后重试");
    return;
  }
  sending.value = true;
  const ok = await socketStore.sendMessage({
    category: "message",
    type: 1,
    receiverId: receiverId.value,
    senderId: sendId.value,
    text
  });
  sending.value = false;
  if (ok) {
    messages.value = [
      ...messages.value,
      {
        id: `temp_${Date.now()}`,
        type: 1,
        content: text,
        senderId: sendId.value,
        receiverId: receiverId.value,
        createdTime: formatTime(new Date())
      }
    ];
    inputText.value = "";
    scrollToBottom();
  } else {
    ElMessage.error("发送失败");
  }
};

// 解析上传接口返回的 fileUrl（与商家端一致）
const getFileUrlFromRes = (res: any): string => {
  const data = res?.data;
  if (Array.isArray(data) && data.length > 0) {
    const first = data[0];
    return typeof first === "string" ? first : first?.fileUrl || first?.url || first?.path || "";
  }
  if (typeof data === "string") return data;
  if (data && typeof data === "object") return data.fileUrl || data.url || data.path || "";
  return "";
};

const triggerImageInput = () => imageInputRef.value?.click();
const triggerVideoInput = () => videoInputRef.value?.click();

const handleImageSelect = async (e: Event) => {
  const target = e.target as HTMLInputElement;
  const file = target.files?.[0];
  target.value = "";
  if (!file || !receiverId.value) return;
  if (!socketStore.isConnected) {
    ElMessage.warning("连接已断开，请稍后重试");
    return;
  }
  uploading.value = true;
  try {
    const form = new FormData();
    form.append("file", file);
    const res: any = await uploadChatFile(form);
    const fileUrl = getFileUrlFromRes(res);
    if (!fileUrl) {
      ElMessage.error("图片上传失败");
      return;
    }
    const ok = await socketStore.sendMessage({
      category: "message",
      type: 2,
      receiverId: receiverId.value,
      senderId: sendId.value,
      text: fileUrl
    });
    if (ok) {
      messages.value = [
        ...messages.value,
        {
          id: `temp_${Date.now()}`,
          type: 2,
          content: fileUrl,
          senderId: sendId.value,
          receiverId: receiverId.value,
          createdTime: formatTime(new Date())
        }
      ];
      scrollToBottom();
    } else {
      ElMessage.error("发送失败");
    }
  } catch (err) {
    console.error("发送图片失败", err);
    ElMessage.error("图片上传或发送失败");
  } finally {
    uploading.value = false;
  }
};

const handleVideoSelect = async (e: Event) => {
  const target = e.target as HTMLInputElement;
  const file = target.files?.[0];
  target.value = "";
  if (!file || !receiverId.value) return;
  if (!socketStore.isConnected) {
    ElMessage.warning("连接已断开，请稍后重试");
    return;
  }
  uploading.value = true;
  try {
    const form = new FormData();
    form.append("file", file);
    const res: any = await uploadChatFile(form);
    const fileUrl = getFileUrlFromRes(res);
    if (!fileUrl) {
      ElMessage.error("视频上传失败");
      return;
    }
    const ok = await socketStore.sendMessage({
      category: "message",
      type: 8,
      receiverId: receiverId.value,
      senderId: sendId.value,
      text: fileUrl
    });
    if (ok) {
      messages.value = [
        ...messages.value,
        {
          id: `temp_${Date.now()}`,
          type: 8,
          content: fileUrl,
          senderId: sendId.value,
          receiverId: receiverId.value,
          createdTime: formatTime(new Date())
        }
      ];
      scrollToBottom();
    } else {
      ElMessage.error("发送失败");
    }
  } catch (err) {
    console.error("发送视频失败", err);
    ElMessage.error("视频上传或发送失败");
  } finally {
    uploading.value = false;
  }
};

// 消息已读（与商家端 chat.vue 一致：receiverId=当前登录人，senderId=当前聊天人）
const readMessage = async () => {
  if (!receiverId.value || !sendId.value) return;
  try {
    await messageRead({
      receiverId: sendId.value,
      senderId: receiverId.value
    });
  } catch (e) {
    console.error("消息已读接口调用失败", e);
  }
};

const loadChatRecord = async () => {
  if (!receiverId.value || !sendId.value) {
    loading.value = false;
    return;
  }
  try {
    loading.value = true;
    await readMessage();
    const res: any = await getChatRecord({
      receiverId: sendId.value,
      senderId: receiverId.value
    });
    const list = res?.data?.messageList || res?.messageList || [];
    list.forEach((item: any) => {
      item.messageId = item.id;
    });
    const filterData = list.filter((v: any) => !(v.type === "5" && v.senderId === sendId.value));
    messages.value = filterData;
  } catch (e) {
    console.error("获取聊天记录失败", e);
  } finally {
    loading.value = false;
    scrollToBottom();
  }
};

const initWebSocket = async () => {
  const phone = userInfo.value?.phone || localGet("iphone");
  if (!phone) {
    ElMessage.warning("未获取到商家信息，无法连接");
    return;
  }
  sendId.value = `store_${phone}`;
  const wsUrl =
    WS_BASE.startsWith("wss") || WS_BASE.startsWith("ws")
      ? `${WS_BASE}/store_${phone}`
      : WS_BASE.replace("https", "wss").replace("http", "ws") + `/store_${phone}`;

  if (!socketStore.isConnected || socketStore.lastConnectedUrl !== wsUrl) {
    await socketStore.connect(wsUrl);
  }
  if (cleanMessageFn) {
    cleanMessageFn();
    cleanMessageFn = null;
  }

  // 归一化 ID：统一去掉 store_/user_ 前缀再比较，避免业主端与商家端 ID 格式不一致导致收不到
  const normalizeId = (id: string) => {
    if (!id) return "";
    const s = String(id).trim();
    return s.replace(/^(store_|user_)/i, "");
  };

  cleanMessageFn = socketStore.subscribe("message", (val: any) => {
    const sId = String(sendId.value);
    const rId = String(receiverId.value);
    const vSender = String(val.senderId ?? "");
    const vReceiver = String(val.receiverId ?? "");
    const sIdNorm = normalizeId(sId);
    const rIdNorm = normalizeId(rId);
    const vSenderNorm = normalizeId(vSender);
    const vReceiverNorm = normalizeId(vReceiver);
    // 当前会话：对方发给我（vReceiver 是我）且 vSender 是当前业主；或反向
    const isCurrent = (vReceiver === sId || vReceiverNorm === sIdNorm) && (vSender === rId || vSenderNorm === rIdNorm);
    const isCurrentReverse = (vReceiver === rId || vReceiverNorm === rIdNorm) && (vSender === sId || vSenderNorm === sIdNorm);
    if (!isCurrent && !isCurrentReverse) return;

    const newMsg = {
      ...val,
      id: val.messageId || val.id,
      content: val.text || val.content,
      createdTime: val.createdTime || formatTime(new Date())
    };
    const contentOrText = String(newMsg.content ?? val.text ?? "").trim();
    const isFromMe = vSender === sId || vSenderNorm === sIdNorm;

    // 1) 先按服务器 id 去重
    let existingIndex = messages.value.findIndex(item => newMsg.id && (item.id === newMsg.id || item.messageId === newMsg.id));
    // 2) 若是自己发的消息，可能是服务端回显：用“临时消息(temp_) + 相同内容”替换，避免显示两条
    if (existingIndex === -1 && isFromMe) {
      const sameContent = (a: any) => String(a?.content ?? a?.text ?? "").trim();
      existingIndex = messages.value.findIndex(
        item =>
          String(item.senderId ?? "") === sId &&
          String(item.id ?? "").startsWith("temp_") &&
          sameContent(item) === sameContent(newMsg) &&
          (newMsg.type == null || Number(item.type) === Number(newMsg.type))
      );
    }
    if (existingIndex !== -1) {
      messages.value = messages.value.map((m, i) => (i === existingIndex ? { ...m, ...newMsg } : m));
    } else {
      messages.value = [...messages.value, newMsg];
    }
    nextTick(() => scrollToBottom());

    if (vSender !== sId) {
      socketStore.sendMessage({ ...val, category: "receipt" }).catch((err: any) => console.error("回执发送失败", err));
    }
  });

  statusTimer = setInterval(() => {
    socketStatus().catch(() => {});
  }, 5000);
};

const formatTime = (d: Date) => {
  const y = d.getFullYear();
  const m = String(d.getMonth() + 1).padStart(2, "0");
  const day = String(d.getDate()).padStart(2, "0");
  const h = String(d.getHours()).padStart(2, "0");
  const min = String(d.getMinutes()).padStart(2, "0");
  const s = String(d.getSeconds()).padStart(2, "0");
  return `${y}-${m}-${day} ${h}:${min}:${s}`;
};

const handleScroll = () => {};

watch(
  () => route.query,
  q => {
    if (q?.receiverId) {
      receiverId.value = String(q.receiverId);
      ownerName.value = decodeURIComponent(String(q.uName || q.ownerName || "业主"));
      ownerAvatar.value = q.userImage
        ? decodeURIComponent(String(q.userImage))
        : "http://localhost:5173/static/activity/avatar.svg";
      requirementId.value = String(q.id || q.requirementId || "");
      loadChatRecord();
    }
  },
  { immediate: true }
);

onMounted(async () => {
  receiverId.value = String(route.query.receiverId || "");
  ownerName.value = decodeURIComponent(String(route.query.uName || route.query.ownerName || "业主"));
  ownerAvatar.value = route.query.userImage
    ? decodeURIComponent(String(route.query.userImage))
    : "http://localhost:5173/static/activity/avatar.svg";
  requirementId.value = String(route.query.id || route.query.requirementId || "");

  if (!receiverId.value) {
    ElMessage.warning("缺少会话信息");
    loading.value = false;
    return;
  }
  await initWebSocket();
  await loadChatRecord();
});

onBeforeUnmount(() => {
  readMessage();
  if (cleanMessageFn) {
    cleanMessageFn();
    cleanMessageFn = null;
  }
  if (statusTimer) {
    clearInterval(statusTimer);
    statusTimer = null;
  }
});
</script>

<style lang="scss" scoped>
.decoration-chat {
  display: flex;
  flex-direction: column;
  height: calc(100vh - 100px);
  background: #f4f6fb;
}
.chat-header {
  display: flex;
  align-items: center;
  padding: 12px 16px;
  background: #ffffff;
  border-bottom: 1px solid #ebeef5;
  .back-btn {
    margin-right: 12px;
    font-size: 18px;
  }
  .chat-title {
    font-size: 16px;
    font-weight: 500;
  }
}
.chat-content {
  flex: 1;
  padding: 16px;
  overflow-y: auto;
  .loading-wrap {
    display: flex;
    gap: 8px;
    align-items: center;
    justify-content: center;
    padding: 24px;
    color: #909399;
  }
  .message-list {
    display: flex;
    flex-direction: column;
    gap: 16px;
  }
  .message-item {
    display: flex;
    gap: 12px;
    align-items: flex-start;
    .msg-avatar {
      flex-shrink: 0;
      overflow: hidden;
      .avatar-fallback {
        display: flex;
        align-items: center;
        justify-content: center;
        width: 100%;
        height: 100%;
        font-size: 16px;
        color: #ffffff;
        background: #c0c4cc;
      }
    }
    &.mine {
      flex-direction: row-reverse;
      .msg-body {
        align-items: flex-end;
      }
      .msg-bubble {
        color: #ffffff;
        background: #409eff;
      }
    }
    .msg-body {
      display: flex;
      flex-direction: column;
      align-items: flex-start;
      max-width: 70%;
    }
    .msg-time {
      margin-bottom: 4px;
      font-size: 12px;
      color: #909399;
    }
    .msg-bubble {
      padding: 10px 14px;
      word-break: break-word;
      background: #ffffff;
      border-radius: 8px;
      box-shadow: 0 1px 2px rgb(0 0 0 / 6%);
    }
    .msg-text {
      font-size: 14px;
      line-height: 1.5;
      &.msg-tip {
        font-style: italic;
        color: #ffffff;
      }
    }
    .msg-image {
      max-width: 200px;
      max-height: 200px;
      cursor: pointer;
      border-radius: 4px;
    }
    .msg-video {
      max-width: 240px;
      max-height: 180px;
      background: #000000;
      border-radius: 4px;
    }
    .msg-share {
      font-size: 14px;
      color: #606266;
    }
  }
}
.hidden-file-input {
  position: absolute;
  width: 0;
  height: 0;
  overflow: hidden;
  pointer-events: none;
  opacity: 0;
}
.chat-input-bar {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 12px 16px;
  background: #ffffff;
  border-top: 1px solid #ebeef5;
  .input-row {
    display: flex;
    gap: 8px;
    align-items: flex-end;
    :deep(.el-input) {
      flex: 1;
      min-width: 0;
    }
  }
  .tool-btns {
    display: flex;
    flex-shrink: 0;
    gap: 4px;
    align-items: center;
    .tool-btn {
      padding: 6px;
    }
  }
  :deep(.el-textarea__inner) {
    border-radius: 8px;
  }
  .send-btn {
    flex-shrink: 0;
    align-self: flex-end;
  }
  .uploading-tip {
    font-size: 12px;
    color: #909399;
  }
}
</style>
