<script setup lang="ts">
import { ref, reactive, onMounted, onBeforeUnmount, nextTick } from 'vue'
import {
  Search,
  Refresh,
  Promotion,
  Plus,
  Edit,
  Delete,
  CircleCheck,
  Close,
  SwitchButton
} from '@element-plus/icons-vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { useUserStore } from '@/stores/modules/user'
import { useChatSocket } from '@/utils/chatSocket'
import {
  getChatSessionPageApi,
  getChatMessagesApi,
  sendChatMessageApi,
  acceptChatSessionApi,
  closeChatSessionApi,
  updateChatSessionStatusApi,
  transferChatSessionApi,
  getQuickReplyListApi,
  createQuickReplyApi,
  updateQuickReplyApi,
  deleteQuickReplyApi,
  chatHeartbeatApi,
  type ChatSession,
  type ChatMessage,
  type QuickReply
} from '@/api/chat'
import { getAdminPageApi, type AdminItem } from '@/api/admin'
import { formatDate, fromNow } from '@/utils/date'

const CHAT_STATUS_MAP = {
  0: { text: '待处理', type: 'warning' },
  1: { text: '处理中', type: 'primary' },
  2: { text: '已解决', type: 'success' },
  3: { text: '已关闭', type: 'info' }
} as const

const userStore = useUserStore()
const ws = useChatSocket(userStore.token || '', 'admin')

// ==================== 会话列表 ====================
const loading = ref(false)
const sessions = ref<ChatSession[]>([])
const total = ref(0)
const query = reactive({
  current: 1,
  size: 50,
  keyword: '',
  status: undefined as 0 | 1 | 2 | 3 | undefined,
  mine: 0 as 0 | 1
})

async function fetchSessions() {
  loading.value = true
  try {
    const res = await getChatSessionPageApi({
      current: query.current,
      size: query.size,
      keyword: query.keyword || undefined,
      status: query.status,
      mine: query.mine
    })
    sessions.value = res.records
    total.value = res.total
    // 同步当前会话的最新状态
    if (activeSession.value) {
      const updated = sessions.value.find((s) => s.id === activeSession.value!.id)
      if (updated) activeSession.value = updated
    }
    if (!activeSession.value && sessions.value.length > 0) {
      selectSession(sessions.value[0])
    }
  } finally {
    loading.value = false
  }
}

function handleSearch() {
  query.current = 1
  fetchSessions()
}

function handleReset() {
  query.keyword = ''
  query.status = undefined
  query.mine = 0
  query.current = 1
  fetchSessions()
}

// ==================== 消息区 ====================
const activeSession = ref<ChatSession | null>(null)
const messages = ref<ChatMessage[]>([])
const inputText = ref('')
const messagesRef = ref<HTMLElement>()
let optimisticSeq = 0

function makeClientMsgId() {
  return `adm${Date.now()}_${++optimisticSeq}`
}

function scrollToBottom() {
  nextTick(() => {
    if (messagesRef.value) {
      messagesRef.value.scrollTop = messagesRef.value.scrollHeight
    }
  })
}

function ackTo(seq: number) {
  if (!activeSession.value || !seq) return
  ws.publish({
    type: 'ack',
    sessionId: activeSession.value.id,
    lastSeq: seq
  })
}

async function loadMessages(sessionId: number) {
  const list = await getChatMessagesApi(sessionId, { limit: 200 })
  messages.value = list
  scrollToBottom()
  const maxSeq = list.reduce((mx, m) => Math.max(mx, m.seq || 0), 0)
  if (maxSeq > 0) ackTo(maxSeq)
}

function selectSession(s: ChatSession) {
  activeSession.value = s
  loadMessages(s.id)
}

