<template>
  <div class="tickets-page">
    <div class="page-header">
      <div>
        <h2 class="page-title">🎫 工单处理</h2>
        <p class="page-desc">处理用户提交的技术支持工单，分配并跟进处理进度</p>
      </div>
      <a-space>
        <a-button @click="loadTickets" :loading="loading">
          <template #icon><ReloadOutlined /></template>
          刷新
        </a-button>
      </a-space>
    </div>

    <!-- 统计卡片 -->
    <a-row :gutter="[16, 16]" class="mb-6">
      <a-col :xs="12" :md="6" v-for="stat in statCards" :key="stat.key">
        <div
          class="stat-card"
          :class="[stat.color, { active: filterStatus === stat.key }]"
          @click="handleStatFilter(stat.key)"
        >
          <div class="stat-icon">{{ stat.icon }}</div>
          <div class="stat-info">
            <div class="stat-value">{{ stat.value }}</div>
            <div class="stat-label">{{ stat.label }}</div>
          </div>
        </div>
      </a-col>
    </a-row>

    <!-- 工单列表 -->
    <div class="panel">
      <div class="panel-header">
        <span class="panel-title">📋 工单列表</span>
        <a-space wrap>
          <a-select v-model:value="filterStatus" style="width: 130px" @change="handleSearch">
            <a-select-option value="">全部状态</a-select-option>
            <a-select-option value="pending">待处理</a-select-option>
            <a-select-option value="assigned">已分配</a-select-option>
            <a-select-option value="processing">处理中</a-select-option>
            <a-select-option value="resolved">已解决</a-select-option>
            <a-select-option value="closed">已关闭</a-select-option>
          </a-select>
          <a-select v-model:value="filterPriority" style="width: 110px" @change="handleSearch">
            <a-select-option value="">全部优先级</a-select-option>
            <a-select-option value="urgent">紧急</a-select-option>
            <a-select-option value="high">高</a-select-option>
            <a-select-option value="normal">普通</a-select-option>
            <a-select-option value="low">低</a-select-option>
          </a-select>
          <a-select v-model:value="filterCategory" style="width: 110px" @change="handleSearch">
            <a-select-option value="">全部分类</a-select-option>
            <a-select-option value="bug">Bug反馈</a-select-option>
            <a-select-option value="feature">功能请求</a-select-option>
            <a-select-option value="consultation">咨询</a-select-option>
            <a-select-option value="complaint">投诉</a-select-option>
            <a-select-option value="other">其他</a-select-option>
          </a-select>
          <a-input-search
            v-model:value="searchKeyword"
            placeholder="搜索工单标题"
            style="width: 200px"
            @search="handleSearch"
          />
        </a-space>
      </div>

      <a-table
        :columns="columns"
        :data-source="tickets"
        :loading="loading"
        :pagination="pagination"
        row-key="ticketId"
        @change="handleTableChange"
        size="middle"
      >
        <template #bodyCell="{ column, record }">
          <!-- 工单信息 -->
          <template v-if="column.key === 'ticketInfo'">
            <div class="ticket-info">
              <div class="ticket-title">
                <a-tag v-if="record.hasUnread" color="red" style="font-size:10px;padding:0 4px">NEW</a-tag>
                {{ record.title }}
              </div>
              <div class="ticket-no">{{ record.ticketNo }}</div>
              <div class="ticket-meta">
                <span>来自：{{ record.submitUserName || '-' }}</span>
                <span v-if="record.productName" style="margin-left:8px">应用：{{ record.productName }}</span>
              </div>
            </div>
          </template>

          <!-- 分类 -->
          <template v-if="column.key === 'category'">
            <a-tag :color="categoryColor(record.category)">{{ categoryText(record.category) }}</a-tag>
          </template>

          <!-- 优先级 -->
          <template v-if="column.key === 'priority'">
            <span :class="['priority-badge', 'priority-' + record.priority]">
              {{ priorityText(record.priority) }}
            </span>
          </template>

          <!-- 状态 -->
          <template v-if="column.key === 'status'">
            <a-tag :color="statusColor(record.status)">{{ statusText(record.status) }}</a-tag>
          </template>

          <!-- 负责人 -->
          <template v-if="column.key === 'assignee'">
            <div v-if="record.assigneeName" class="assignee-cell">
              <a-avatar :size="24" :src="record.assigneeAvatar">
                <template #icon><UserOutlined /></template>
              </a-avatar>
              <span>{{ record.assigneeName }}</span>
            </div>
            <a-button v-else type="link" size="small" @click="handleAssign(record)">
              <PlusOutlined /> 分配
            </a-button>
          </template>

          <!-- 提交时间 -->
          <template v-if="column.key === 'createTime'">
            <span class="text-sm text-gray">{{ record.createTime?.substring(0, 16) || '-' }}</span>
          </template>

          <!-- 操作 -->
          <template v-if="column.key === 'action'">
            <a-space>
              <a-button type="link" size="small" @click="handleView(record)">处理</a-button>
              <a-dropdown :trigger="['click']">
                <a-button type="link" size="small">更多 <DownOutlined /></a-button>
                <template #overlay>
                  <a-menu @click="({ key }) => handleQuickStatus(key as string, record)">
                    <a-menu-item key="processing" v-if="['pending','assigned'].includes(record.status)">🔄 开始处理</a-menu-item>
                    <a-menu-item key="resolved" v-if="['processing','assigned'].includes(record.status)">✅ 标记已解决</a-menu-item>
                    <a-menu-item key="closed" v-if="record.status !== 'closed'">🔒 关闭工单</a-menu-item>
                    <a-menu-item key="rejected">❌ 拒绝工单</a-menu-item>
                  </a-menu>
                </template>
              </a-dropdown>
            </a-space>
          </template>
        </template>
      </a-table>
    </div>

    <!-- 工单详情/处理弹窗 -->
    <a-modal
      v-model:open="showDetailModal"
      :title="`工单处理：${currentTicket?.ticketNo || ''}`"
      width="780px"
      :footer="null"
      destroy-on-close
    >
      <template v-if="currentTicket">
        <!-- 基本信息 -->
        <a-descriptions :column="3" size="small" class="mb-4">
          <a-descriptions-item label="工单标题" :span="3">
            <strong>{{ currentTicket.title }}</strong>
          </a-descriptions-item>
          <a-descriptions-item label="状态">
            <a-tag :color="statusColor(currentTicket.status)">{{ statusText(currentTicket.status) }}</a-tag>
          </a-descriptions-item>
          <a-descriptions-item label="优先级">
            <span :class="['priority-badge', 'priority-' + currentTicket.priority]">{{ priorityText(currentTicket.priority) }}</span>
          </a-descriptions-item>
          <a-descriptions-item label="分类">
            <a-tag :color="categoryColor(currentTicket.category)">{{ categoryText(currentTicket.category) }}</a-tag>
          </a-descriptions-item>
          <a-descriptions-item label="提交人">{{ currentTicket.submitUserName || '-' }}</a-descriptions-item>
          <a-descriptions-item label="关联应用">{{ currentTicket.productName || '-' }}</a-descriptions-item>
          <a-descriptions-item label="负责人">{{ currentTicket.assigneeName || '未分配' }}</a-descriptions-item>
          <a-descriptions-item label="提交时间" :span="3">{{ currentTicket.createTime }}</a-descriptions-item>
        </a-descriptions>

        <!-- 工单内容 -->
        <div class="ticket-content-box">
          <div class="ticket-content-title">📝 工单内容</div>
          <div class="ticket-content-body">{{ currentTicket.content }}</div>
        </div>

        <!-- 回复区 -->
        <div class="reply-section">
          <div class="reply-title">💬 回复记录</div>
          <a-spin v-if="loadingReplies" style="padding:20px;display:block;text-align:center" />
          <div v-else-if="replies.length === 0" class="reply-empty">暂无回复</div>
          <div v-else class="reply-list">
            <div v-for="reply in replies" :key="reply.replyId" class="reply-item" :class="{ 'reply-staff': reply.isStaff }">
              <a-avatar :size="32" :src="reply.userAvatar">
                <template #icon><UserOutlined /></template>
              </a-avatar>
              <div class="reply-bubble">
                <div class="reply-meta">
                  <span class="reply-name">{{ reply.userName }}</span>
                  <a-tag v-if="reply.isStaff" color="blue" style="font-size:10px;padding:0 4px">客服</a-tag>
                  <span class="reply-time">{{ reply.createTime?.substring(0, 16) }}</span>
                </div>
                <div class="reply-content">{{ reply.content }}</div>
              </div>
            </div>
          </div>

          <!-- 回复输入框 -->
          <div class="reply-input-area">
            <a-textarea
              v-model:value="replyContent"
              :rows="3"
              placeholder="输入回复内容..."
              :maxlength="2000"
              show-count
            />
            <div class="reply-actions">
              <a-space>
                <a-select v-model:value="quickStatus" style="width: 140px" placeholder="同时更新状态">
                  <a-select-option value="">不更新状态</a-select-option>
                  <a-select-option value="processing">更新为处理中</a-select-option>
                  <a-select-option value="resolved">更新为已解决</a-select-option>
                  <a-select-option value="closed">更新为已关闭</a-select-option>
                </a-select>
                <a-button type="primary" :loading="replying" @click="handleSubmitReply">发送回复</a-button>
              </a-space>
            </div>
          </div>
        </div>
      </template>
    </a-modal>

    <!-- 分配弹窗 -->
    <a-modal
      v-model:open="showAssignModal"
      title="分配工单"
      :confirm-loading="assigning"
      @ok="confirmAssign"
    >
      <a-form layout="vertical">
        <a-form-item label="选择负责人" required>
          <a-select v-model:value="assigneeId" placeholder="请选择技术人员" style="width:100%">
            <a-select-option v-for="staff in staffList" :key="staff.userId" :value="staff.userId">
              {{ staff.nickname }}
            </a-select-option>
          </a-select>
        </a-form-item>
      </a-form>
    </a-modal>
  </div>
