import { useState, useEffect, useRef, useCallback } from 'react'
import { Button, Dropdown, Input, Modal, Select, Spin, message as antMsg } from 'antd'
import {
  CheckCircleOutlined, FileTextOutlined, FlagOutlined, PaperClipOutlined,
  SearchOutlined, SendOutlined, SmileOutlined, SwapOutlined, FilterOutlined,
  ExportOutlined, BookOutlined, PictureOutlined,
} from '@ant-design/icons'
import { useAuth } from '@/stores/auth'
import {
  addSessionNote, claimSession, endSession, getAvailableAgents, getCustomers, getKnowledgeEntries,
  getSession, getSessions, markSessionRead, sendSessionMessage, transferSession, updateSessionPriority,
  type AvailableAgent, type Customer, type KnowledgeEntry, type Message, type Session, type SessionEvent,
} from '@/services/api'

const endReasons = [
  { value: 'resolved', label: '已解决' },
  { value: 'no_response', label: '无人回复' },
  { value: 'visitor_left', label: '访客离开' },
  { value: 'transferred', label: '已转接' },
  { value: 'other', label: '其他' },
]
const quickReplies = [
  '您好，正在为您查询，请稍候。',
  '感谢您的耐心等待，还有什么可以帮您？',
  '为更快处理，请您提供订单号或截图。',
]

/** 列表项展示：紧急 / 等待中 / 进行中 */
function listStatusMeta(session: Session) {
  if (session.priority === 'urgent') {
    return { label: '紧急', bar: '#dc2626', avatarBg: '#fef2f2', avatarColor: '#dc2626', dot: '#dc2626' }
  }
  if (session.status === 'waiting') {
    return { label: '等待中', bar: '#d97706', avatarBg: '#fffbeb', avatarColor: '#d97706', dot: '#d97706' }
  }
  return { label: '进行中', bar: '#2563eb', avatarBg: '#eff6ff', avatarColor: '#2563eb', dot: '#2563eb' }
}

function relativeTime(iso?: string | null) {
  if (!iso) return ''
  const diff = Date.now() - new Date(iso).getTime()
  const mins = Math.floor(diff / 60000)
  if (mins < 1) return '刚刚'
  if (mins < 60) return `${mins}分钟前`
  const hours = Math.floor(mins / 60)
  if (hours < 24) return `${hours}小时前`
  const days = Math.floor(hours / 24)
  if (days < 7) return `${days}天前`
  return new Date(iso).toLocaleDateString('zh-CN', { month: '2-digit', day: '2-digit' })
}

function parseTags(tagsStr: string): string[] {
  try {
    const parsed = JSON.parse(tagsStr)
    return Array.isArray(parsed) ? parsed : []
  } catch {
    return tagsStr ? tagsStr.split(',').map(t => t.trim()).filter(Boolean) : []
  }
}

function channelLabel(source?: string) {
  if (!source) return '网页'
  if (source.includes('微信') || source.toLowerCase().includes('wechat')) return '微信'
  if (source.toLowerCase().includes('app')) return 'APP'
  if (source.includes('电话')) return '电话'
  return source.length > 6 ? '网页' : source
}

interface SessionDetail {
  messages: Message[]
  events: SessionEvent[]
  pendingCount: number
}

