<script setup lang="ts">
import CommentBox from '@/components/common/CommentBox/index.vue'
import { useUserStore } from '@/stores'
import { storeToRefs } from 'pinia'
import BackButton from '@/components/common/BackButton/index.vue'
import type { ScrollbarInstance } from 'element-plus'
import { getMessageList, sendMessage, getMessageDetailList, deleteMessage } from '@/api'
import type { ConversationItem, MessageDetailListItem } from '@/api/selfMessage/types'
import { parseEmoji } from '@/utils/emoji'
import { push } from 'notivue'
import { BooleanFlag } from '@/constants'
import { useMessageBox } from '@/hooks'

const userStore = useUserStore()
const { userInfo } = storeToRefs(userStore)
const route = useRoute()
const { confirm } = useMessageBox()

const categoryTabs = [
  {
    key: BooleanFlag.YES,
    label: '匿名私信',
  },
  {
    key: BooleanFlag.NO,
    label: '实名私信',
  },
]

const conversationList = ref<ConversationItem[]>([])

const activeCategory = ref<BooleanFlag>(BooleanFlag.NO)
const activeConversationId = ref<number>(0)
const keyword = ref('')
const draftText = ref('')
const draftImages = ref('')
const sending = ref(false)
const conversationBoxRef = useTemplateRef<ScrollbarInstance>('conversationBoxRef')
const toChatType = (chatType: ConversationItem['chat_type']) => Number(chatType) as BooleanFlag
const listLoading = ref(false)

const getCategoryFromRoute = () => {
  const isReal = Number(route.query.isReal)
  if (isReal === 1) return BooleanFlag.NO
  if (isReal === 0) return BooleanFlag.YES
  return null
}

const applyCategoryFromRoute = () => {
  const routeCategory = getCategoryFromRoute()
  if (routeCategory === null || routeCategory === activeCategory.value) return false
  activeCategory.value = routeCategory
  activeConversationId.value = 0
  messageDetailList.value = []
  return true
}

const refreshConversationList = async (searchText = keyword.value.trim()) => {
  listLoading.value = true
  try {
    const { data } = await getMessageList({
      search: searchText || undefined,
    })
    conversationList.value = data?.dialogList || []
  } finally {
    listLoading.value = false
  }
}

const filteredConversationList = computed(() => {
  const list = conversationList.value.filter(
    (item) => toChatType(item.chat_type) === activeCategory.value,
  )
  return list
})

const activeConversation = computed(() => {
  return (
    filteredConversationList.value.find((item) => item.id === activeConversationId.value) ?? null
  )
})

const conversationStats = computed(() => ({
  anonymous: conversationList.value.filter((item) => toChatType(item.chat_type) === BooleanFlag.YES)
    .length,
  realname: conversationList.value.filter((item) => toChatType(item.chat_type) === BooleanFlag.NO)
    .length,
}))

const canSend = computed(() => {
  return (
    !!activeConversation.value &&
    (!!draftText.value.trim() || !!draftImages.value.trim()) &&
    !sending.value
  )
})

watch(filteredConversationList, (list) => {
  if (!list.length) {
    activeConversationId.value = 0
    return
  }

  // 仅当当前选中 id 已不在列表中时才清空，避免进入页面时自动选中第一项
  if (
    activeConversationId.value !== 0 &&
    !list.some((item) => item.id === activeConversationId.value)
  ) {
    activeConversationId.value = 0
    messageDetailList.value = []
  }
})

const messageDetailList = ref<MessageDetailListItem[]>([])

/** 拉取会话详情并滚动到底；不要在 watch(activeConversation) 里再调，否则会与点击逻辑并发请求两次 */
const selectConversation = async (item: ConversationItem, shouldScrollToBottom = true) => {
  activeConversationId.value = item.id
  const { data } = await getMessageDetailList({
    receiverId: item.other_user_id,
    dialogId: item.id,
    chatType: activeCategory.value,
  })
  messageDetailList.value = data || []
  if (shouldScrollToBottom) {
    await nextTick()
    scrollToBottom()
  }

  // 刷新active的content
  const lastItem = messageDetailList.value.at(-1)
  if (lastItem) {
    const index = conversationList.value.findIndex((i) => i.id === activeConversationId.value)
    if (index !== -1) {
      conversationList.value[index]!.last_message = lastItem.content
    }
  }
}