</template>

<script setup lang="ts">
import { ReloadOutlined, UserOutlined, PlusOutlined, DownOutlined } from '@ant-design/icons-vue'
import { message } from 'ant-design-vue'
import {
  getAllTickets, getTicketDetail, getTicketReplies, replyTicket,
  updateTicketStatus, assignTicket, getTechStaffList, getTicketStats,
} from '@/api/ticket/index'
import type { Ticket, TicketReply, TicketStatus } from '@/api/ticket/model'

definePageMeta({ layout: 'admin' })
useHead({ title: '工单处理 - 平台管理' })

const loading = ref(false)
const tickets = ref<Ticket[]>([])
const filterStatus = ref<TicketStatus | ''>('')
const filterPriority = ref('')
const filterCategory = ref('')
const searchKeyword = ref('')

const pagination = reactive({ current: 1, pageSize: 20, total: 0, showSizeChanger: true, showQuickJumper: true })

const statCards = reactive([
  { key: 'pending', icon: '⏳', label: '待处理', value: 0, color: 'orange' },
  { key: 'processing', icon: '🔄', label: '处理中', value: 0, color: 'blue' },
  { key: 'resolved', icon: '✅', label: '已解决', value: 0, color: 'green' },
  { key: '', icon: '📋', label: '全部工单', value: 0, color: 'gray' },
])