const Dashboard = () => {
  const { user } = useAuth()
  const [sessions, setSessions] = useState<Session[]>([])
  const [customers, setCustomers] = useState<Record<number, Customer>>({})
  const [loading, setLoading] = useState(true)
  const [selectedId, setSelectedId] = useState<number | null>(null)
  const [detail, setDetail] = useState<SessionDetail | null>(null)
  const [detailLoading, setDetailLoading] = useState(false)
  const [messageInput, setMessageInput] = useState('')
  const [search, setSearch] = useState('')
  const [sending, setSending] = useState(false)
  const [transferOpen, setTransferOpen] = useState(false)
  const [availableAgents, setAvailableAgents] = useState<AvailableAgent[]>([])
  const [targetAgentID, setTargetAgentID] = useState<number>()
  const [endingOpen, setEndingOpen] = useState(false)
  const [endReason, setEndReason] = useState('resolved')
  const [knowledgeOpen, setKnowledgeOpen] = useState(false)
  const [knowledgeKeyword, setKnowledgeKeyword] = useState('')
  const [knowledgeEntries, setKnowledgeEntries] = useState<KnowledgeEntry[]>([])
  const [knowledgeLoading, setKnowledgeLoading] = useState(false)
  const [imagePreview, setImagePreview] = useState<string | null>(null)
  const [noteInput, setNoteInput] = useState('')
  const [savingNote, setSavingNote] = useState(false)
  const [customerHistory, setCustomerHistory] = useState<Session[]>([])
  const initialLoad = useRef(true)
  const chatEndRef = useRef<HTMLDivElement>(null)
  const fileInputRef = useRef<HTMLInputElement>(null)
  const socketRef = useRef<WebSocket | null>(null)
  const lastTypingAt = useRef(0)

  const isManager = user?.role === 'admin' || user?.role === 'supervisor'

  const loadAll = useCallback(async () => {
    setLoading(true)
    try {
      const [sessionRes, customerRes] = await Promise.all([
        getSessions({ page: 1, pageSize: 100 }),
        getCustomers({ page: 1, pageSize: 100 }),
      ])
      const sessionList = Array.isArray(sessionRes.list) ? sessionRes.list : []
      const customerList = Array.isArray(customerRes.list) ? customerRes.list : []
      setSessions(sessionList)
      setCustomers(Object.fromEntries(customerList.map(customer => [customer.id, customer])))
      if (sessionList.length > 0 && initialLoad.current) {
        const preferred = sessionList.find(session => session.status === 'active')
          || sessionList.find(session => session.priority === 'urgent')
          || sessionList[0]
        setSelectedId(preferred.id)
        initialLoad.current = false
      }
    } catch {
      antMsg.error('加载会话失败')
      setSessions([])
      setCustomers({})
    } finally {
      setLoading(false)
    }
  }, [])

  const loadDetail = useCallback(async (id: number, markRead = true) => {
    setDetailLoading(true)
    try {
      const response = await getSession(id)
      const data = response.data
      setDetail({ messages: data.messages || [], events: data.events || [], pendingCount: data.pending_count || 0 })
      if (markRead) {
        await markSessionRead(id)
        setSessions(previous => previous.map(session => session.id === id ? { ...session, unread_count: 0 } : session))
      }
    } catch {
      antMsg.error('加载消息失败')
    } finally {
      setDetailLoading(false)
    }
    setTimeout(() => chatEndRef.current?.scrollIntoView({ behavior: 'smooth' }), 80)
  }, [])

  useEffect(() => { loadAll() }, [loadAll])

  useEffect(() => {
    if (!user?.token) return
    const scheme = window.location.protocol === 'https:' ? 'wss:' : 'ws:'
    const socket = new WebSocket(`${scheme}//${window.location.host}/api/ws`, ['kefu-v1', user.token])
    socketRef.current = socket
    socket.onmessage = event => {
      try {
        const payload = JSON.parse(event.data)
        if (payload.type === 'message' && payload.session_id === selectedId) {
          loadDetail(payload.session_id)
        }
        if (payload.type === 'message' || payload.type === 'session_created' || payload.type === 'session_updated') {
          loadAll()
        }
      } catch {
        // ignore
      }
    }
    return () => {
      socket.close()
      socketRef.current = null
    }
  }, [user?.token, selectedId, loadAll, loadDetail])

  useEffect(() => {
    if (selectedId) loadDetail(selectedId)
  }, [selectedId, loadDetail])

  useEffect(() => {
    if (!knowledgeOpen) return
    setKnowledgeLoading(true)
    getKnowledgeEntries({ search: knowledgeKeyword, page: 1 }).then(response => {
      setKnowledgeEntries(Array.isArray(response.list) ? response.list : [])
    }).catch(() => setKnowledgeEntries([])).finally(() => setKnowledgeLoading(false))
  }, [knowledgeOpen, knowledgeKeyword])

  const selected = sessions.find(session => session.id === selectedId)
  const selectedCustomer = selected ? customers[selected.customer_id] : null
  const canOperate = Boolean(selected && (isManager || selected.agent_id === user?.user_id) && selected.status === 'active')

  useEffect(() => {
    if (!selectedCustomer) {
      setCustomerHistory([])
      return
    }
    // 从已加载会话中筛出该客户的历史（含已结束）
    getSessions({ page: 1, pageSize: 50 }).then(res => {
      const list = Array.isArray(res.list) ? res.list : []
      setCustomerHistory(
        list
          .filter(s => s.customer_id === selectedCustomer.id && s.id !== selectedId)
          .slice(0, 5),
      )
    }).catch(() => setCustomerHistory([]))
  }, [selectedCustomer?.id, selectedId])

  const filteredSessions = sessions
    .filter(session => {
      if (session.status === 'ended') return false
      const customer = customers[session.customer_id]
      const keyword = search.trim().toLowerCase()
      return !keyword
        || customer?.name.toLowerCase().includes(keyword)
        || String(session.id).includes(keyword)
        || (session.last_message || '').toLowerCase().includes(keyword)
    })
    .slice()
    .sort((a, b) => {
      const rank = (s: Session) => (s.priority === 'urgent' ? 0 : s.status === 'waiting' ? 1 : 2)
      const r = rank(a) - rank(b)
      if (r !== 0) return r
      const ta = new Date(a.last_message_at || a.created_at).getTime()
      const tb = new Date(b.last_message_at || b.created_at).getTime()
      return tb - ta
    })

  const notes = detail?.events.filter(event => event.action === 'note').slice().reverse() || []

  const emitTyping = () => {
    if (!selectedId || !canOperate) return
    const now = Date.now()
    if (now - lastTypingAt.current < 1200 || socketRef.current?.readyState !== WebSocket.OPEN) return
    lastTypingAt.current = now
    socketRef.current.send(JSON.stringify({ type: 'typing', session_id: selectedId }))
  }

  const sendMessage = async (content: string, type: 'text' | 'image' = 'text') => {
    if (!selectedId || !canOperate || sending || (type === 'text' && !content.trim())) return
    setSending(true)
    try {
      await sendSessionMessage(selectedId, content, type)
      if (type === 'text') setMessageInput('')
      await loadDetail(selectedId)
      await loadAll()
    } catch (error) {
      antMsg.error(error instanceof Error ? error.message : '发送失败')
    } finally {
      setSending(false)
    }
  }

  const handleImage = (file?: File) => {
    if (!file) return
    if (!['image/jpeg', 'image/png', 'image/gif'].includes(file.type)) {
      antMsg.error('仅支持 jpg、png、gif 图片')
      return
    }
    if (file.size > 5 * 1024 * 1024) {
      antMsg.error('图片不能超过 5 MB')
      return
    }
    const reader = new FileReader()
    reader.onload = () => setImagePreview(String(reader.result))
    reader.readAsDataURL(file)
  }

  const handleClaim = async (sessionID: number) => {
    try {
      await claimSession(sessionID)
      antMsg.success('已领取会话')
      setSelectedId(sessionID)
      await loadAll()
    } catch (error) {
      antMsg.error(error instanceof Error ? error.message : '领取失败')
    }
  }

  const openTransfer = async () => {
    if (!selected) return
    try {
      const response = await getAvailableAgents()
      setAvailableAgents((response.data || []).filter(agent => agent.id !== user?.user_id))
      setTargetAgentID(undefined)
      setTransferOpen(true)
    } catch {
      antMsg.error('加载在线客服失败')
    }
  }

  const handleTransfer = async () => {
    if (!selected || !targetAgentID) return
    try {
      await transferSession(selected.id, targetAgentID)
      antMsg.success('会话已转接')
      setTransferOpen(false)
      setSelectedId(null)
      setDetail(null)
      await loadAll()
    } catch (error) {
      antMsg.error(error instanceof Error ? error.message : '转接失败')
    }
  }

  const handlePriority = async (priority: 'normal' | 'urgent') => {
    if (!selected) return
    try {
      await updateSessionPriority(selected.id, priority)
      antMsg.success('优先级已更新')
      await loadAll()
    } catch (error) {
      antMsg.error(error instanceof Error ? error.message : '更新失败')
    }
  }

  const handleEnd = async () => {
    if (!selected) return
    try {
      await endSession(selected.id, endReason)
      antMsg.success('会话已结束')
      setEndingOpen(false)
      setSelectedId(null)
      setDetail(null)
      await loadAll()
    } catch (error) {
      antMsg.error(error instanceof Error ? error.message : '结束会话失败')
    }
  }

  const handleAddNote = async () => {
    if (!selected || !noteInput.trim()) return
    setSavingNote(true)
    try {
      await addSessionNote(selected.id, noteInput)
      setNoteInput('')
      await loadDetail(selected.id, false)
    } catch (error) {
      antMsg.error(error instanceof Error ? error.message : '保存备注失败')
    } finally {
      setSavingNote(false)
    }
  }

  const agentInitial = (user?.nickname || '客').slice(0, 1)

  if (loading) {
    return <div className="h-full flex items-center justify-center"><Spin size="large" /></div>
  }

  return (
    <div className="h-full flex overflow-hidden">
      <input
        ref={fileInputRef}
        type="file"
        accept="image/jpeg,image/png,image/gif"
        className="hidden"
        onChange={event => { handleImage(event.target.files?.[0]); event.currentTarget.value = '' }}
      />

      {/* 会话列表面板 320px */}
      <section className="w-[320px] shrink-0 flex flex-col h-full border-r border-neutral-200 bg-white">
        <div className="shrink-0 px-3 py-3 border-b border-neutral-200">
          <div className="flex items-center gap-2 mb-2">
            <div className="flex items-center flex-1 min-w-0 rounded-lg px-2.5 h-[34px] bg-neutral-100 border border-neutral-200">
              <SearchOutlined className="text-neutral-400 text-xs mr-1.5 shrink-0" />
              <input
                className="bg-transparent border-none outline-none flex-1 min-w-0 text-sm text-neutral-900 placeholder:text-neutral-400"
                placeholder="搜索访客或会话"
                value={search}
                onChange={e => setSearch(e.target.value)}
              />
            </div>
            <button
              type="button"
              className="w-[34px] h-[34px] rounded-lg bg-neutral-100 border border-neutral-200 text-neutral-500 flex items-center justify-center shrink-0"
              title="筛选"
            >
              <FilterOutlined className="text-xs" />
            </button>
          </div>
          <div className="flex items-center justify-between">
            <span className="inline-flex items-center px-2 py-0.5 rounded-md text-xs font-medium bg-[#dbeafe] text-[#2563eb]">
              当前会话 {filteredSessions.length} 个
            </span>
            <a
              href="/widget/preview"
              target="_blank"
              rel="noreferrer"
              className="inline-flex items-center gap-1 px-2 py-0.5 rounded-md text-xs text-[#2563eb] hover:bg-[#eff6ff]"
            >
              <ExportOutlined className="text-[10px]" />
              预览访客窗口
            </a>
          </div>
        </div>

        <div className="flex-1 overflow-y-auto no-scrollbar">
          {filteredSessions.length === 0 ? (
            <div className="text-center text-sm text-neutral-400 py-16">暂无待处理会话</div>
          ) : filteredSessions.map(session => {
            const customer = customers[session.customer_id]
            const name = customer?.name || `客户${session.customer_id}`
            const meta = listStatusMeta(session)
            const selected = selectedId === session.id
            return (
              <button
                key={session.id}
                type="button"
                onClick={() => setSelectedId(session.id)}
                className={`w-full flex items-stretch text-left border-b border-neutral-100 transition-colors ${
                  selected ? 'bg-[#eff6ff]' : 'hover:bg-neutral-50'
                }`}
              >
                <div className="w-[3px] shrink-0" style={{ background: selected || session.priority === 'urgent' || session.status === 'waiting' ? meta.bar : 'transparent' }} />
                <div className="flex-1 min-w-0 px-3 py-3">
                  <div className="flex items-center justify-between mb-1">
                    <div className="flex items-center gap-2 min-w-0">
                      <div
                        className="w-9 h-9 rounded-full flex items-center justify-center shrink-0 text-sm font-semibold"
                        style={{ background: meta.avatarBg, color: meta.avatarColor }}
                      >
                        {name.slice(0, 1)}
                      </div>
                      <span className="truncate font-medium text-sm text-neutral-800">{name}</span>
                    </div>
                    <div className="flex items-center gap-1.5 shrink-0 ml-2">
                      <span className="whitespace-nowrap text-xs text-neutral-400">
                        {relativeTime(session.last_message_at || session.created_at)}
                      </span>
                      {session.unread_count > 0 && (
                        <span className="min-w-[18px] h-[18px] px-[5px] rounded-full bg-[#dc2626] text-white text-[11px] font-semibold flex items-center justify-center">
                          {session.unread_count > 99 ? '99+' : session.unread_count}
                        </span>
                      )}
                    </div>
                  </div>
                  <div className="flex items-center justify-between pl-0">
                    <p className="truncate flex-1 min-w-0 mr-2 text-xs text-neutral-500">
                      {session.last_message || '暂无消息'}
                    </p>
                    <span className="flex items-center gap-1 shrink-0 text-xs text-neutral-500">
                      <span className="inline-block w-1.5 h-1.5 rounded-full" style={{ background: meta.dot }} />
                      {meta.label}
                    </span>
                  </div>
                  {session.status === 'waiting' && user?.role === 'agent' && (
                    <div className="mt-1.5 pl-11">
                      <span
                        role="button"
                        tabIndex={0}
                        className="text-xs text-[#2563eb] hover:underline"
                        onClick={e => { e.stopPropagation(); handleClaim(session.id) }}
                        onKeyDown={e => { if (e.key === 'Enter') { e.stopPropagation(); handleClaim(session.id) } }}
                      >
                        领取会话
                      </span>
                    </div>
                  )}
                </div>
              </button>
            )
          })}
        </div>
      </section>

      {/* 主聊天区 */}
      <section className="flex-1 flex flex-col min-w-0 h-full bg-neutral-50">
        {selected && selectedCustomer ? (
          <>
            <div
              className="shrink-0 flex items-center justify-between px-5 bg-white border-b border-neutral-200"
              style={{ height: 'var(--header-height)' }}
            >
              <div className="flex items-center gap-3 min-w-0">
                <div
                  className="w-[38px] h-[38px] rounded-full flex items-center justify-center shrink-0 text-base font-semibold"
                  style={{
                    background: listStatusMeta(selected).avatarBg,
                    color: listStatusMeta(selected).avatarColor,
                  }}
                >
                  {selectedCustomer.name.slice(0, 1)}
                </div>
                <div className="min-w-0">
                  <div className="flex items-center gap-2">
                    <span className="truncate font-semibold text-base text-neutral-900">{selectedCustomer.name}</span>
                    <span className="inline-flex items-center px-1.5 py-0.5 rounded text-xs bg-[#ecfeff] text-[#0891b2]">
                      {channelLabel(selectedCustomer.source)}
                    </span>
                    <span className="inline-flex items-center gap-1 px-1.5 py-0.5 rounded text-xs bg-[#f0fdf4] text-[#16a34a]">
                      <span className="inline-block w-1.5 h-1.5 rounded-full bg-[#16a34a]" />
                      {selectedCustomer.status === 'online' ? '在线' : selectedCustomer.status === 'busy' ? '忙碌' : '离线'}
                    </span>
                  </div>
                  <div className="flex items-center gap-2 mt-0.5 text-xs text-neutral-400">
                    <span className="truncate">会话 #{selected.id}</span>
                    {selectedCustomer.source && (
                      <>
                        <span>|</span>
                        <span className="truncate">{selectedCustomer.source}</span>
                      </>
                    )}
                  </div>
                </div>
              </div>
              <div className="flex items-center gap-1.5 shrink-0 ml-4">
                <Dropdown
                  menu={{
                    items: [
                      { key: 'urgent', label: '标记紧急', onClick: () => handlePriority('urgent') },
                      { key: 'normal', label: '取消紧急', onClick: () => handlePriority('normal') },
                    ],
                  }}
                  disabled={!canOperate}
                >
                  <button type="button" className="w-8 h-8 rounded-lg flex items-center justify-center text-neutral-500 hover:bg-neutral-100 disabled:opacity-40" title="优先级" disabled={!canOperate}>
                    <FlagOutlined />
                  </button>
                </Dropdown>
                <button type="button" className="w-8 h-8 rounded-lg flex items-center justify-center text-neutral-500 hover:bg-neutral-100 disabled:opacity-40" title="知识库" disabled={!canOperate} onClick={() => setKnowledgeOpen(true)}>
                  <BookOutlined />
                </button>
                <button type="button" className="w-8 h-8 rounded-lg flex items-center justify-center text-neutral-500 hover:bg-neutral-100 disabled:opacity-40" title="转接" disabled={!canOperate} onClick={openTransfer}>
                  <SwapOutlined />
                </button>
                <button type="button" className="w-8 h-8 rounded-lg flex items-center justify-center text-red-500 hover:bg-red-50 disabled:opacity-40" title="结束会话" disabled={!canOperate} onClick={() => setEndingOpen(true)}>
                  <CheckCircleOutlined />
                </button>
              </div>
            </div>

            <div className="flex-1 overflow-y-auto px-5 py-4 min-h-0">
              {detailLoading ? (
                <div className="h-full flex items-center justify-center"><Spin /></div>
              ) : (
                <>
                  <div className="flex justify-center mb-4">
                    <span className="inline-flex items-center px-3 py-1 rounded-lg text-xs text-neutral-400 bg-white border border-neutral-100">
                      会话开始 — {new Date(selected.created_at).toLocaleString('zh-CN', { month: 'numeric', day: 'numeric', hour: '2-digit', minute: '2-digit' })}
                    </span>
                  </div>
                  {(detail?.messages || []).map(message => {
                    const isAgent = message.sender_type === 'agent'
                    const visitorInitial = selectedCustomer.name.slice(0, 1)
                    return (
                      <div
                        key={message.id}
                        className={`flex items-start gap-2.5 mb-4 ${isAgent ? 'flex-row-reverse' : ''}`}
                      >
                        <div
                          className="w-9 h-9 rounded-full flex items-center justify-center shrink-0 text-sm font-semibold"
                          style={isAgent
                            ? { background: '#2563eb', color: '#fff' }
                            : { background: listStatusMeta(selected).avatarBg, color: listStatusMeta(selected).avatarColor }}
                        >
                          {isAgent ? agentInitial : visitorInitial}
                        </div>
                        <div className={`min-w-0 max-w-[65%] ${isAgent ? 'items-end' : ''}`}>
                          <div
                            className={`px-3.5 py-2.5 shadow-sm ${
                              isAgent
                                ? 'rounded-xl rounded-tr-sm bg-[#2563eb] text-white'
                                : 'rounded-xl rounded-tl-sm bg-white text-neutral-800 border border-neutral-100'
                            }`}
                          >
                            {message.type === 'image' ? (
                              <img src={message.content} alt="聊天图片" className="max-w-64 max-h-64 rounded-lg" />
                            ) : (
                              <p className="text-sm leading-normal whitespace-pre-wrap break-words m-0">{message.content}</p>
                            )}
                          </div>
                          <div className={`mt-1 text-xs text-neutral-400 ${isAgent ? 'text-right' : ''}`}>
                            {new Date(message.sent_at).toLocaleTimeString('zh-CN', { hour: '2-digit', minute: '2-digit', second: '2-digit' })}
                          </div>
                        </div>
                      </div>
                    )
                  })}
                  {detail?.messages.length === 0 && (
                    <div className="text-center text-sm text-neutral-400 py-10">暂无消息，开始对话吧</div>
                  )}
                  <div ref={chatEndRef} />
                </>
              )}
            </div>

            <div className="shrink-0 bg-white border-t border-neutral-200">
              {selected.status !== 'active' || !canOperate ? (
                <div className="text-center text-sm text-neutral-400 py-4">
                  {selected.status === 'waiting' ? '领取会话后即可回复' : '会话已结束，无法继续发送消息'}
                </div>
              ) : (
                <>
                  <div className="flex items-center gap-1 px-4 pt-2.5 pb-1">
                    <button type="button" className="w-8 h-8 rounded-md flex items-center justify-center text-neutral-500 hover:bg-neutral-100" title="表情">
                      <SmileOutlined />
                    </button>
                    <button type="button" className="w-8 h-8 rounded-md flex items-center justify-center text-neutral-500 hover:bg-neutral-100" title="图片" onClick={() => fileInputRef.current?.click()}>
                      <PictureOutlined />
                    </button>
                    <button type="button" className="w-8 h-8 rounded-md flex items-center justify-center text-neutral-500 hover:bg-neutral-100" title="附件" onClick={() => fileInputRef.current?.click()}>
                      <PaperClipOutlined />
                    </button>
                    <div className="w-px h-5 bg-neutral-200 mx-1" />
                    <Dropdown
                      menu={{
                        items: quickReplies.map((content, index) => ({
                          key: String(index),
                          label: content,
                          onClick: () => setMessageInput(content),
                        })),
                      }}
                    >
                      <button type="button" className="h-8 px-2 rounded-md text-xs text-neutral-500 hover:bg-neutral-100">
                        快捷回复
                      </button>
                    </Dropdown>
                    <button type="button" className="h-8 px-2 rounded-md text-xs text-neutral-500 hover:bg-neutral-100 flex items-center gap-1" onClick={() => setKnowledgeOpen(true)}>
                      <FileTextOutlined />
                      知识库
                    </button>
                  </div>
                  <div className="flex items-end gap-2.5 px-4 pb-3 pt-1">
                    <div className="flex-1 min-w-0 rounded-lg px-3.5 py-2.5 bg-neutral-50 border border-neutral-200">
                      <Input.TextArea
                        autoSize={{ minRows: 1, maxRows: 4 }}
                        variant="borderless"
                        className="!bg-transparent !p-0 text-sm"
                        placeholder="输入回复内容… Enter 发送，Shift+Enter 换行"
                        value={messageInput}
                        onChange={event => { setMessageInput(event.target.value); emitTyping() }}
                        onPaste={event => {
                          const image = Array.from(event.clipboardData.items).find(item => item.type.startsWith('image/'))
                          if (image) {
                            event.preventDefault()
                            handleImage(image.getAsFile() || undefined)
                          }
                        }}
                        onKeyDown={event => {
                          if (event.key === 'Enter' && !event.shiftKey) {
                            event.preventDefault()
                            sendMessage(messageInput)
                          }
                        }}
                      />
                    </div>
                    <button
                      type="button"
                      disabled={!messageInput.trim() || sending}
                      onClick={() => sendMessage(messageInput)}
                      className="w-10 h-10 rounded-lg bg-[#2563eb] hover:bg-[#1d4ed8] disabled:opacity-40 text-white flex items-center justify-center shrink-0 shadow-sm"
                    >
                      {sending ? <Spin size="small" /> : <SendOutlined />}
                    </button>
                  </div>
                </>
              )}
            </div>
          </>
        ) : (
          <div className="flex-1 flex flex-col items-center justify-center text-neutral-400 gap-2">
            <div className="w-16 h-16 rounded-2xl bg-white border border-neutral-200 flex items-center justify-center text-2xl text-neutral-300">
              <SearchOutlined />
            </div>
            <div className="text-sm">选择一个会话开始处理</div>
          </div>
        )}
      </section>

      {/* 右侧客户信息 320px */}
      <aside className="w-[320px] shrink-0 flex flex-col h-full border-l border-neutral-200 bg-white">
        {selectedCustomer ? (
          <>
            <div
              className="shrink-0 flex items-center justify-between px-4 border-b border-neutral-200"
              style={{ height: 'var(--header-height)' }}
            >
              <span className="font-semibold text-base text-neutral-800">客户信息</span>
            </div>
            <div className="flex-1 overflow-y-auto px-4 py-4 no-scrollbar">
              <div className="flex flex-col items-center mb-5">
                <div
                  className="w-14 h-14 rounded-full flex items-center justify-center mb-2 text-[22px] font-semibold"
                  style={{
                    background: selected ? listStatusMeta(selected).avatarBg : '#eff6ff',
                    color: selected ? listStatusMeta(selected).avatarColor : '#2563eb',
                  }}
                >
                  {selectedCustomer.name.slice(0, 1)}
                </div>
                <div className="font-semibold text-lg text-neutral-900">{selectedCustomer.name}</div>
                <div className="flex items-center gap-1 mt-1 text-xs text-neutral-400">
                  <span
                    className="inline-block w-1.5 h-1.5 rounded-full"
                    style={{ background: selectedCustomer.status === 'online' ? '#16a34a' : '#94a3b8' }}
                  />
                  {selectedCustomer.status === 'online' ? '在线' : selectedCustomer.status === 'busy' ? '忙碌' : '离线'}
                </div>
              </div>

              <div className="mb-5">
                <div className="flex items-center gap-1.5 mb-2.5 text-xs font-semibold text-neutral-500 uppercase tracking-wider">
                  基本信息
                </div>
                <div className="flex flex-col gap-2 text-sm">
                  <div className="flex items-start gap-2">
                    <span className="shrink-0 text-neutral-400 min-w-12">手机</span>
                    <span className="truncate text-neutral-800">{selectedCustomer.phone || '—'}</span>
                  </div>
                  <div className="flex items-start gap-2">
                    <span className="shrink-0 text-neutral-400 min-w-12">邮箱</span>
                    <span className="truncate text-neutral-800">{selectedCustomer.email || '—'}</span>
                  </div>
                  <div className="flex items-start gap-2">
                    <span className="shrink-0 text-neutral-400 min-w-12">来源</span>
                    <span className="truncate text-neutral-800">{selectedCustomer.source || '—'}</span>
                  </div>
                  <div className="flex items-start gap-2">
                    <span className="shrink-0 text-neutral-400 min-w-12">对话</span>
                    <span className="truncate text-neutral-800">{selectedCustomer.conversation_count} 次</span>
                  </div>
                </div>
              </div>

              <div className="mb-5">
                <div className="mb-2.5 text-xs font-semibold text-neutral-500 uppercase tracking-wider">客户标签</div>
                <div className="flex flex-wrap gap-1.5">
                  {parseTags(selectedCustomer.tags).length === 0 ? (
                    <span className="text-xs text-neutral-400">暂无标签</span>
                  ) : parseTags(selectedCustomer.tags).map(tag => (
                    <span key={tag} className="text-xs px-2 py-0.5 rounded-md bg-[#dbeafe] text-[#2563eb] font-medium">
                      {tag}
                    </span>
                  ))}
                </div>
              </div>

              <div className="mb-5">
                <div className="mb-2.5 text-xs font-semibold text-neutral-500 uppercase tracking-wider">访问来源</div>
                <div className="flex flex-col gap-2 text-sm">
                  <div className="flex items-start gap-2">
                    <span className="shrink-0 text-neutral-400 min-w-12">渠道</span>
                    <span className="text-neutral-800">{channelLabel(selectedCustomer.source)}在线客服</span>
                  </div>
                  <div className="flex items-start gap-2">
                    <span className="shrink-0 text-neutral-400 min-w-12">来源</span>
                    <span className="text-neutral-800">{selectedCustomer.source || '直接访问'}</span>
                  </div>
                </div>
              </div>

              <div className="mb-5">
                <div className="mb-2.5 text-xs font-semibold text-neutral-500 uppercase tracking-wider">历史会话</div>
                <div className="flex flex-col gap-2">
                  {customerHistory.length === 0 ? (
                    <div className="text-xs text-neutral-400">暂无其他会话</div>
                  ) : customerHistory.map(s => (
                    <button
                      key={s.id}
                      type="button"
                      onClick={() => setSelectedId(s.id)}
                      className="rounded-lg px-3 py-2 text-left bg-neutral-50 border border-neutral-100 hover:border-blue-200"
                    >
                      <div className="flex items-center justify-between mb-1">
                        <span className="truncate text-sm font-medium text-neutral-700">会话 #{s.id}</span>
                        <span className="whitespace-nowrap text-xs text-neutral-400">
                          {new Date(s.created_at).toLocaleDateString('zh-CN', { month: '2-digit', day: '2-digit' })}
                        </span>
                      </div>
                      <p className="line-clamp-1 text-xs text-neutral-400 m-0">
                        {s.last_message || (s.status === 'ended' ? '已结束' : '进行中')}
                      </p>
                    </button>
                  ))}
                </div>
              </div>

              <div className="mb-2">
                <div className="mb-2.5 text-xs font-semibold text-neutral-500 uppercase tracking-wider">内部备注</div>
                <div className="space-y-2 max-h-40 overflow-auto">
                  {notes.length === 0 ? (
                    <div className="text-xs text-neutral-400">暂无内部备注</div>
                  ) : notes.map(note => (
                    <div key={note.id} className="bg-amber-50 text-amber-900 rounded-lg p-2 text-xs whitespace-pre-wrap border border-amber-100">
                      {note.detail}
                      <div className="text-amber-600/70 mt-1">{new Date(note.created_at).toLocaleString('zh-CN')}</div>
                    </div>
                  ))}
                </div>
                {canOperate && (
                  <div className="mt-2 flex gap-1">
                    <Input
                      size="small"
                      maxLength={500}
                      placeholder="添加仅客服可见的备注"
                      value={noteInput}
                      onChange={e => setNoteInput(e.target.value)}
                      onPressEnter={handleAddNote}
                    />
                    <Button size="small" loading={savingNote} onClick={handleAddNote}>保存</Button>
                  </div>
                )}
              </div>
            </div>
          </>
        ) : (
          <div className="flex-1 flex items-center justify-center text-sm text-neutral-400">选择会话查看客户信息</div>
        )}
      </aside>

      <Modal title="转接会话" open={transferOpen} onCancel={() => setTransferOpen(false)} onOk={handleTransfer} okButtonProps={{ disabled: !targetAgentID }}>
        <p className="text-sm text-neutral-500 mb-3">请选择一位在线客服接手当前会话。</p>
        <Select
          className="w-full"
          placeholder="选择客服"
          value={targetAgentID}
          onChange={setTargetAgentID}
          options={availableAgents.map(agent => ({ value: agent.id, label: agent.nickname }))}
        />
      </Modal>
      <Modal title="结束会话" open={endingOpen} onCancel={() => setEndingOpen(false)} onOk={handleEnd} okText="确认结束">
        <p className="text-sm text-neutral-500 mb-3">请选择本次会话的结束原因。</p>
        <Select className="w-full" value={endReason} onChange={setEndReason} options={endReasons} />
      </Modal>
      <Modal
        title="图片预览"
        open={Boolean(imagePreview)}
        onCancel={() => setImagePreview(null)}
        onOk={() => { if (imagePreview) sendMessage(imagePreview, 'image'); setImagePreview(null) }}
        okText="发送"
        okButtonProps={{ loading: sending }}
      >
        <div className="flex justify-center">
          <img src={imagePreview || ''} alt="待发送图片预览" className="max-h-[420px] max-w-full rounded-lg" />
        </div>
      </Modal>
      <Modal title="知识库与快捷回复" open={knowledgeOpen} onCancel={() => setKnowledgeOpen(false)} footer={null} width={640}>
        <Input
          prefix={<SearchOutlined />}
          placeholder="搜索标题或内容"
          value={knowledgeKeyword}
          onChange={event => setKnowledgeKeyword(event.target.value)}
          allowClear
          className="mb-3"
        />
        {knowledgeLoading ? (
          <div className="py-10 text-center"><Spin /></div>
        ) : (
          <div className="space-y-2 max-h-96 overflow-auto">
            {knowledgeEntries.length === 0 ? (
              <div className="text-center text-neutral-400 py-8">未找到可用知识条目</div>
            ) : knowledgeEntries.map(entry => (
              <button
                key={entry.id}
                type="button"
                className="w-full text-left border border-neutral-100 rounded-lg p-3 hover:border-blue-300 hover:bg-blue-50"
                onClick={() => { setMessageInput(entry.content); setKnowledgeOpen(false) }}
              >
                <div className="text-sm font-medium text-neutral-800">{entry.title}</div>
                <div className="text-xs text-neutral-500 mt-1 line-clamp-2">{entry.content}</div>
              </button>
            ))}
          </div>
        )}
      </Modal>
    </div>
  )
}

export default Dashboard