watch(
  () => activeConversation.value?.id,
  (id) => {
    if (!id) return
    const current = conversationList.value.find((item) => item.id === id)
    if (current) {
      current.un_read_count = 0
      current.had_read = BooleanFlag.YES
    }
  },
)

const switchCategory = (category: BooleanFlag) => {
  // if (activeCategory.value === category) return
  activeCategory.value = category
  activeConversationId.value = 0
  messageDetailList.value = []
  // 重新刷新
  refreshConversationList()
}

const handleSearchBlur = async () => {
  await refreshConversationList()
}

const handleSearchClear = () => {
  keyword.value = ''
  refreshConversationList('')
}

const scrollToBottom = () => {
  const wrapper = conversationBoxRef.value
  if (!wrapper?.wrapRef) return
  wrapper.scrollTo({
    top: wrapper.wrapRef.scrollHeight,
    behavior: 'smooth',
  })
}

const handleSend = async () => {
  if (!canSend.value || !activeConversation.value) return

  sending.value = true
  try {
    await sendMessage({
      content: draftText.value,
      chatType: activeCategory.value,
      senderId: userInfo.value.userId,
      receiverId: activeConversation.value.other_user_id,
      images: draftImages.value,
    })
    draftText.value = ''
    draftImages.value = ''
    await selectConversation(activeConversation.value)
  } finally {
    sending.value = false
  }
}

const handleInputKeydown = (event: KeyboardEvent) => {
  if (event.key === 'Enter' && !event.shiftKey) {
    event.preventDefault()
    handleSend()
  }
}

const onConversationMenu = async (cmd: string | number, item: ConversationItem) => {
  if (cmd !== 'delete') return
  await confirm({
    title: '删除会话',
    message: '确定删除该会话？删除后聊天记录将不可恢复。',
    confirmText: '删除',
    cancelText: '取消',
    type: 'warning',
  })

  try {
    await deleteMessage({ type: 'user', idList: [item.id] })
    conversationList.value = conversationList.value.filter((c) => c.id !== item.id)
    // 选中会话被删时，由 watch(filteredConversationList) 把 activeConversationId 置 0 并清空 messageDetailList
    push.success('已删除会话')
  } catch {
    /* 失败时请求封装已 toast */
  }
}

const onMessageMenu = async (cmd: string | number, message: MessageDetailListItem) => {
  if (cmd !== 'delete') return
  if (!message.is_self) return
  await confirm({
    title: '撤回消息',
    message: '确定撤回这条消息？',
    confirmText: '撤回',
    cancelText: '取消',
    type: 'warning',
  })

  await deleteMessage({ type: 'message', idList: [message.message_id] })
  // await refreshConversationList()
  if (activeConversation.value) await selectConversation(activeConversation.value, false)
  push.success('已撤回消息')
}

onActivated(() => {
  applyCategoryFromRoute()
  refreshConversationList()
})
</script>