function onChatMessage(msg: ChatMessage) {
  if (!msg || !activeSession.value || msg.sessionId !== activeSession.value.id) return
  // 替换本地乐观消息
  if (msg.clientMsgId) {
    const idx = messages.value.findIndex((m) => m.clientMsgId === msg.clientMsgId)
    if (idx >= 0) {
      messages.value[idx] = msg
      scrollToBottom()
      return
    }
  }
  if (messages.value.some((m) => m.id === msg.id)) return
  messages.value.push(msg)
  scrollToBottom()
  if (msg.seq) ackTo(msg.seq)
}

async function sendMessage() {
  const content = inputText.value.trim()
  if (!content || !activeSession.value) return
  const clientMsgId = makeClientMsgId()
  inputText.value = ''
  // 乐观渲染
  messages.value.push({
    id: -Date.now(),
    sessionId: activeSession.value.id,
    seq: 0,
    senderId: 0,
    senderType: 1,
    type: 'text',
    content,
    isRecalled: 0,
    createTime: new Date().toISOString(),
    clientMsgId
  })
  scrollToBottom()

  const ok = ws.publish({
    type: 'send',
    sessionId: activeSession.value.id,
    content,
    clientMsgId
  })
  if (!ok) {
    // WebSocket 未连接 → HTTP 兜底
    try {
      const saved = await sendChatMessageApi(activeSession.value.id, { type: 'text', content })
      const idx = messages.value.findIndex((m) => m.clientMsgId === clientMsgId)
      if (idx >= 0) messages.value[idx] = saved
      else messages.value.push(saved)
      scrollToBottom()
      if (saved.seq) ackTo(saved.seq)
    } catch {
      ElMessage.error('发送失败，请检查连接')
    }
  }
}

// ==================== 会话操作 ====================
async function handleAccept() {
  if (!activeSession.value) return
  const ok = ws.publish({ type: 'accept', sessionId: activeSession.value.id })
  if (!ok) {
    await acceptChatSessionApi(activeSession.value.id)
  }
  ElMessage.success('已接管会话')
  fetchSessions()
}

async function handleResolve() {
  if (!activeSession.value) return
  await updateChatSessionStatusApi(activeSession.value.id, 2)
  ElMessage.success('会话已标记为已解决')
  fetchSessions()
}

async function handleClose() {
  if (!activeSession.value) return
  try {
    await ElMessageBox.confirm('确定要关闭该会话吗？关闭后用户无法继续发送消息。', '提示', {
      type: 'warning',
      confirmButtonText: '关闭会话',
      cancelButtonText: '取消'
    })
    const ok = ws.publish({ type: 'close', sessionId: activeSession.value.id })
    if (!ok) await closeChatSessionApi(activeSession.value.id)
    ElMessage.success('会话已关闭')
    fetchSessions()
  } catch {
    /* 用户取消 */
  }
}

// ==================== 转接 ====================
const transferVisible = ref(false)
const transferAdminId = ref<number | null>(null)
const adminOptions = ref<AdminItem[]>([])

async function openTransfer() {
  transferAdminId.value = null
  try {
    const res = await getAdminPageApi({ current: 1, size: 100 })
    const selfId = (userStore.adminInfo as any)?.id
    adminOptions.value = res.records.filter((a) => a.id !== selfId && a.status === 1)
    transferVisible.value = true
  } catch {
    /* 拦截器已提示 */
  }
}

async function submitTransfer() {
  if (!activeSession.value || !transferAdminId.value) return
  await transferChatSessionApi(activeSession.value.id, transferAdminId.value)
  ElMessage.success('会话已转接')
  transferVisible.value = false
  fetchSessions()
}

// ==================== 快捷回复 ====================
const quickReplyVisible = ref(false)
const quickReplies = ref<QuickReply[]>([])
const qrDialogVisible = ref(false)
const qrForm = reactive({
  id: undefined as number | undefined,
  title: '',
  content: '',
  category: '',
  sort: 0,
  status: 1 as 0 | 1
})

async function loadQuickReplies() {
  quickReplies.value = await getQuickReplyListApi()
}

function insertQuickReply(q: QuickReply) {
  inputText.value = q.content
  quickReplyVisible.value = false
}

