"use client"

import Link from "next/link"
import {
  ArrowRightLeftIcon,
  CircleOffIcon,
  ClipboardListIcon,
  PlusIcon,
  RefreshCcwIcon,
  SearchIcon,
  SaveIcon,
  Settings2Icon,
  SquarePenIcon,
  StarIcon,
  Trash2Icon,
} from "lucide-react"
import { useCallback, useEffect, useMemo, useState } from "react"
import { toast } from "sonner"

import { ListPagination } from "@/components/list-pagination"
import { OptionCombobox } from "@/components/option-combobox"
import { Badge } from "@/components/ui/badge"
import { Button } from "@/components/ui/button"
import { Checkbox } from "@/components/ui/checkbox"
import { Input } from "@/components/ui/input"
import {
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
} from "@/components/ui/table"
import {
  fetchAgentProfilesAll,
  fetchAgentTeamsAll,
  type AdminAgentProfile,
  type AdminAgentTeam,
  fetchTagsAll,
  type TagTree,
} from "@/lib/api/admin"
import {
  fetchTicketPriorityConfigsAll,
  type TicketPriorityConfig,
} from "@/lib/api/ticket-config"
import {
  createTicket,
  batchWatchTickets,
  deleteTicketView,
  fetchTicketViews,
  fetchTicketSummary,
  fetchTickets,
  saveTicketView,
  updateTicket,
  unwatchTicket,
  watchTicket,
  type Paging,
  type TicketSavedView,
  type TicketItem,
  type TicketSummary,
} from "@/lib/api/ticket"
import { readSession } from "@/lib/auth"
import { formatDateTime } from "@/lib/utils"
import { EditDialog } from "./_components/edit"
import { TicketAssignDialog } from "./_components/ticket-assign-dialog"
import { TicketPriorityBadge } from "./_components/ticket-priority-badge"
import { TicketReasonDialog } from "./_components/ticket-reason-dialog"
import { TicketSLABadge } from "./_components/ticket-sla-badge"
import { TicketStatusDialog } from "./_components/ticket-status-dialog"
import { TicketStatusBadge } from "./_components/ticket-status-badge"

const emptyPaging: Paging = { page: 1, limit: 20, total: 0 }
const emptySummary: TicketSummary = {
  all: 0,
  mine: 0,
  watching: 0,
  collaboration: 0,
  participating: 0,
  mentioned: 0,
  unassigned: 0,
  pendingCustomer: 0,
  pendingInternal: 0,
  overdue: 0,
}

type QuickViewKey =
  | "all"
  | "mine"
  | "collaboration"
  | "participating"
  | "mentioned"
  | "watching"
  | "unassigned"
  | "pending_customer"
  | "pending_internal"
  | "overdue"

type SavedTicketView = {
  id: number
  name: string
  keywordInput: string
  keyword: string
  statusFilter: string
  priorityFilter: string
  severityFilter: string
  tagFilter: string
  teamFilter: string
  assigneeFilter: string
  sourceFilter: string
  watchFilter: string
  quickView: QuickViewKey
}

function buildTagOptions(nodes: TagTree[], parentPath = ""): Array<{ value: string; label: string }> {
  const result: Array<{ value: string; label: string }> = []
  nodes.forEach((item) => {
    const currentPath = parentPath ? `${parentPath} / ${item.name}` : item.name
    result.push({ value: String(item.id), label: currentPath })
    if (item.children.length > 0) {
      result.push(...buildTagOptions(item.children, currentPath))
    }
  })
  return result
}

function isClosedStatus(status: string) {
  return status === "resolved" || status === "closed" || status === "cancelled"
}

function getResolveDeadlineTime(ticket: TicketItem) {
  if (!ticket.resolveDeadlineAt) {
    return null
  }
  const deadline = new Date(ticket.resolveDeadlineAt.replace(" ", "T"))
  if (Number.isNaN(deadline.getTime())) {
    return null
  }
  return deadline.getTime()
}

function isOverdueTicket(ticket: TicketItem) {
  const deadline = getResolveDeadlineTime(ticket)
  if (deadline === null || isClosedStatus(ticket.status)) {
    return false
  }
  return deadline < Date.now()
}

function isRiskTicket(ticket: TicketItem) {
  const deadline = getResolveDeadlineTime(ticket)
  if (deadline === null || isClosedStatus(ticket.status)) {
    return false
  }
  const remainingMinutes = Math.floor((deadline - Date.now()) / 60000)
  return remainingMinutes >= 0 && remainingMinutes <= 240
}

function getTicketRowClassName(ticket: TicketItem) {
  if (isOverdueTicket(ticket)) {
    return "bg-red-50/80 hover:bg-red-50"
  }
  if (ticket.currentAssigneeId <= 0 && !isClosedStatus(ticket.status)) {
    return "bg-amber-50/70 hover:bg-amber-50"
  }
  if (isRiskTicket(ticket)) {
    return "bg-orange-50/60 hover:bg-orange-50"
  }
  return ""
}