<template>
  <div class="rounded-lg relative">
    <BackButton />
    <section class="flex h-[calc(100vh-6.25rem)] gap-4 overflow-hidden">
      <aside
        class="flex-1/4 rounded-lg border border-[#d8e5f2] bg-white p-4 shadow-[0_0.5rem_1.5rem_rgba(134,167,207,0.12)]"
      >
        <div class="flex h-full flex-col">
          <div>
            <div class="mb-4 flex items-start justify-between gap-3">
              <div>
                <h2 class="m-0 text-4.5 font-700 text-[#17305d]">私信列表</h2>
              </div>
            </div>

            <div class="mb-4 grid grid-cols-2 gap-2">
              <button
                v-for="item in categoryTabs"
                :key="item.key"
                class="cursor-pointer flex items-center justify-between rounded-lg border px-4 py-3 text-3.5 transition-all"
                :class="
                  activeCategory === item.key
                    ? 'border-[#8eadff] bg-[linear-gradient(180deg,#f4f8ff_0%,#eaf1ff_100%)] text-[#2f5ab7] shadow-[0_0.25rem_0.625rem_rgba(130,160,220,0.12)]'
                    : 'border-[#dfebf5] bg-[#f9fbfe] text-[#667b95]'
                "
                @click="switchCategory(item.key)"
              >
                <span>{{ item.label }}</span>
                <span
                  class="inline-flex h-6 min-w-6 items-center justify-center rounded-full bg-[#e8eff8] px-1.5 text-3 font-700"
                >
                  {{
                    item.key === BooleanFlag.YES
                      ? conversationStats.anonymous
                      : conversationStats.realname
                  }}
                </span>
              </button>
            </div>

            <el-input
              v-model="keyword"
              size="large"
              clearable
              placeholder="搜索用户名"
              class="mb-4"
              :loading="listLoading"
              @blur="handleSearchBlur"
              @clear="handleSearchClear"
            >
              <template #prefix>
                <el-icon><IEpSearch /></el-icon>
              </template>
            </el-input>
          </div>
          <div class="min-h-0 flex-1">
            <el-scrollbar>
              <div v-if="filteredConversationList.length" class="space-y-3">
                <el-dropdown
                  v-for="item in filteredConversationList"
                  :key="item.id"
                  class="block w-full"
                  trigger="contextmenu"
                  @command="(cmd) => onConversationMenu(cmd, item)"
                >
                  <button
                    type="button"
                    class="cursor-pointer w-full rounded-lg border p-3 text-left transition-all"
                    :class="
                      activeConversation?.id === item.id
                        ? 'border-[#cbdcff] bg-[linear-gradient(180deg,#f6faff_0%,#edf5ff_100%)] shadow-[0_0.5rem_1.125rem_rgba(134,167,207,0.15)]'
                        : 'border-transparent bg-transparent hover:border-[#dde8f3] hover:bg-[#f9fbfe]'
                    "
                    @click="selectConversation(item)"
                  >
                    <div class="flex gap-3">
                      <div class="relative shrink-0">
                        <el-avatar :size="46" :src="item.other_user_avatar" />
                        <span
                          v-if="Number(item.had_read) === BooleanFlag.NO"
                          class="pointer-events-none absolute right-0 top-0 h-2.5 w-2.5 rounded-full border-2 border-white bg-[#f56c6c] shadow-[0_0_0_1px_rgba(245,108,108,0.35)]"
                          title="未读"
                        />
                      </div>

                      <div class="min-w-0 flex-1">
                        <div class="flex items-center justify-between gap-2">
                          <div class="flex min-w-0 items-center gap-2">
                            <span class="max-w-[6.875rem] truncate text-4 font-700 text-[#17305d]">
                              {{ item.other_user_name }}
                            </span>
                          </div>
                          <span class="shrink-0 text-3 text-[#8ca0b8]">{{
                            item.last_time_str
                          }}</span>
                        </div>

                        <div class="mt-2 flex min-w-0 items-center gap-2">
                          <span
                            class="inline-flex h-5 shrink-0 items-center rounded-full bg-[#fff3dc] px-2 text-3 text-[#9a6817]"
                          >
                            {{ item.chat_type_desc }}
                          </span>
                          <!-- 省略号 -->
                          <span
                            class="truncate text-base text-[#7890aa] max-w-[150px]"
                            v-html="parseEmoji(item.last_message)"
                          ></span>
                          <span
                            v-if="item.un_read_count > 0"
                            class="inline-flex h-5 min-w-5 shrink-0 items-center justify-center rounded-full bg-[#f56c6c] px-1.5 text-3 font-700 text-white"
                          >
                            {{ item.un_read_count > 99 ? '99+' : item.un_read_count }}
                          </span>
                        </div>
                      </div>
                    </div>
                  </button>
                  <template #dropdown>
                    <el-dropdown-menu>
                      <el-dropdown-item command="delete"> 删除会话 </el-dropdown-item>
                    </el-dropdown-menu>
                  </template>
                </el-dropdown>
              </div>

              <el-empty v-else description="没有找到匹配的会话" :image-size="90" />
            </el-scrollbar>
          </div>
        </div>
      </aside>

      <main
        class="overflow-hidden h-full flex-3/4 rounded-lg border border-[#d8e5f2] bg-white shadow-[0_0.5rem_1.5rem_rgba(134,167,207,0.12)]"
      >
        <template v-if="activeConversation">
          <div class="flex h-full min-h-0 flex-col">
            <header
              class="relative z-1 flex flex-col gap-3 border-b border-[#e6eef6] bg-#fff px-5 py-4 shadow-[0_10px_16px_-16px_rgba(15,23,42,0.22)] md:flex-row md:items-center md:justify-between"
            >
              <div class="flex min-w-0 items-center gap-3">
                <el-avatar :size="50" :src="activeConversation.other_user_avatar" />
                <div class="min-w-0">
                  <div class="flex items-center gap-2">
                    <strong class="text-4.5 font-700 text-[#18305d]">{{
                      activeConversation.other_user_name
                    }}</strong>
                    <span
                      class="inline-flex h-6 items-center rounded-full px-2.5 text-3 font-700"
                      :class="
                        toChatType(activeConversation.chat_type) === BooleanFlag.NO
                          ? 'bg-[#e7f7ed] text-[#2a7f61]'
                          : 'bg-[#e8f0ff] text-[#3762c7]'
                      "
                    >
                      {{ activeConversation.chat_type_desc }}
                    </span>
                  </div>
                </div>
              </div>

              <div class="text-[0.8125rem] text-[#6f84a4]">
                当前对话按
                <span class="mx-1 font-700 text-[#4a6fd2]">{{
                  activeConversation.chat_type_desc
                }}</span>
                方式展示
              </div>
            </header>
            <div class="min-h-0 flex-1 overflow-hidden">
              <div
                v-show="!messageDetailList.length"
                class="flex h-full items-center justify-center"
              >
                <el-empty description="没有找到匹配的会话" :image-size="90" />
              </div>
              <el-scrollbar v-show="messageDetailList.length" ref="conversationBoxRef">
                <div v-show="messageDetailList.length" class="px-5 py-5">
                  <div v-for="message in messageDetailList" :key="message.message_id" class="pb-3">
                    <div
                      class="mb-4 flex w-full min-w-0 cursor-default items-start gap-3"
                      :class="{ 'flex-row-reverse': message.is_self }"
                    >
                      <el-avatar :size="38" :src="message.sender_avatar" class="shrink-0" />

                      <div
                        class="flex max-w-[min(72%,38.75rem)] flex-col gap-1"
                        :class="{ 'items-end': message.is_self }"
                      >
                        <div class="flex items-center gap-2 text-3 text-[#8c9bb0]">
                          <span>{{ message.sender_name }}</span>
                          <span class="text-[#9eb0c6]">{{ message.create_time_str }}</span>
                        </div>

                        <div
                          class="w-fit max-w-full rounded-lg px-3 py-2 shadow-[0_0.125rem_0.5rem_rgba(39,74,120,0.04)]"
                          :class="
                            message.is_self
                              ? 'rounded-tr-[0.375rem]  bg-[#dbeaff]'
                              : 'rounded-tl-[0.375rem]  bg-[#dff1fd]'
                          "
                        >
                          <el-dropdown
                            v-if="message.is_self"
                            class="inline-block max-w-full"
                            trigger="contextmenu"
                            @command="(cmd) => onMessageMenu(cmd, message)"
                          >
                            <p
                              v-if="message.content"
                              v-html="parseEmoji(message.content)"
                              class="cursor-pointer m-0 whitespace-pre-wrap break-words text-3.5 leading-[1.625rem]"
                            ></p>
                            <template #dropdown>
                              <el-dropdown-menu>
                                <el-dropdown-item command="delete"> 撤回消息 </el-dropdown-item>
                              </el-dropdown-menu>
                            </template>
                          </el-dropdown>
                          <p
                            v-else-if="message.content"
                            v-html="parseEmoji(message.content)"
                            class="m-0 whitespace-pre-wrap break-words text-3.5 leading-[1.625rem]"
                          ></p>
                          <div
                            v-if="message.image_list?.length"
                            class="mt-2 flex flex-wrap gap-2"
                            :class="'justify-start'"
                            :style="{
                              width: message.image_list.length > 1 ? '15.5rem' : '7.5rem',
                            }"
                          >
                            <el-image
                              v-for="image in message.image_list"
                              :key="image"
                              :src="image"
                              fit="cover"
                              :preview-src-list="message.image_list"
                              preview-teleported
                              class="h-30 w-30 overflow-hidden rounded-lg"
                            />
                          </div>
                        </div>
                      </div>
                    </div>
                  </div>
                </div>
              </el-scrollbar>
            </div>
            <footer
              class="relative z-1 h-auto border-t border-[#e6eef6] bg-white px-5 py-4 shadow-[0_-10px_16px_-16px_rgba(15,23,42,0.22)]"
            >
              <div
                class="mb-3 flex items-center justify-between gap-3 text-[0.8125rem] text-[#7690ac]"
              >
                <div class="flex items-center gap-1.5">
                  <el-icon><IEpInfoFilled /></el-icon>
                  <span>按 Enter 发送，Shift + Enter 换行</span>
                </div>
                <span>{{ draftText.length }} / 250</span>
              </div>

              <div class="self-message-commentbox" @keydown="handleInputKeydown">
                <CommentBox
                  v-model:inputText="draftText"
                  v-model:inputImg="draftImages"
                  :textAreaHeight="72"
                  placeholder="请输入回复内容"
                  :showMention="false"
                >
                  <template #submit>
                    <button
                      type="button"
                      class="comment-publish-btn cursor-pointer disabled:opacity-50 px-6 py-2 text-white rounded-full text-sm hover:shadow-lg transition-all"
                      :disabled="!draftText?.trim() || sending"
                      @click="handleSend"
                    >
                      <div v-show="sending" class="flex items-center gap-2">
                        <el-icon><IEpLoading /></el-icon>
                        <span>发表中...</span>
                      </div>
                      <div v-show="!sending">发表</div>
                    </button>
                  </template>
                </CommentBox>
              </div>
            </footer>
          </div>
        </template>

        <div v-else class="flex h-full items-center justify-center">
          <el-empty description="选择一个会话开始查看私信内容" :image-size="120" />
        </div>
      </main>
    </section>
  </div>