function openQrCreate() {
  Object.assign(qrForm, { id: undefined, title: '', content: '', category: '', sort: 0, status: 1 })
  qrDialogVisible.value = true
}

function openQrEdit(q: QuickReply) {
  Object.assign(qrForm, {
    id: q.id,
    title: q.title,
    content: q.content,
    category: q.category || '',
    sort: q.sort,
    status: q.status
  })
  qrDialogVisible.value = true
}

async function saveQuickReply() {
  if (!qrForm.title.trim() || !qrForm.content.trim()) {
    ElMessage.warning('标题和内容不能为空')
    return
  }
  const payload = {
    title: qrForm.title.trim(),
    content: qrForm.content.trim(),
    category: qrForm.category.trim() || undefined,
    sort: qrForm.sort,
    status: qrForm.status
  }
  if (qrForm.id) {
    await updateQuickReplyApi({ ...payload, id: qrForm.id })
    ElMessage.success('快捷回复已更新')
  } else {
    await createQuickReplyApi(payload)
    ElMessage.success('快捷回复已创建')
  }
  qrDialogVisible.value = false
  loadQuickReplies()
}

async function removeQuickReply(q: QuickReply) {
  try {
    await ElMessageBox.confirm(`确定删除快捷回复「${q.title}」吗？`, '提示', { type: 'warning' })
    await deleteQuickReplyApi(q.id)
    ElMessage.success('已删除')
    loadQuickReplies()
  } catch {
    /* 用户取消 */
  }
}

// ==================== WebSocket 事件 ====================
function onAdminEvent(ev: any) {
  if (!ev || !ev.eventType) return
  if (['session_message', 'session_accepted', 'session_closed'].includes(ev.eventType)) {
    fetchSessions()
  }
}

function onPersonalEvent(ev: any) {
  if (!ev) return
  if (ev.eventType === 'session_closed' && activeSession.value) {
    fetchSessions()
  }
}

function onChatError(ev: any) {
  ElMessage.error(ev?.message || '连接出错，正在重连…')
}

// ==================== 生命周期 ====================
let heartbeatTimer: number | undefined

onMounted(() => {
  ws.connect()
  ws.on('admin_event', onAdminEvent)
  ws.on('event', onPersonalEvent)
  ws.on('message', onChatMessage)
  ws.on('error', onChatError)
  fetchSessions()
  loadQuickReplies()
  heartbeatTimer = window.setInterval(() => {
    chatHeartbeatApi().catch(() => {})
  }, 30000)
})

onBeforeUnmount(() => {
  ws.disconnect()
  if (heartbeatTimer) window.clearInterval(heartbeatTimer)
})
</script>

