<script setup lang="ts">
import { onMounted, reactive, ref, watch } from 'vue'
import { Message } from '@arco-design/web-vue'
import { http } from '../../api/http'
import { formatDateTimeZh, formatDateZh } from '../../utils/datetime'
import { bookingTypeLabel } from '../../utils/bookingType'
import { reservationStatusLabel } from '../../utils/reservationStatus'
import { listTableRowIndex } from '../../utils/listTableRowIndex'
import * as XLSX from 'xlsx'

const REGISTRATIONS_LIST_SCROLL_X = 2100

type ActivityDayRef = {
  id: number
  activity_id: number
  activity_date: string
  session_name?: string
  session_start_at?: string
  session_end_at?: string
}

type Registration = {
  id: number
  visitor_name: string
  visitor_phone?: string
  booking_type?: string | null
  ticket_count?: number
  status: 'pending' | 'verified' | 'cancelled' | 'expired'
  qr_token: string
  created_at: string
  verified_at?: string | null
  venue?: { id: number; name: string }
  activity?: { id: number; title: string }
  activity_day?: ActivityDayRef | null
  is_blacklisted?: boolean
}

function formatActivitySessionTime(ad: ActivityDayRef | null | undefined): string {
  if (!ad) return '-'
  const name = (ad.session_name || '').trim()
  if (ad.session_start_at && ad.session_end_at) {
    const s = new Date(String(ad.session_start_at).replace(' ', 'T'))
    const e = new Date(String(ad.session_end_at).replace(' ', 'T'))
    if (Number.isNaN(s.getTime()) || Number.isNaN(e.getTime())) {
      return [name, ad.activity_date ? formatDateZh(ad.activity_date) : ''].filter(Boolean).join(' ')
    }
    const y = s.getFullYear()
    const m = String(s.getMonth() + 1).padStart(2, '0')
    const d = String(s.getDate()).padStart(2, '0')
    const pad2 = (n: number) => String(n).padStart(2, '0')
    const hm = (t: Date) => `${pad2(t.getHours())}:${pad2(t.getMinutes())}`
    if (s.toDateString() === e.toDateString()) {
      const timePart = `${y}年${m}月${d}日 ${hm(s)}-${hm(e)}`
      return name ? `${name} ${timePart}` : timePart
    }
    return [name, `${ad.session_start_at} ~ ${ad.session_end_at}`].filter(Boolean).join(' ')
  }
  return [name, ad.activity_date ? formatDateZh(ad.activity_date) : ''].filter(Boolean).join(' ') || '-'
}

const loading = ref(false)
const status = ref<'all' | 'pending' | 'verified' | 'cancelled' | 'expired'>('all')
const keyword = ref('')
const dateRange = ref<string[]>([])
const exportScope = ref<'current' | 'all'>('current')
const exportFields = ref<string[]>([
  'ID',
  '活动',
  '场馆',
  '报名人',
  '手机号',
  '预约类型',
  '预约票数',
  '场次名称',
  '活动时间',
  '状态',
  '下单时间',
  '核销时间',
  '二维码Token',
])
const EXPORT_FIELDS_KEY = 'szkp_export_fields_registrations_v2'
const pagination = reactive({ current: 1, pageSize: 10, total: 0 })
const rows = ref<Registration[]>([])
const selectedKeys = ref<(number | string)[]>([])
const blacklistVisible = ref(false)
const blacklistReason = ref('')
const blacklistMode = ref<'single' | 'batch'>('single')
const currentRow = ref<Registration | null>(null)

async function loadRows() {
  loading.value = true
  try {
    const params = {
      status: status.value,
      keyword: keyword.value || undefined,
      start_date: dateRange.value?.[0] || undefined,
      end_date: dateRange.value?.[1] || undefined,
      page: pagination.current,
      page_size: pagination.pageSize,
    }
    const { data } = await http.get('/activity-registrations', { params })
    rows.value = data.data
    pagination.total = data.total
  } catch (error: any) {
    Message.error(error?.response?.data?.message ?? '加载报名失败')
  } finally {
    loading.value = false
  }
}