</template>

<style scoped>
:deep(.self-message-commentbox textarea) {
  min-height: 4.25rem !important;
}

:deep(.self-message-commentbox .el-button--primary) {
  border-radius: 0.875rem;
  border-color: #85a7ff;
  background: linear-gradient(90deg, #71b6ff 0%, #7f92ff 100%);
  box-shadow: 0 0.375rem 1rem rgba(125, 146, 255, 0.2);
}

:deep(.self-message-commentbox .el-button--large) {
  min-width: 5.75rem;
}

@media (max-width: 64rem) {
  :deep(.self-message-commentbox .el-button--large) {
    width: 100%;
  }
}
/**
 * 发表按钮：不用纯 Uno 渐变工具类。
 * 旧版内核 / 部分企业微信 WebView 对「依赖 CSS 变量的 linear-gradient」解析失败时，
 * 背景会变成透明或无效，原生 button 呈白底，易出现「只剩阴影、几乎看不见按钮」。
 * 这里用实色 background-color 作兜底，并写死 hex + -webkit- 前缀渐变。
 */
.comment-publish-btn {
  -webkit-appearance: none;
  appearance: none;
  margin: 0;
  border: 1px solid rgba(255, 255, 255, 0.35);
  /* 与 Tailwind blue-500 / purple-500 接近的实色兜底 */
  background-color: #6366f1;
  background-image: -webkit-linear-gradient(left, #3b82f6, #a855f7);
  background-image: linear-gradient(to right, #3b82f6, #a855f7);
  color: #ffffff;
}

.comment-publish-btn:disabled {
  cursor: not-allowed;
}
</style>