<template>
  <div class="page-container chat-page">
    <div class="page-header">
      <div>
        <h2>客服消息</h2>
        <p class="page-desc">WebSocket 实时会话，支持接管 / 转接 / 快捷回复</p>
      </div>
      <div class="ws-status">
        <span :class="['ws-dot', { online: ws.connected.value }]" />
        {{ ws.connected.value ? '实时连接中' : '重连中…' }}
      </div>
    </div>

    <div class="chat-container">
      <!-- 会话列表 -->
      <div class="session-list">
        <div class="session-header">
          <el-input
            v-model="query.keyword"
            placeholder="搜索用户名 / 会话编号"
            :prefix-icon="Search"
            size="default"
            clearable
            @keyup.enter="handleSearch"
          />
          <div class="session-filters">
            <el-select v-model="query.status" placeholder="会话状态" clearable size="small">
              <el-option label="待处理" :value="0" />
              <el-option label="处理中" :value="1" />
              <el-option label="已解决" :value="2" />
              <el-option label="已关闭" :value="3" />
            </el-select>
            <el-checkbox v-model="query.mine" :true-value="1" :false-value="0">只看我的</el-checkbox>
          </div>
          <div class="session-actions">
            <el-button size="small" :icon="Search" @click="handleSearch">查询</el-button>
            <el-button size="small" :icon="Refresh" @click="handleReset">重置</el-button>
          </div>
        </div>

        <div v-loading="loading" class="session-scroll">
          <div
            v-for="s in sessions"
            :key="s.id"
            :class="['session-item', { active: activeSession?.id === s.id }]"
            @click="selectSession(s)"
          >
            <el-avatar :size="40">{{ (s.username || s.nickname || '?').charAt(0) }}</el-avatar>
            <div class="session-info">
              <div class="session-top">
                <span class="session-name">{{ s.username || s.nickname || ('用户' + s.userId) }}</span>
                <span class="session-time">{{ fromNow(s.lastTime || s.createTime) }}</span>
              </div>
              <div class="session-bottom">
                <span class="last-msg">{{ s.lastMessage || '（暂无消息）' }}</span>
                <el-badge v-if="s.unreadCount > 0" :value="s.unreadCount" class="badge" />
              </div>
              <div class="session-tags">
                <el-tag :type="(CHAT_STATUS_MAP[s.status as 0 | 1 | 2 | 3].type as any)" size="small">
                  {{ CHAT_STATUS_MAP[s.status as 0 | 1 | 2 | 3].text }}
                </el-tag>
                <span v-if="s.adminName" class="admin-name">{{ s.adminName }}</span>
              </div>
            </div>
          </div>
          <el-empty v-if="!loading && sessions.length === 0" description="暂无会话" :image-size="80" />
        </div>
      </div>

      <!-- 聊天窗口 -->
      <div class="chat-window">
        <template v-if="activeSession">
          <div class="chat-header">
            <el-avatar :size="36">{{ (activeSession.username || activeSession.nickname || '?').charAt(0) }}</el-avatar>
            <div class="chat-user">
              <div class="chat-name">
                {{ activeSession.username || activeSession.nickname || ('用户' + activeSession.userId) }}
                <el-tag
                  :type="(CHAT_STATUS_MAP[activeSession.status as 0 | 1 | 2 | 3].type as any)"
                  size="small"
                  style="margin-left: 8px"
                >
                  {{ CHAT_STATUS_MAP[activeSession.status as 0 | 1 | 2 | 3].text }}
                </el-tag>
              </div>
              <div class="chat-no">会话号：{{ activeSession.sessionNo }}</div>
            </div>
            <div class="chat-ops">
              <el-button
                v-if="activeSession.status === 0 || !activeSession.adminId"
                size="small"
                type="primary"
                :icon="SwitchButton"
                @click="handleAccept"
              >接管</el-button>
              <el-button
                v-if="activeSession.status === 1"
                size="small"
                type="success"
                :icon="CircleCheck"
                @click="handleResolve"
              >已解决</el-button>
              <el-button
                v-if="activeSession.status === 1"
                size="small"
                @click="openTransfer"
              >转接</el-button>
              <el-button
                v-if="activeSession.status < 3"
                size="small"
                type="danger"
                plain
                :icon="Close"
                @click="handleClose"
              >关闭</el-button>
            </div>
          </div>

          <div ref="messagesRef" class="chat-messages">
            <div
              v-for="m in messages"
              :key="m.id"
              :class="['msg-row', m.senderType === 1 ? 'mine' : m.senderType === 2 ? 'system' : 'theirs']"
            >
              <el-avatar v-if="m.senderType === 0" :size="32">
                {{ (activeSession.username || activeSession.nickname || '?').charAt(0) }}
              </el-avatar>
              <div v-if="m.senderType === 2" class="system-msg">{{ m.content }}</div>
              <template v-else>
                <div class="msg-bubble">
                  <span class="msg-text">{{ m.content }}</span>
                  <span class="msg-time">{{ formatDate(m.createTime) }}</span>
                </div>
                <el-avatar v-if="m.senderType === 1" :size="32" style="background: #1E40AF">客</el-avatar>
              </template>
            </div>
          </div>

          <div class="chat-input">
            <el-input
              v-model="inputText"
              type="textarea"
              :rows="3"
              :disabled="activeSession.status === 3"
              :placeholder="activeSession.status === 3 ? '会话已关闭，无法发送' : '请输入回复内容，Ctrl+Enter 发送'"
              @keydown.ctrl.enter.prevent="sendMessage"
            />
            <div class="chat-actions">
              <el-button :icon="Promotion" text @click="quickReplyVisible = true">快捷回复</el-button>
              <el-button
                type="primary"
                :disabled="!inputText.trim() || activeSession.status === 3"
                @click="sendMessage"
              >发送 (Ctrl+Enter)</el-button>
            </div>
          </div>
        </template>
        <el-empty v-else description="请选择左侧会话开始处理" />
      </div>
    </div>

    <!-- 快捷回复抽屉 -->
    <el-drawer v-model="quickReplyVisible" title="快捷回复" size="360px">
      <div class="qr-actions">
        <el-button type="primary" size="small" :icon="Plus" @click="openQrCreate">新增模板</el-button>
      </div>
      <div class="qr-list">
        <div v-for="q in quickReplies" :key="q.id" class="qr-item">
          <div class="qr-head">
            <span class="qr-title">{{ q.title }}</span>
            <span class="qr-category">{{ q.category || '通用' }}</span>
          </div>
          <p class="qr-content">{{ q.content }}</p>
          <div class="qr-ops">
            <el-button link type="primary" size="small" @click="insertQuickReply(q)">使用</el-button>
            <el-button link type="primary" size="small" :icon="Edit" @click="openQrEdit(q)">编辑</el-button>
            <el-button link type="danger" size="small" :icon="Delete" @click="removeQuickReply(q)">删除</el-button>
          </div>
        </div>
        <el-empty v-if="quickReplies.length === 0" description="暂无快捷回复" :image-size="70" />
      </div>
    </el-drawer>

    <!-- 快捷回复编辑 -->
    <el-dialog v-model="qrDialogVisible" :title="qrForm.id ? '编辑快捷回复' : '新增快捷回复'" width="460px">
      <el-form label-width="70px">
        <el-form-item label="标题">
          <el-input v-model="qrForm.title" placeholder="例如：物流咨询" maxlength="100" />
        </el-form-item>
        <el-form-item label="分类">
          <el-input v-model="qrForm.category" placeholder="例如：问候 / 物流 / 售后（可留空）" />
        </el-form-item>
        <el-form-item label="内容">
          <el-input v-model="qrForm.content" type="textarea" :rows="4" maxlength="500" show-word-limit />
        </el-form-item>
        <el-form-item label="排序">
          <el-input-number v-model="qrForm.sort" :min="0" />
        </el-form-item>
        <el-form-item label="状态">
          <el-radio-group v-model="qrForm.status">
            <el-radio :value="1">启用</el-radio>
            <el-radio :value="0">禁用</el-radio>
          </el-radio-group>
        </el-form-item>
      </el-form>
      <template #footer>
        <el-button @click="qrDialogVisible = false">取消</el-button>
        <el-button type="primary" @click="saveQuickReply">保存</el-button>
      </template>
    </el-dialog>

    <!-- 转接 -->
    <el-dialog v-model="transferVisible" title="转接会话" width="420px">
      <el-form label-width="80px">
        <el-form-item label="转给">
          <el-select v-model="transferAdminId" placeholder="选择目标客服" style="width: 100%">
            <el-option
              v-for="a in adminOptions"
              :key="a.id"
              :label="a.nickname || a.username"
              :value="a.id"
            />
          </el-select>
        </el-form-item>
      </el-form>
      <template #footer>
        <el-button @click="transferVisible = false">取消</el-button>
        <el-button type="primary" :disabled="!transferAdminId" @click="submitTransfer">确认转接</el-button>
      </template>
    </el-dialog>
  </div>