function onSearch() {
  pagination.current = 1
  loadRows()
}

async function exportCsv() {
  try {
    if (exportFields.value.length === 0) {
      Message.warning('请至少选择一个导出字段')
      return
    }
    let list: Registration[] = rows.value
    if (exportScope.value === 'all') {
      const res = await http.get('/activity-registrations', {
        params: {
          status: status.value,
          keyword: keyword.value || undefined,
          start_date: dateRange.value?.[0] || undefined,
          end_date: dateRange.value?.[1] || undefined,
          page: 1,
          page_size: 5000,
        },
      })
      list = res.data.data || []
    }
    const fullRows = list.map((r) => ({
      ID: r.id,
      活动: r.activity?.title || '',
      场馆: r.venue?.name || '',
      报名人: r.visitor_name,
      手机号: r.visitor_phone || '',
      预约类型: bookingTypeLabel(r.booking_type, r.ticket_count),
      预约票数: r.ticket_count ?? 1,
      场次名称: (r.activity_day?.session_name || '').trim() || '-',
      活动时间: formatActivitySessionTime(r.activity_day),
      状态: reservationStatusLabel(r.status),
      下单时间: formatDateTimeZh(r.created_at),
      核销时间: formatDateTimeZh(r.verified_at),
      二维码Token: r.qr_token,
    }))
    const exportRows = fullRows.map((row) => {
      const obj: Record<string, any> = {}
      exportFields.value.forEach((k) => {
        obj[k] = row[k as keyof typeof row]
      })
      return obj
    })
    const ws = XLSX.utils.json_to_sheet(exportRows)
    const wb = XLSX.utils.book_new()
    XLSX.utils.book_append_sheet(wb, ws, '报名管理')
    const now = new Date()
    const dateText = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}-${String(now.getDate()).padStart(2, '0')}`
    XLSX.writeFile(wb, `报名管理-${dateText}.xlsx`)
  } catch (error: any) {
    Message.error(error?.response?.data?.message ?? '导出失败')
  }
}

function openQuickBlacklist(row: Registration) {
  blacklistMode.value = 'single'
  currentRow.value = row
  blacklistReason.value = ''
  blacklistVisible.value = true
}

function openBatchQuickBlacklist() {
  if (!selectedKeys.value.length) {
    Message.warning('请先选择要列入灰名单的报名记录')
    return
  }
  blacklistMode.value = 'batch'
  currentRow.value = null
  blacklistReason.value = ''
  blacklistVisible.value = true
}

async function submitQuickBlacklist() {
  if (!blacklistReason.value.trim()) {
    Message.warning('请填写灰名单原因')
    return false
  }
  try {
    if (blacklistMode.value === 'single' && currentRow.value) {
      await http.post(`/activity-registrations/${currentRow.value.id}/quick-blacklist`, {
        reason: blacklistReason.value.trim(),
      })
    } else {
      await http.post('/activity-registrations/quick-blacklist/batch', {
        reservation_ids: selectedKeys.value.map((id) => Number(id)),
        reason: blacklistReason.value.trim(),
      })
      selectedKeys.value = []
    }
    localStorage.setItem('szkp_blacklist_refresh_hint', '1')
    Message.success('已加入灰名单')
    blacklistVisible.value = false
    await loadRows()
    return true
  } catch (error: any) {
    Message.error(error?.response?.data?.message ?? '操作失败')
    return false
  }
}

onMounted(() => {
  const cached = localStorage.getItem(EXPORT_FIELDS_KEY)
  if (cached) {
    try {
      const arr = JSON.parse(cached)
      if (Array.isArray(arr) && arr.length > 0) {
        exportFields.value = arr.map((k: string) => (k === '入馆日期' ? '预约入馆日期' : k))
      }
    } catch {
      // ignore
    }
  }
  loadRows()
})

watch(
  exportFields,
  (val) => {
    localStorage.setItem(EXPORT_FIELDS_KEY, JSON.stringify(val))
  },
  { deep: true },
)

function onPageChange(p: number) {
  pagination.current = p
  loadRows()
}

function onSelectionChange(keys: (number | string)[]) {
  selectedKeys.value = keys
}
</script>

<template>
  <a-card title="活动管理 / 报名管理">
    <div class="reg-toolbar">
      <a-space wrap :size="12">
        <a-radio-group v-model="status" type="button" size="small" @change="loadRows">
          <a-radio value="all">全部</a-radio>
          <a-radio value="pending">待核销</a-radio>
          <a-radio value="verified">已核销</a-radio>
          <a-radio value="cancelled">已取消</a-radio>
          <a-radio value="expired">已过期</a-radio>
        </a-radio-group>
        <a-input v-model="keyword" placeholder="姓名/手机/token" allow-clear style="width: 220px" />
        <a-range-picker v-model="dateRange" style="width: 260px" />
        <a-button type="primary" @click="onSearch">查询</a-button>
        <a-button @click="loadRows">刷新</a-button>
        <a-button status="warning" @click="openBatchQuickBlacklist">批量列入灰名单</a-button>
      </a-space>
      <div class="reg-export-bar">
        <a-select v-model="exportScope" class="reg-export-scope">
          <a-option value="current">导出当前页</a-option>
          <a-option value="all">导出全部</a-option>
        </a-select>
        <a-select
          v-model="exportFields"
          multiple
          allow-clear
          :max-tag-count="2"
          placeholder="选择导出字段"
          class="reg-export-fields"
        >
          <a-option value="ID">ID</a-option>
          <a-option value="活动">活动</a-option>
          <a-option value="场馆">场馆</a-option>
          <a-option value="报名人">报名人</a-option>
          <a-option value="手机号">手机号</a-option>
          <a-option value="预约类型">预约类型</a-option>
          <a-option value="预约票数">预约票数</a-option>
          <a-option value="场次名称">场次名称</a-option>
          <a-option value="活动时间">活动时间</a-option>
          <a-option value="状态">状态</a-option>
          <a-option value="下单时间">下单时间</a-option>
          <a-option value="核销时间">核销时间</a-option>
          <a-option value="二维码Token">二维码Token</a-option>
        </a-select>
        <a-button class="reg-export-btn" @click="exportCsv">导出Excel</a-button>
      </div>
    </div>
    <a-table
      class="list-data-table registrations-table"
      :scroll="{ x: REGISTRATIONS_LIST_SCROLL_X }"
      :data="rows"
      :loading="loading"
      row-key="id"
      :row-selection="{ type: 'checkbox', selectedRowKeys: selectedKeys, showCheckedAll: true }"
      :pagination="{
        current: pagination.current,
        pageSize: pagination.pageSize,
        total: pagination.total,
        showTotal: true,
      }"
      @selection-change="onSelectionChange"
      @page-change="onPageChange"
    >
      <template #columns>
        <a-table-column title="" :width="50" :ellipsis="true" :tooltip="true">
          <template #cell="{ rowIndex }">{{
            listTableRowIndex(rowIndex, pagination.current, pagination.pageSize)
          }}</template>
        </a-table-column>
        <a-table-column title="活动" :width="280" :min-width="220">
          <template #cell="{ record }">{{ record.activity?.title || '-' }}</template>
        </a-table-column>
        <a-table-column title="场馆" :width="220" :min-width="180">
          <template #cell="{ record }">{{ record.venue?.name || '-' }}</template>
        </a-table-column>
        <a-table-column title="报名人" data-index="visitor_name" :width="140" :min-width="120" />
        <a-table-column title="手机号" data-index="visitor_phone" :width="150" :min-width="130" />
        <a-table-column title="预约类型" :width="100">
          <template #cell="{ record }">{{ bookingTypeLabel(record.booking_type, record.ticket_count) }}</template>
        </a-table-column>
        <a-table-column title="预约票数" :width="110">
          <template #cell="{ record }">{{ record.ticket_count ?? 1 }}</template>
        </a-table-column>
        <a-table-column title="场次名称" :width="160" :min-width="120" :ellipsis="true" :tooltip="true">
          <template #cell="{ record }">{{ (record.activity_day?.session_name || '').trim() || '-' }}</template>
        </a-table-column>
        <a-table-column title="活动时间" :width="220" :min-width="180" :ellipsis="true" :tooltip="true">
          <template #cell="{ record }">{{ formatActivitySessionTime(record.activity_day) }}</template>
        </a-table-column>
        <a-table-column title="状态" :width="120">
          <template #cell="{ record }">
            <a-tag
              :color="
                record.status === 'verified'
                  ? 'green'
                  : record.status === 'pending'
                    ? 'arcoblue'
                    : record.status === 'expired'
                      ? 'orange'
                      : 'gray'
              "
            >
              {{ reservationStatusLabel(record.status) }}
            </a-tag>
          </template>
        </a-table-column>
        <a-table-column title="下单时间" :width="190" :min-width="175">
          <template #cell="{ record }">{{ formatDateTimeZh(record.created_at) }}</template>
        </a-table-column>
        <a-table-column title="核销时间" :width="190" :min-width="175">
          <template #cell="{ record }">{{ formatDateTimeZh(record.verified_at) }}</template>
        </a-table-column>
        <a-table-column
          title="二维码 token"
          data-index="qr_token"
          :width="220"
          :min-width="180"
          :ellipsis="true"
          :tooltip="true"
          fixed="right"
          align="left"
        />
        <a-table-column title="操作" :width="140" fixed="right" align="center">
          <template #cell="{ record }">
            <a-button v-if="!record.is_blacklisted" type="text" status="warning" @click="openQuickBlacklist(record)">
              一键列入灰名单
            </a-button>
          </template>
        </a-table-column>
      </template>
    </a-table>

    <a-modal v-model:visible="blacklistVisible" title="灰名单原因" :on-before-ok="submitQuickBlacklist">
      <a-form layout="vertical" class="admin-modal-form">
        <a-form-item label="原因" required class="admin-modal-form__full">
          <a-textarea v-model="blacklistReason" placeholder="请输入原因" :max-length="255" show-word-limit />
        </a-form-item>
      </a-form>
    </a-modal>
  </a-card>
</template>

<style scoped>
.reg-toolbar {
  width: 100%;
  max-width: 100%;
  margin-bottom: 12px;
  box-sizing: border-box;
}

/* 导出：中间列可收缩，窄屏时按钮自动落到下一行 */
.reg-export-bar {
  display: grid;
  grid-template-columns: 130px minmax(0, 1fr) auto;
  gap: 12px;
  align-items: start;
  margin-top: 12px;
  width: 100%;
  box-sizing: border-box;
}

.reg-export-scope {
  width: 130px;
}

.reg-export-fields {
  width: 100%;
  min-width: 0;
}

.reg-export-fields :deep(.arco-select-view) {
  max-width: 100%;
}

.reg-export-btn {
  justify-self: start;
}

@media (max-width: 720px) {
  .reg-export-bar {
    grid-template-columns: minmax(0, 1fr) auto;
    grid-template-areas:
      'scope btn'
      'fields fields';
  }

  .reg-export-scope {
    grid-area: scope;
  }

  .reg-export-fields {
    grid-area: fields;
  }

  .reg-export-btn {
    grid-area: btn;
    justify-self: end;
  }
}

.registrations-table :deep(.arco-table-td .arco-table-cell) {
  white-space: normal;
  word-break: break-word;
}

/* token 列启用省略号时单行展示 */
.registrations-table :deep(.arco-table-text-ellipsis) {
  white-space: nowrap;
}
</style>