function parseSavedTicketView(item: TicketSavedView): SavedTicketView | null {
  const filters = item.filters
  if (!filters || typeof filters !== "object") {
    return null
  }
  return {
    id: item.id,
    name: item.name,
    keywordInput: typeof filters.keywordInput === "string" ? filters.keywordInput : "",
    keyword: typeof filters.keyword === "string" ? filters.keyword : "",
    statusFilter: typeof filters.statusFilter === "string" ? filters.statusFilter : "all",
    priorityFilter: typeof filters.priorityFilter === "string" ? filters.priorityFilter : "all",
    severityFilter: typeof filters.severityFilter === "string" ? filters.severityFilter : "all",
    tagFilter:
      typeof filters.tagFilter === "string"
        ? filters.tagFilter
        : typeof filters.categoryFilter === "string"
          ? filters.categoryFilter
          : "all",
    teamFilter: typeof filters.teamFilter === "string" ? filters.teamFilter : "all",
    assigneeFilter: typeof filters.assigneeFilter === "string" ? filters.assigneeFilter : "all",
    sourceFilter: typeof filters.sourceFilter === "string" ? filters.sourceFilter : "all",
    watchFilter: typeof filters.watchFilter === "string" ? filters.watchFilter : "all",
    quickView: typeof filters.quickView === "string" ? (filters.quickView as QuickViewKey) : "all",
  }
}