const columns = [
  { title: '工单信息', key: 'ticketInfo', width: 280 },
  { title: '分类', key: 'category', width: 100 },
  { title: '优先级', key: 'priority', width: 90 },
  { title: '状态', key: 'status', width: 100 },
  { title: '负责人', key: 'assignee', width: 140 },
  { title: '提交时间', key: 'createTime', width: 140 },
  { title: '操作', key: 'action', width: 150 },
]

// 详情弹窗
const showDetailModal = ref(false)
const currentTicket = ref<Ticket | null>(null)
const replies = ref<TicketReply[]>([])
const loadingReplies = ref(false)
const replyContent = ref('')
const replying = ref(false)
const quickStatus = ref('')

// 分配弹窗
const showAssignModal = ref(false)
const assigning = ref(false)
const assigneeId = ref<number | null>(null)
const assignTarget = ref<Ticket | null>(null)
const staffList = ref<{ userId: number; nickname: string; avatar: string }[]>([])

async function loadTickets() {
  loading.value = true
  try {
    const res = await getAllTickets({
      page: pagination.current,
      limit: pagination.pageSize,
      status: filterStatus.value as TicketStatus || undefined,
      priority: filterPriority.value as any || undefined,
      category: filterCategory.value as any || undefined,
      keywords: searchKeyword.value || undefined,
    })
    // ticket API 直接返回 axios response，data 字段即 {list, count}
    const data = (res as any)?.data ?? res
    tickets.value = data?.list || []
    pagination.total = data?.count || 0
    loadStats()
  } catch {
    message.error('加载工单列表失败')
  } finally {
    loading.value = false
  }
}

async function loadStats() {
  try {
    const res = await getTicketStats()
    const stats = (res as any)?.data ?? res
    statCards[0].value = stats?.pending || 0
    statCards[1].value = stats?.processing || 0
    statCards[2].value = stats?.resolved || 0
    statCards[3].value = stats?.total || 0
  } catch { /* ignore */ }
}