</template>

<style lang="scss" scoped>
.chat-page {
  height: calc(100vh - 100px);
}
.ws-status {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 13px;
  color: $color-text-secondary;

  .ws-dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: $color-warning;

    &.online {
      background: $color-success;
    }
  }
}
.chat-container {
  display: flex;
  height: calc(100vh - 200px);
  background: #fff;
  border-radius: 10px;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);
  overflow: hidden;
}
.session-list {
  width: 300px;
  border-right: 1px solid $color-border-light;
  display: flex;
  flex-direction: column;
  flex-shrink: 0;
}
.session-header {
  padding: 12px;
  border-bottom: 1px solid $color-border-light;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.session-filters {
  display: flex;
  align-items: center;
  gap: 8px;
}
.session-actions {
  display: flex;
  gap: 8px;
}
.session-scroll {
  flex: 1;
  overflow-y: auto;
}
.session-item {
  display: flex;
  gap: 10px;
  padding: 12px;
  cursor: pointer;
  border-bottom: 1px solid $color-border-light;
  transition: background 0.2s;

  &:hover {
    background: $bg-hover;
  }
  &.active {
    background: rgba(30, 64, 175, 0.08);
  }
}
.session-info {
  flex: 1;
  min-width: 0;
}
.session-top {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 4px;
}
.session-name {
  font-weight: 500;
  font-size: 14px;
}
.session-time {
  font-size: 11px;
  color: $color-text-placeholder;
}
.session-bottom {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 8px;
}
.last-msg {
  flex: 1;
  font-size: 12px;
  color: $color-text-secondary;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.session-tags {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-top: 4px;

  .admin-name {
    font-size: 12px;
    color: $color-text-placeholder;
  }
}

.chat-window {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-width: 0;
}
.chat-header {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 12px 20px;
  border-bottom: 1px solid $color-border-light;
}
.chat-user {
  flex: 1;
  min-width: 0;
}
.chat-name {
  font-weight: 500;
}
.chat-no {
  font-size: 12px;
  color: $color-text-secondary;
}
.chat-ops {
  display: flex;
  gap: 6px;
}
.chat-messages {
  flex: 1;
  overflow-y: auto;
  padding: 20px;
  background: $bg-page;
}
.msg-row {
  display: flex;
  gap: 8px;
  margin-bottom: 16px;
  align-items: flex-start;

  &.mine {
    flex-direction: row-reverse;
  }
  &.system {
    justify-content: center;
  }
}
.msg-bubble {
  max-width: 60%;
  padding: 8px 12px 6px;
  background: #fff;
  border-radius: 8px;
  font-size: 14px;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);

  .msg-text {
    display: block;
    white-space: pre-wrap;
    word-break: break-word;
  }
  .msg-time {
    display: block;
    margin-top: 4px;
    font-size: 11px;
    color: $color-text-placeholder;
    text-align: right;
  }
}
.msg-row.mine .msg-bubble {
  background: $brand-primary;
  color: #fff;

  .msg-time {
    color: rgba(255, 255, 255, 0.7);
  }
}
.system-msg {
  padding: 4px 12px;
  border-radius: 10px;
  background: rgba(107, 114, 128, 0.12);
  color: $color-text-secondary;
  font-size: 12px;
}

.chat-input {
  border-top: 1px solid $color-border-light;
  padding: 12px 20px;
}
.chat-actions {
  margin-top: 8px;
  display: flex;
  justify-content: flex-end;
  align-items: center;
  gap: 8px;
}

// 快捷回复
.qr-actions {
  margin-bottom: 12px;
}
.qr-list {
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.qr-item {
  padding: 12px;
  border: 1px solid $color-border-light;
  border-radius: 8px;

  .qr-head {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 6px;

    .qr-title {
      font-weight: 600;
      font-size: 14px;
    }
    .qr-category {
      font-size: 12px;
      color: $color-text-placeholder;
    }
  }
  .qr-content {
    margin: 0 0 8px;
    font-size: 13px;
    color: $color-text-regular;
    line-height: 1.5;
  }
  .qr-ops {
    display: flex;
    justify-content: flex-end;
  }
}
</style>