export default function TicketsPage() {
  const [result, setResult] = useState<{ results: TicketItem[]; page: Paging }>({
    results: [],
    page: emptyPaging,
  })
  const [summary, setSummary] = useState<TicketSummary>(emptySummary)
  const [loading, setLoading] = useState(true)
  const [saving, setSaving] = useState(false)
  const [dialogOpen, setDialogOpen] = useState(false)
  const [editingItemId, setEditingItemId] = useState<number | null>(null)
  const [keywordInput, setKeywordInput] = useState("")
  const [keyword, setKeyword] = useState("")
  const [statusFilter, setStatusFilter] = useState("all")
  const [priorityFilter, setPriorityFilter] = useState("all")
  const [severityFilter, setSeverityFilter] = useState("all")
  const [tagFilter, setTagFilter] = useState("all")
  const [teamFilter, setTeamFilter] = useState("all")
  const [assigneeFilter, setAssigneeFilter] = useState("all")
  const [sourceFilter, setSourceFilter] = useState("all")
  const [watchFilter, setWatchFilter] = useState("all")
  const [quickView, setQuickView] = useState<QuickViewKey>("all")
  const [savedViews, setSavedViews] = useState<SavedTicketView[]>([])
  const [activeSavedViewId, setActiveSavedViewId] = useState("all")
  const [teams, setTeams] = useState<AdminAgentTeam[]>([])
  const [agents, setAgents] = useState<AdminAgentProfile[]>([])
  const [tags, setTags] = useState<TagTree[]>([])
  const [priorities, setPriorities] = useState<TicketPriorityConfig[]>([])
  const [actionLoadingId, setActionLoadingId] = useState<number | null>(null)
  const [selectedTicketIds, setSelectedTicketIds] = useState<number[]>([])
  const [assignDialogOpen, setAssignDialogOpen] = useState(false)
  const [statusDialogOpen, setStatusDialogOpen] = useState(false)
  const [closeDialogOpen, setCloseDialogOpen] = useState(false)
  const [reopenDialogOpen, setReopenDialogOpen] = useState(false)
  const [actionTicket, setActionTicket] = useState<TicketItem | null>(null)
  const currentUserId = readSession()?.user?.id ?? 0

  const activeStatusFilter = useMemo(() => {
    if (quickView === "pending_customer") {
      return "pending_customer"
    }
    if (quickView === "pending_internal") {
      return "pending_internal"
    }
    return statusFilter === "all" ? undefined : statusFilter
  }, [quickView, statusFilter])

  const activeWatchFilter = quickView === "watching" ? 1 : watchFilter === "watching" ? 1 : undefined
  const activeCollaborationFilter = quickView === "collaboration" ? 1 : undefined
  const activeCollaboratingFilter = quickView === "participating" ? 1 : undefined
  const activeMentionedFilter = quickView === "mentioned" ? 1 : undefined
  const activeMineFilter = quickView === "mine" ? 1 : undefined
  const activeUnassignedFilter = quickView === "unassigned" ? 1 : undefined
  const activeOverdueFilter = quickView === "overdue" ? 1 : undefined

  const loadSummary = useCallback(async () => {
    try {
      const data = await fetchTicketSummary()
      setSummary(data)
    } catch (error) {
      toast.error(error instanceof Error ? error.message : "加载工单汇总失败")
    }
  }, [])

  const loadSavedViews = useCallback(async () => {
    try {
      const data = await fetchTicketViews()
      const views = Array.isArray(data)
        ? data
            .map(parseSavedTicketView)
            .filter((item): item is SavedTicketView => item !== null)
        : []
      setSavedViews(views)
    } catch (error) {
      toast.error(error instanceof Error ? error.message : "加载保存视图失败")
    }
  }, [])

  const loadTickets = useCallback(async () => {
    setLoading(true)
    try {
      const data = await fetchTickets({
        page: result.page.page,
        limit: result.page.limit,
        keyword: keyword.trim() || undefined,
        status: activeStatusFilter,
        priority: priorityFilter === "all" ? undefined : Number(priorityFilter),
        severity: severityFilter === "all" ? undefined : Number(severityFilter),
        tagId: tagFilter === "all" ? undefined : Number(tagFilter),
        currentTeamId: teamFilter === "all" ? undefined : Number(teamFilter),
        currentAssigneeId: assigneeFilter === "all" ? undefined : Number(assigneeFilter),
        source: sourceFilter === "all" ? undefined : sourceFilter,
        watching: activeWatchFilter,
        collaboration: activeCollaborationFilter,
        collaborating: activeCollaboratingFilter,
        mentioned: activeMentionedFilter,
        mine: activeMineFilter,
        unassigned: activeUnassignedFilter,
        overdue: activeOverdueFilter,
      })
      setResult({
        results: Array.isArray(data.results) ? data.results : [],
        page: data.page ?? emptyPaging,
      })
    } catch (error) {
      toast.error(error instanceof Error ? error.message : "加载工单失败")
    } finally {
      setLoading(false)
    }
  }, [
    activeMineFilter,
    activeOverdueFilter,
    activeStatusFilter,
    activeUnassignedFilter,
    activeWatchFilter,
    activeCollaborationFilter,
    activeCollaboratingFilter,
    activeMentionedFilter,
    assigneeFilter,
    tagFilter,
    keyword,
    priorityFilter,
    result.page.limit,
    result.page.page,
    severityFilter,
    sourceFilter,
    teamFilter,
  ])

  useEffect(() => {
    void loadTickets()
  }, [loadTickets])

  useEffect(() => {
    setSelectedTicketIds((current) =>
      current.filter((ticketId) => result.results.some((item) => item.id === ticketId)),
    )
  }, [result.results])

  useEffect(() => {
    void loadSummary()
  }, [loadSummary])

  useEffect(() => {
    void loadSavedViews()
  }, [loadSavedViews])

  useEffect(() => {
    void (async () => {
      const [teamData, agentData, tagData, priorityData] = await Promise.all([
        fetchAgentTeamsAll(),
        fetchAgentProfilesAll(),
        fetchTagsAll(),
        fetchTicketPriorityConfigsAll(),
      ])
      setTeams(Array.isArray(teamData) ? teamData : [])
      setAgents(Array.isArray(agentData) ? agentData : [])
      setTags(Array.isArray(tagData) ? tagData : [])
      setPriorities(Array.isArray(priorityData) ? priorityData : [])
    })()
  }, [])

  function resetToFirstPage() {
    setResult((current) => ({
      ...current,
      page: { ...current.page, page: 1 },
    }))
  }

  function applyFilters() {
    setKeyword(keywordInput)
    setActiveSavedViewId("all")
    resetToFirstPage()
  }

  function buildCurrentView(name: string, existingId?: number): SavedTicketView {
    return {
      id: existingId ?? 0,
      name,
      keywordInput,
      keyword,
      statusFilter,
      priorityFilter,
      severityFilter,
      tagFilter,
      teamFilter,
      assigneeFilter,
      sourceFilter,
      watchFilter,
      quickView,
    }
  }

  function applySavedView(view: SavedTicketView) {
    setKeywordInput(view.keywordInput)
    setKeyword(view.keyword)
    setStatusFilter(view.statusFilter)
    setPriorityFilter(view.priorityFilter)
    setSeverityFilter(view.severityFilter)
    setTagFilter(view.tagFilter)
    setTeamFilter(view.teamFilter)
    setAssigneeFilter(view.assigneeFilter)
    setSourceFilter(view.sourceFilter)
    setWatchFilter(view.watchFilter)
    setQuickView(view.quickView)
    setActiveSavedViewId(String(view.id))
    setResult((current) => ({
      ...current,
      page: { ...current.page, page: 1 },
    }))
  }

  function resetAllFilters() {
    setKeywordInput("")
    setKeyword("")
    setStatusFilter("all")
    setPriorityFilter("all")
    setSeverityFilter("all")
    setTagFilter("all")
    setTeamFilter("all")
    setAssigneeFilter("all")
    setSourceFilter("all")
    setWatchFilter("all")
    setQuickView("all")
    setActiveSavedViewId("all")
    resetToFirstPage()
  }

  async function handleSaveCurrentView() {
    const currentView = activeSavedViewId === "all"
      ? null
      : savedViews.find((item) => String(item.id) === activeSavedViewId) ?? null
    const defaultName = currentView?.name ?? ""
    const name = window.prompt("输入视图名称", defaultName)?.trim()
    if (!name) {
      return
    }
    const nextView = buildCurrentView(name, currentView?.id)
    try {
      const saved = await saveTicketView({
        id: nextView.id > 0 ? nextView.id : undefined,
        name: nextView.name,
        filters: {
          keywordInput: nextView.keywordInput,
          keyword: nextView.keyword,
          statusFilter: nextView.statusFilter,
          priorityFilter: nextView.priorityFilter,
          severityFilter: nextView.severityFilter,
          tagFilter: nextView.tagFilter,
          teamFilter: nextView.teamFilter,
          assigneeFilter: nextView.assigneeFilter,
          sourceFilter: nextView.sourceFilter,
          watchFilter: nextView.watchFilter,
          quickView: nextView.quickView,
        },
      })
      const parsed = parseSavedTicketView(saved)
      if (parsed) {
        setSavedViews((current) => {
          const exists = current.some((item) => item.id === parsed.id)
          return exists ? current.map((item) => (item.id === parsed.id ? parsed : item)) : [parsed, ...current]
        })
        setActiveSavedViewId(String(parsed.id))
      }
      toast.success(currentView ? "视图已更新" : "视图已保存")
    } catch (error) {
      toast.error(error instanceof Error ? error.message : "保存视图失败")
    }
  }

  async function handleDeleteSavedView(viewId: number) {
    const currentView = savedViews.find((item) => item.id === viewId)
    if (!currentView) {
      return
    }
    const confirmed = window.confirm(`确认删除视图「${currentView.name}」吗？`)
    if (!confirmed) {
      return
    }
    try {
      await deleteTicketView(currentView.id)
      setSavedViews((current) => current.filter((item) => item.id !== currentView.id))
      if (activeSavedViewId === String(currentView.id)) {
        setActiveSavedViewId("all")
      }
      toast.success("视图已删除")
    } catch (error) {
      toast.error(error instanceof Error ? error.message : "删除视图失败")
    }
  }

  function handleFilterKeyDown(event: React.KeyboardEvent<HTMLInputElement>) {
    if (event.key !== "Enter") {
      return
    }
    event.preventDefault()
    applyFilters()
  }

  function openCreateDialog() {
    setEditingItemId(null)
    setDialogOpen(true)
  }

  function openEditDialog(item: TicketItem) {
    setEditingItemId(item.id)
    setDialogOpen(true)
  }

  function openAssignDialog(item: TicketItem) {
    setActionTicket(item)
    setAssignDialogOpen(true)
  }

  function openStatusDialog(item: TicketItem) {
    setActionTicket(item)
    setStatusDialogOpen(true)
  }

  function openCloseDialog(item: TicketItem) {
    setActionTicket(item)
    setCloseDialogOpen(true)
  }

  function openReopenDialog(item: TicketItem) {
    setActionTicket(item)
    setReopenDialogOpen(true)
  }

  function handleDialogOpenChange(open: boolean) {
    if (saving) {
      return
    }
    if (!open) {
      setEditingItemId(null)
    }
    setDialogOpen(open)
  }

  async function refreshAll() {
    await Promise.all([loadSummary(), loadTickets()])
  }

  async function handleSubmit(
    payload: Parameters<typeof createTicket>[0] | Parameters<typeof updateTicket>[0],
  ) {
    if (saving) {
      return
    }
    setSaving(true)
    try {
      if ("ticketId" in payload) {
        await updateTicket(payload)
        toast.success("工单已更新")
      } else {
        await createTicket(payload)
        toast.success("工单已创建")
      }
      setDialogOpen(false)
      setEditingItemId(null)
      await refreshAll()
    } catch (error) {
      toast.error(error instanceof Error ? error.message : "保存工单失败")
    } finally {
      setSaving(false)
    }
  }

  async function handleWatchToggle(item: TicketItem) {
    setActionLoadingId(item.id)
    try {
      if (item.watchedByMe) {
        await unwatchTicket(item.id)
        toast.success("已取消关注")
      } else {
        await watchTicket(item.id)
        toast.success("已关注工单")
      }
      await refreshAll()
    } catch (error) {
      toast.error(error instanceof Error ? error.message : "更新关注状态失败")
    } finally {
      setActionLoadingId(null)
    }
  }

  function toggleSelectTicket(ticketId: number, checked: boolean) {
    setSelectedTicketIds((current) => {
      if (checked) {
        if (current.includes(ticketId)) {
          return current
        }
        return current.concat(ticketId)
      }
      return current.filter((item) => item !== ticketId)
    })
  }

  function handleSelectAll(checked: boolean) {
    setSelectedTicketIds(checked ? result.results.map((item) => item.id) : [])
  }

  async function handleBatchWatch(watched: boolean) {
    if (selectedTicketIds.length === 0) {
      toast.error("请先选择工单")
      return
    }
    setSaving(true)
    try {
      await batchWatchTickets({ ticketIds: selectedTicketIds, watched })
      toast.success(watched ? `已批量关注 ${selectedTicketIds.length} 张工单` : `已批量取消关注 ${selectedTicketIds.length} 张工单`)
      setSelectedTicketIds([])
      await refreshAll()
    } catch (error) {
      toast.error(error instanceof Error ? error.message : "批量更新关注失败")
    } finally {
      setSaving(false)
    }
  }

  const tagOptions = [{ value: "all", label: "全部标签" }].concat(
    buildTagOptions(tags),
  )
  const priorityOptions = [{ value: "all", label: "全部优先级" }].concat(
    priorities.map((priority) => ({
      value: String(priority.id),
      label: priority.name,
    })),
  )

  const teamOptions = [{ value: "all", label: "全部团队" }].concat(
    teams.map((team) => ({ value: String(team.id), label: team.name })),
  )

  const agentOptions = [{ value: "all", label: "全部处理人" }].concat(
    agents.map((agent) => ({
      value: String(agent.userId),
      label: agent.displayName || agent.nickname || agent.username || `客服#${agent.userId}`,
    })),
  )

  const quickViews: Array<{
    key: QuickViewKey
    label: string
    description: string
    count: number
  }> = [
    { key: "all", label: "全部工单", description: "工单总量", count: summary.all },
    { key: "mine", label: "我的工单", description: "当前指派给我", count: summary.mine },
    { key: "collaboration", label: "协作相关", description: "我参与或提及我的工单", count: summary.collaboration },
    { key: "participating", label: "我参与的", description: "我是协作人的工单", count: summary.participating },
    { key: "mentioned", label: "提及我的", description: "内部备注里提到了我", count: summary.mentioned },
    { key: "unassigned", label: "待分配", description: "尚未指派处理人", count: summary.unassigned },
    { key: "watching", label: "我的关注", description: "我在跟进的工单", count: summary.watching },
    {
      key: "pending_customer",
      label: "待客户反馈",
      description: "等待客户补充信息",
      count: summary.pendingCustomer,
    },
    {
      key: "pending_internal",
      label: "待内部处理",
      description: "等待内部协作处理",
      count: summary.pendingInternal,
    },
    { key: "overdue", label: "已超时", description: "解决 SLA 已超时", count: summary.overdue },
  ] 

  const allSelected =
    result.results.length > 0 && selectedTicketIds.length === result.results.length

  const displayResults = useMemo(() => {
    const list = [...result.results]
    list.sort((left, right) => {
      const leftOverdue = isOverdueTicket(left)
      const rightOverdue = isOverdueTicket(right)
      if (leftOverdue !== rightOverdue) {
        return leftOverdue ? -1 : 1
      }

      if (quickView === "unassigned") {
        const leftUnassigned = left.currentAssigneeId <= 0 ? 1 : 0
        const rightUnassigned = right.currentAssigneeId <= 0 ? 1 : 0
        if (leftUnassigned !== rightUnassigned) {
          return rightUnassigned - leftUnassigned
        }
      }

      const leftDeadline = getResolveDeadlineTime(left)
      const rightDeadline = getResolveDeadlineTime(right)
      if (leftDeadline !== null || rightDeadline !== null) {
        if (leftDeadline === null) {
          return 1
        }
        if (rightDeadline === null) {
          return -1
        }
        if (leftDeadline !== rightDeadline) {
          return leftDeadline - rightDeadline
        }
      }

      if (left.priority !== right.priority) {
        return right.priority - left.priority
      }

      return (right.id ?? 0) - (left.id ?? 0)
    })
    return list
  }, [quickView, result.results])

  const savedViewOptions = useMemo(
    () =>
      [{ value: "all", label: "筛选视图" }].concat(
        savedViews.map((item) => ({
          value: String(item.id),
          label: item.name,
        })),
      ),
    [savedViews],
  )

  return (
    <div className="min-h-0 flex-1 overflow-auto bg-muted/20 p-4 md:p-6">
      <div className="flex w-full flex-col gap-4">
        <div className="flex flex-col gap-3 xl:flex-row xl:items-center xl:justify-between">
          <div>
            <h1 className="text-xl font-semibold">工单</h1>
            {/* <p className="mt-1 text-sm text-muted-foreground">
              作为队列工作台处理异步问题、分派、流转与关闭
            </p> */}
            <div className="mt-1 flex flex-wrap gap-2 text-xs text-muted-foreground">
              <span className="rounded bg-red-50 px-2 py-1 text-red-700">红色：已超时</span>
              <span className="rounded bg-amber-50 px-2 py-1 text-amber-700">黄色：待分配</span>
              <span className="rounded bg-orange-50 px-2 py-1 text-orange-700">橙色：即将超时</span>
            </div>
          </div>
          <div className="flex items-center gap-2">
            <div className="w-48">
              <OptionCombobox
                value={activeSavedViewId}
                onChange={(value) => {
                  if (value === "all") {
                    setActiveSavedViewId("all")
                    return
                  }
                  const nextView = savedViews.find((item) => String(item.id) === value)
                  if (nextView) {
                    applySavedView(nextView)
                  }
                }}
                placeholder="保存视图"
                options={savedViewOptions}
                renderOptionAction={(option) => {
                  if (option.value === "all") {
                    return null
                  }
                  const viewId = Number(option.value)
                  if (!Number.isFinite(viewId)) {
                    return null
                  }
                  return (
                    <Button
                      type="button"
                      variant="ghost"
                      size="icon"
                      className="size-7 text-muted-foreground hover:text-destructive"
                      onClick={() => void handleDeleteSavedView(viewId)}
                    >
                      <Trash2Icon className="size-4" />
                    </Button>
                  )
                }}
              />
            </div>
            <Button variant="outline" onClick={handleSaveCurrentView}>
              <SaveIcon className="size-4" />
              保存视图
            </Button>
            <Button onClick={openCreateDialog}>
              <PlusIcon className="size-4" />
              新建工单
            </Button>
          </div>
        </div>


        <div className="rounded-lg border bg-background/80 p-2">
          <div className="flex flex-wrap gap-2">
            {quickViews.map((view) => {
              const active = quickView === view.key
              return (
                <button
                  key={view.key}
                  type="button"
                  className={`inline-flex min-w-0 items-center gap-2 rounded-md border px-3 py-1.5 text-sm transition ${
                    active
                      ? "border-primary bg-primary/8 text-primary shadow-sm"
                      : "border-border bg-background text-foreground hover:border-primary/40 hover:bg-muted/60"
                  }`}
                  onClick={() => {
                    setQuickView(view.key)
                    resetToFirstPage()
                  }}
                >
                  <span className="truncate font-medium">{view.label}</span>
                  <span
                    className={`rounded-full px-1.5 py-0.5 text-[11px] font-semibold tabular-nums ${
                      active ? "bg-primary/12 text-primary" : "bg-muted text-muted-foreground"
                    }`}
                  >
                    {view.count}
                  </span>
                </button>
              )
            })}
          </div>
        </div>

        <div className="grid gap-3 lg:grid-cols-4 xl:grid-cols-[minmax(0,1.5fr)_repeat(8,minmax(0,1fr))_auto]">
          <div className="relative">
            <SearchIcon className="pointer-events-none absolute top-1/2 left-3 size-4 -translate-y-1/2 text-muted-foreground" />
            <Input
              className="pl-9"
              value={keywordInput}
              placeholder="搜索工单号、标题或描述"
              onChange={(event) => setKeywordInput(event.target.value)}
              onKeyDown={handleFilterKeyDown}
            />
          </div>
          <OptionCombobox
            value={statusFilter}
            onChange={(value) => {
              setStatusFilter(value)
              setQuickView("all")
              resetToFirstPage()
            }}
            placeholder="全部状态"
            options={[
              { value: "all", label: "全部状态" },
              { value: "new", label: "新建" },
              { value: "open", label: "处理中" },
              { value: "pending_customer", label: "待客户反馈" },
              { value: "pending_internal", label: "待内部处理" },
              { value: "resolved", label: "已解决" },
              { value: "closed", label: "已关闭" },
              { value: "cancelled", label: "已取消" },
            ]}
          />
          <OptionCombobox
            value={tagFilter}
            onChange={(value) => {
              setTagFilter(value)
              setQuickView("all")
              resetToFirstPage()
            }}
            placeholder="全部标签"
            options={tagOptions}
          />
          <OptionCombobox
            value={priorityFilter}
            onChange={(value) => {
              setPriorityFilter(value)
              setQuickView("all")
              resetToFirstPage()
            }}
            placeholder="全部优先级"
            options={priorityOptions}
          />
          <OptionCombobox
            value={severityFilter}
            onChange={(value) => {
              setSeverityFilter(value)
              setQuickView("all")
              resetToFirstPage()
            }}
            placeholder="全部严重度"
            options={[
              { value: "all", label: "全部严重度" },
              { value: "1", label: "轻微" },
              { value: "2", label: "一般" },
              { value: "3", label: "严重" },
            ]}
          />
          <OptionCombobox
            value={sourceFilter}
            onChange={(value) => {
              setSourceFilter(value)
              setQuickView("all")
              resetToFirstPage()
            }}
            placeholder="全部来源"
            options={[
              { value: "all", label: "全部来源" },
              { value: "manual", label: "手动创建" },
              { value: "conversation", label: "会话转工单" },
              { value: "email", label: "邮件" },
              { value: "api", label: "API" },
              { value: "system", label: "系统" },
            ]}
          />
          <OptionCombobox
            value={teamFilter}
            onChange={(value) => {
              setTeamFilter(value)
              setQuickView("all")
              resetToFirstPage()
            }}
            placeholder="全部团队"
            options={teamOptions}
          />
          <OptionCombobox
            value={assigneeFilter}
            onChange={(value) => {
              setAssigneeFilter(value)
              setQuickView("all")
              resetToFirstPage()
            }}
            placeholder="全部处理人"
            options={agentOptions}
          />
          <OptionCombobox
            value={watchFilter}
            onChange={(value) => {
              setWatchFilter(value)
              setQuickView("all")
              resetToFirstPage()
            }}
            placeholder="全部关注"
            options={[
              { value: "all", label: "全部关注" },
              { value: "watching", label: "我关注的" },
            ]}
          />
          <div className="flex gap-2">
            <Button variant="outline" onClick={applyFilters}>
              查询
            </Button>
            <Button variant="outline" onClick={() => void refreshAll()}>
              <RefreshCcwIcon className="size-4" />
            </Button>
            <Button variant="ghost" onClick={resetAllFilters}>
              重置
            </Button>
          </div>
        </div>

        <div className="overflow-hidden rounded-lg border bg-background">
          {selectedTicketIds.length > 0 ? (
            <div className="flex flex-col gap-3 border-b bg-muted/30 px-4 py-3 lg:flex-row lg:items-center lg:justify-between">
              <div className="text-sm text-muted-foreground">
                已选择 <span className="font-medium text-foreground">{selectedTicketIds.length}</span> 张工单
              </div>
              <div className="flex flex-wrap gap-2">
                <Button
                  variant="outline"
                  size="sm"
                  onClick={() => {
                    setActionTicket(null)
                    setAssignDialogOpen(true)
                  }}
                  disabled={saving}
                >
                  批量指派
                </Button>
                <Button
                  variant="outline"
                  size="sm"
                  onClick={() => {
                    setActionTicket(null)
                    setStatusDialogOpen(true)
                  }}
                  disabled={saving}
                >
                  批量改状态
                </Button>
                <Button
                  variant="outline"
                  size="sm"
                  onClick={() => void handleBatchWatch(true)}
                  disabled={saving}
                >
                  批量关注
                </Button>
                <Button
                  variant="outline"
                  size="sm"
                  onClick={() => void handleBatchWatch(false)}
                  disabled={saving}
                >
                  取消关注
                </Button>
                <Button variant="ghost" size="sm" onClick={() => setSelectedTicketIds([])} disabled={saving}>
                  清空选择
                </Button>
              </div>
            </div>
          ) : null}
          <Table>
            <TableHeader className="bg-muted/35">
              <TableRow>
                <TableHead className="w-10">
                  <Checkbox
                    checked={allSelected}
                    onCheckedChange={(checked) => handleSelectAll(Boolean(checked))}
                    aria-label="全选工单"
                  />
                </TableHead>
                <TableHead>工单</TableHead>
                <TableHead>客户</TableHead>
                <TableHead>标签</TableHead>
                <TableHead>优先级</TableHead>
                <TableHead>状态</TableHead>
                <TableHead>SLA 风险</TableHead>
                <TableHead>协作</TableHead>
                <TableHead>处理人</TableHead>
                <TableHead>团队</TableHead>
                <TableHead>关注</TableHead>
                <TableHead>更新时间</TableHead>
                <TableHead className="text-right">操作</TableHead>
              </TableRow>
            </TableHeader>
            <TableBody>
              {loading ? (
                <TableRow>
                  <TableCell colSpan={13} className="h-32 text-center text-muted-foreground">
                    加载中...
                  </TableCell>
                </TableRow>
              ) : result.results.length > 0 ? (
                displayResults.map((item) => (
                  <TableRow key={item.id} className={getTicketRowClassName(item)}>
                    <TableCell>
                      <Checkbox
                        checked={selectedTicketIds.includes(item.id)}
                        onCheckedChange={(checked) => toggleSelectTicket(item.id, Boolean(checked))}
                        aria-label={`选择工单 ${item.ticketNo}`}
                      />
                    </TableCell>
                    <TableCell className="min-w-64">
                      <div className="space-y-1">
                        <div className="font-medium">{item.title}</div>
                        <div className="flex flex-wrap items-center gap-2 text-xs text-muted-foreground">
                          <span>{item.ticketNo}</span>
                          <span>{item.source || "manual"}</span>
                          {item.currentAssigneeId <= 0 && !isClosedStatus(item.status) ? (
                            <span className="rounded bg-amber-100 px-1.5 py-0.5 text-amber-700">
                              待分配
                            </span>
                          ) : null}
                          {item.pendingReason && !isClosedStatus(item.status) ? (
                            <span className="rounded bg-muted px-1.5 py-0.5">{item.pendingReason}</span>
                          ) : null}
                        </div>
                      </div>
                    </TableCell>
                    <TableCell>{item.customer?.name || "未绑定客户"}</TableCell>
                    <TableCell>
                      {item.tags && item.tags.length > 0 ? (
                        <div className="flex flex-wrap gap-1">
                          {item.tags.map((tag) => (
                            <Badge key={tag.id} variant="outline">
                              {tag.name}
                            </Badge>
                          ))}
                        </div>
                      ) : (
                        <span className="text-muted-foreground">未打标签</span>
                      )}
                    </TableCell>
                    <TableCell>
                      <TicketPriorityBadge priority={item.priority} priorityName={item.priorityName} />
                    </TableCell>
                    <TableCell>
                      <TicketStatusBadge status={item.status} />
                    </TableCell>
                    <TableCell>
                      <TicketSLABadge ticket={item} />
                    </TableCell>
                    <TableCell>
                      <div className="flex flex-wrap gap-1">
                        {quickView === "participating" || quickView === "collaboration" ? (
                          <Badge variant="outline">协作中</Badge>
                        ) : null}
                        {quickView === "mentioned" || quickView === "collaboration" ? (
                          <Badge variant="outline" className="border-amber-300 bg-amber-50 text-amber-800">
                            提及我
                          </Badge>
                        ) : null}
                        {item.currentAssigneeId === currentUserId ? (
                          <Badge variant="outline" className="border-blue-300 bg-blue-50 text-blue-800">
                            负责人
                          </Badge>
                        ) : null}
                      </div>
                    </TableCell>
                    <TableCell>{item.currentAssigneeName || "未指派"}</TableCell>
                    <TableCell>{item.currentTeamName || "未分组"}</TableCell>
                    <TableCell>
                      <Button
                        variant="ghost"
                        size="sm"
                        disabled={actionLoadingId === item.id}
                        onClick={() => void handleWatchToggle(item)}
                      >
                        <StarIcon
                          className={`size-4 ${item.watchedByMe ? "fill-current text-amber-500" : ""}`}
                        />
                        {item.watchedByMe ? "已关注" : "关注"}
                      </Button>
                    </TableCell>
                    <TableCell>{item.updatedAt ? formatDateTime(item.updatedAt) : "—"}</TableCell>
                    <TableCell className="text-right">
                      <div className="flex justify-end gap-2">
                        <Link href={`/tickets/detail?id=${item.id}`} target="_blank" rel="noreferrer">
                          <Button variant="outline" size="sm">
                            <ClipboardListIcon className="size-4" />
                            详情
                          </Button>
                        </Link>
                        <Button variant="ghost" size="sm" onClick={() => openAssignDialog(item)}>
                          <ArrowRightLeftIcon className="size-4" />
                          指派
                        </Button>
                        <Button variant="ghost" size="sm" onClick={() => openStatusDialog(item)}>
                          <SquarePenIcon className="size-4" />
                          状态
                        </Button>
                        {item.status === "closed" ? (
                          <Button variant="ghost" size="sm" onClick={() => openReopenDialog(item)}>
                            重开
                          </Button>
                        ) : (
                          <Button variant="ghost" size="sm" onClick={() => openCloseDialog(item)}>
                            <CircleOffIcon className="size-4" />
                            关闭
                          </Button>
                        )}
                        <Button variant="ghost" size="sm" onClick={() => openEditDialog(item)}>
                          编辑
                        </Button>
                      </div>
                    </TableCell>
                  </TableRow>
                ))
              ) : (
                <TableRow>
                  <TableCell colSpan={13} className="h-32 text-center text-muted-foreground">
                    暂无符合当前筛选条件的工单
                  </TableCell>
                </TableRow>
              )}
            </TableBody>
          </Table>
        </div>

        <ListPagination
          page={result.page.page}
          total={result.page.total}
          limit={result.page.limit}
          loading={loading}
          onPageChange={(page) =>
            setResult((current) => ({
              ...current,
              page: { ...current.page, page },
            }))
          }
          onLimitChange={(limit) =>
            setResult((current) => ({
              ...current,
              page: { ...current.page, page: 1, limit },
            }))
          }
        />
      </div>

      <EditDialog
        open={dialogOpen}
        saving={saving}
        itemId={editingItemId}
        onOpenChange={handleDialogOpenChange}
        onSubmit={handleSubmit}
      />
      <TicketAssignDialog
        open={assignDialogOpen}
        ticketId={actionTicket?.id ?? null}
        ticketIds={actionTicket ? undefined : selectedTicketIds}
        currentTeamId={actionTicket?.currentTeamId}
        currentAssigneeId={actionTicket?.currentAssigneeId}
        onOpenChange={(open) => {
          setAssignDialogOpen(open)
          if (!open) {
            setActionTicket(null)
            setSelectedTicketIds((current) => current)
          }
        }}
        onSuccess={async () => {
          setSelectedTicketIds([])
          await refreshAll()
        }}
      />
      <TicketStatusDialog
        open={statusDialogOpen}
        ticketId={actionTicket?.id ?? null}
        ticketIds={actionTicket ? undefined : selectedTicketIds}
        currentStatus={actionTicket?.status}
        onOpenChange={(open) => {
          setStatusDialogOpen(open)
          if (!open) {
            setActionTicket(null)
          }
        }}
        onSuccess={async () => {
          setSelectedTicketIds([])
          await refreshAll()
        }}
      />
      <TicketReasonDialog
        open={closeDialogOpen}
        mode="close"
        ticketId={actionTicket?.id ?? null}
        defaultReason={actionTicket?.closeReason || "处理完成"}
        onOpenChange={(open) => {
          setCloseDialogOpen(open)
          if (!open) {
            setActionTicket(null)
          }
        }}
        onSuccess={refreshAll}
      />
      <TicketReasonDialog
        open={reopenDialogOpen}
        mode="reopen"
        ticketId={actionTicket?.id ?? null}
        defaultReason="客户有新反馈"
        onOpenChange={(open) => {
          setReopenDialogOpen(open)
          if (!open) {
            setActionTicket(null)
          }
        }}
        onSuccess={refreshAll}
      />
    </div>
  )
}