function handleStatFilter(key: string) {
  filterStatus.value = key as any
  pagination.current = 1
  loadTickets()
}

function handleSearch() {
  pagination.current = 1
  loadTickets()
}

function handleTableChange(pag: any) {
  pagination.current = pag.current
  pagination.pageSize = pag.pageSize
  loadTickets()
}

async function handleView(record: Ticket) {
  currentTicket.value = record
  showDetailModal.value = true
  replyContent.value = ''
  quickStatus.value = ''
  loadingReplies.value = true
  try {
    const res = await getTicketReplies(record.ticketId)
    const data = (res as any)?.data ?? res
    replies.value = Array.isArray(data) ? data : (data?.list || [])
  } catch {
    replies.value = []
  } finally {
    loadingReplies.value = false
  }
}

async function handleSubmitReply() {
  if (!replyContent.value.trim()) {
    message.warning('请输入回复内容')
    return
  }
  replying.value = true
  try {
    await replyTicket({ ticketId: currentTicket.value!.ticketId, content: replyContent.value })
    if (quickStatus.value) {
      await updateTicketStatus({ ticketId: currentTicket.value!.ticketId, status: quickStatus.value as TicketStatus })
    }
    message.success('回复已发送')
    replyContent.value = ''
    quickStatus.value = ''
    // 重新加载回复
    const res = await getTicketReplies(currentTicket.value!.ticketId)
    const data = (res as any)?.data ?? res
    replies.value = Array.isArray(data) ? data : (data?.list || [])
    loadTickets()
  } catch (e: any) {
    message.error(e?.message || '发送失败')
  } finally {
    replying.value = false
  }
}

async function handleQuickStatus(key: string, record: Ticket) {
  try {
    await updateTicketStatus({ ticketId: record.ticketId, status: key as TicketStatus })
    message.success('状态已更新')
    loadTickets()
  } catch (e: any) {
    message.error(e?.message || '操作失败')
  }
}

async function handleAssign(record: Ticket) {
  assignTarget.value = record
  assigneeId.value = null
  showAssignModal.value = true
  try {
    const res = await getTechStaffList()
    const data = (res as any)?.data ?? res
    staffList.value = Array.isArray(data) ? data : []
  } catch { staffList.value = [] }
}

async function confirmAssign() {
  if (!assigneeId.value) {
    message.warning('请选择负责人')
    return
  }
  assigning.value = true
  try {
    await assignTicket({ ticketId: assignTarget.value!.ticketId, assigneeId: assigneeId.value })
    message.success('工单已分配')
    showAssignModal.value = false
    loadTickets()
  } catch (e: any) {
    message.error(e?.message || '分配失败')
  } finally {
    assigning.value = false
  }
}

function statusText(status?: string) {
  const map: Record<string, string> = {
    pending: '待处理', assigned: '已分配', processing: '处理中',
    resolved: '已解决', closed: '已关闭', rejected: '已拒绝',
  }
  return map[status || ''] || status || '-'
}

function statusColor(status?: string) {
  const map: Record<string, string> = {
    pending: 'orange', assigned: 'blue', processing: 'processing',
    resolved: 'success', closed: 'default', rejected: 'error',
  }
  return map[status || ''] || 'default'
}

function priorityText(p?: string) {
  const map: Record<string, string> = { urgent: '紧急', high: '高', normal: '普通', low: '低' }
  return map[p || ''] || p || '-'
}

function categoryText(c?: string) {
  const map: Record<string, string> = { bug: 'Bug反馈', feature: '功能请求', consultation: '咨询', complaint: '投诉', other: '其他' }
  return map[c || ''] || c || '-'
}

function categoryColor(c?: string) {
  const map: Record<string, string> = { bug: 'error', feature: 'blue', consultation: 'cyan', complaint: 'warning', other: 'default' }
  return map[c || ''] || 'default'
}

onMounted(() => loadTickets())
</script>

<style scoped>
.tickets-page { min-height: 100%; }

.page-header {
  display: flex; align-items: center;
  justify-content: space-between; margin-bottom: 20px;
}
.page-title { font-size: 18px; font-weight: 700; color: #1f2937; margin: 0; }
.page-desc { font-size: 13px; color: #9ca3af; margin: 2px 0 0; }

.stat-card {
  display: flex; align-items: center; gap: 12px; padding: 16px;
  border-radius: 12px; border: 2px solid transparent; cursor: pointer; transition: all 0.2s;
}
.stat-card:hover { transform: translateY(-2px); box-shadow: 0 4px 12px rgba(0,0,0,0.08); }
.stat-card.active { box-shadow: 0 4px 12px rgba(0,0,0,0.12); }
.stat-card.blue { background: #eff6ff; border-color: #dbeafe; }
.stat-card.orange { background: #fff7ed; border-color: #fed7aa; }
.stat-card.green { background: #f0fdf4; border-color: #bbf7d0; }
.stat-card.gray { background: #f9fafb; border-color: #e5e7eb; }
.stat-card.active.blue { border-color: #3b82f6; }
.stat-card.active.orange { border-color: #f97316; }
.stat-card.active.green { border-color: #22c55e; }
.stat-icon { font-size: 28px; flex-shrink: 0; }
.stat-value { font-size: 22px; font-weight: 700; color: rgba(0,0,0,0.85); line-height: 1.2; }
.stat-label { font-size: 12px; color: rgba(0,0,0,0.45); margin-top: 2px; }

.panel { background: #fff; border: 1px solid #f0f0f0; border-radius: 12px; overflow: hidden; }
.panel-header {
  display: flex; align-items: center; justify-content: space-between;
  padding: 14px 18px; border-bottom: 1px solid #f5f5f5; flex-wrap: wrap; gap: 10px;
}
.panel-title { font-size: 14px; font-weight: 600; color: rgba(0,0,0,0.85); }

.ticket-info .ticket-title { font-size: 14px; font-weight: 500; color: rgba(0,0,0,0.85); margin-bottom: 3px; }
.ticket-no { font-size: 11px; color: #4f46e5; font-family: monospace; }
.ticket-meta { font-size: 11px; color: rgba(0,0,0,0.45); margin-top: 2px; }

.priority-badge { font-size: 12px; font-weight: 600; padding: 2px 8px; border-radius: 4px; }
.priority-urgent { color: #fff; background: #ef4444; }
.priority-high { color: #fff; background: #f97316; }
.priority-normal { color: #1d4ed8; background: #dbeafe; }
.priority-low { color: rgba(0,0,0,0.45); background: #f3f4f6; }

.assignee-cell { display: flex; align-items: center; gap: 6px; font-size: 13px; }

/* 详情弹窗 */
.ticket-content-box {
  background: #fafafa; border-radius: 8px; padding: 14px;
  margin-bottom: 20px; border: 1px solid #f0f0f0;
}
.ticket-content-title { font-size: 13px; font-weight: 600; color: rgba(0,0,0,0.65); margin-bottom: 8px; }
.ticket-content-body { font-size: 14px; color: rgba(0,0,0,0.85); white-space: pre-wrap; word-break: break-word; line-height: 1.8; }

.reply-section { margin-top: 4px; }
.reply-title { font-size: 13px; font-weight: 600; color: rgba(0,0,0,0.65); margin-bottom: 12px; }
.reply-empty { text-align: center; color: rgba(0,0,0,0.45); padding: 20px; font-size: 13px; }
.reply-list { display: flex; flex-direction: column; gap: 12px; margin-bottom: 16px; max-height: 300px; overflow-y: auto; }
.reply-item { display: flex; gap: 10px; }
.reply-staff { flex-direction: row-reverse; }
.reply-bubble { flex: 1; }
.reply-meta { display: flex; align-items: center; gap: 6px; margin-bottom: 4px; flex-wrap: wrap; }
.reply-staff .reply-meta { flex-direction: row-reverse; }
.reply-name { font-size: 13px; font-weight: 500; color: rgba(0,0,0,0.65); }
.reply-time { font-size: 11px; color: rgba(0,0,0,0.35); }
.reply-content {
  font-size: 13px; line-height: 1.6; padding: 10px 14px;
  background: #f5f5f5; border-radius: 8px; word-break: break-word;
  display: inline-block; max-width: 100%;
}
.reply-staff .reply-content { background: #e0f2fe; }

.reply-input-area { border-top: 1px solid #f0f0f0; padding-top: 14px; margin-top: 4px; }
.reply-actions { display: flex; justify-content: flex-end; margin-top: 10px; }

.mb-4 { margin-bottom: 16px; }
.mb-6 { margin-bottom: 24px; }
.text-sm { font-size: 12px; }
.text-gray { color: rgba(0,0,0,0.45); }
</style>
