<template>
  <div class="hotel-order-page">
    <AiCrudPage
      ref="crudRef"
      :api-config="{
        list: 'get@/hotel/order/page',
      }"
      :search-schema="searchSchema"
      :columns="tableColumns"
      row-key="id"
      :hide-add="true"
      :hide-batch-delete="true"
      :show-export="false"
      :show-import="false"
      :hide-selection="true"
    >
      <!-- 工具栏：看板统计 -->
      <template #toolbar-start>
        <div class="order-dashboard">
          <div class="dashboard-item">
            <span class="dashboard-value warning">{{ dashboard.pendingCount }}</span>
            <span class="dashboard-label">待接单</span>
          </div>
          <div v-if="connected" class="sse-indicator" title="实时通知已连接">
            <span class="sse-dot" />
          </div>
          <div class="dashboard-item">
            <span class="dashboard-value primary">{{ dashboard.preparingCount }}</span>
            <span class="dashboard-label">备餐中</span>
          </div>
          <div class="dashboard-item">
            <span class="dashboard-value primary">{{ dashboard.deliveringCount }}</span>
            <span class="dashboard-label">配送中</span>
          </div>
          <div class="dashboard-divider" />
          <div class="dashboard-item">
            <span class="dashboard-value">{{ dashboard.todayTotal }}</span>
            <span class="dashboard-label">今日订单</span>
          </div>
          <div class="dashboard-item">
            <span class="dashboard-value success">¥{{ dashboard.todayRevenue }}</span>
            <span class="dashboard-label">今日营收</span>
          </div>
        </div>
      </template>
    </AiCrudPage>

    <!-- 订单详情弹窗 -->
    <NModal
      v-model:show="detailVisible"
      title="订单详情"
      preset="card"
      style="width: 680px;"
      :mask-closable="true"
    >
      <NSpin :show="detailLoading">
        <div v-if="detailData" class="order-detail">
          <!-- 基本信息 -->
          <div class="detail-section">
            <div class="detail-header">
              <span class="detail-order-no">{{ detailData.orderNo }}</span>
              <DictTag dict-type="hotel_order_status" :value="String(detailData.status)" size="small" />
            </div>
            <div class="detail-grid">
              <div class="detail-item">
                <span class="detail-label">房间号</span>
                <span class="detail-value">{{ detailData.roomNo }}</span>
              </div>
              <div class="detail-item">
                <span class="detail-label">联系人</span>
                <span class="detail-value">{{ detailData.contactName }}</span>
              </div>
              <div class="detail-item">
                <span class="detail-label">联系电话</span>
                <span class="detail-value">{{ detailData.contactPhone }}</span>
              </div>
              <div class="detail-item">
                <span class="detail-label">支付方式</span>
                <span class="detail-value">
                  <DictTag v-if="detailData.payMethod" dict-type="hotel_pay_method" :value="detailData.payMethod" size="small" />
                </span>
              </div>
              <div class="detail-item">
                <span class="detail-label">配送时间</span>
                <span class="detail-value">
                  <template v-if="detailData.deliveryTimeType === 'CUSTOM'">
                    {{ detailData.customDeliveryTime }}
                  </template>
                  <template v-else>
                    立即送达
                  </template>
                </span>
              </div>
              <div class="detail-item">
                <span class="detail-label">下单时间</span>
                <span class="detail-value">{{ detailData.createTime }}</span>
              </div>
            </div>
            <div v-if="detailData.note" class="detail-note">
              <span class="detail-label">备注：</span>{{ detailData.note }}
            </div>
          </div>

          <!-- 金额信息 -->
          <div class="detail-section">
            <div class="detail-amount-row">
              <span>菜品总额：<strong>¥{{ calcItemsTotal }}</strong></span>
              <span>配送费：<strong>¥{{ detailData.deliveryFee }}</strong></span>
              <span class="detail-total">合计：<strong>¥{{ detailData.totalAmount }}</strong></span>
            </div>
          </div>

          <!-- 时间线 -->
          <div v-if="hasTimeInfo" class="detail-section">
            <div class="detail-label" style="margin-bottom: 6px;">
              时间记录
            </div>
            <div class="detail-grid">
              <div v-if="detailData.acceptTime" class="detail-item">
                <span class="detail-label">接单</span>
                <span class="detail-value">{{ detailData.acceptTime }}</span>
              </div>
              <div v-if="detailData.readyTime" class="detail-item">
                <span class="detail-label">出餐</span>
                <span class="detail-value">{{ detailData.readyTime }}</span>
              </div>
              <div v-if="detailData.deliverTime" class="detail-item">
                <span class="detail-label">配送</span>
                <span class="detail-value">{{ detailData.deliverTime }}</span>
              </div>
              <div v-if="detailData.completeTime" class="detail-item">
                <span class="detail-label">完成</span>
                <span class="detail-value">{{ detailData.completeTime }}</span>
              </div>
              <div v-if="detailData.refundTime" class="detail-item">
                <span class="detail-label">退单</span>
                <span class="detail-value">{{ detailData.refundTime }}</span>
              </div>
            </div>
            <div v-if="detailData.rejectReason" class="detail-note">
              <span class="detail-label">拒单原因：</span>{{ detailData.rejectReason }}
            </div>
            <div v-if="detailData.refundReason" class="detail-note">
              <span class="detail-label">退单原因：</span>{{ detailData.refundReason }}
            </div>
          </div>

          <!-- 菜品明细 -->
          <div class="detail-section">
            <div class="detail-label" style="margin-bottom: 6px;">
              菜品明细
            </div>
            <NDataTable
              :columns="detailItemColumns"
              :data="detailData.items || []"
              :bordered="true"
              size="small"
              :pagination="false"
            />
          </div>
        </div>
      </NSpin>
    </NModal>

    <!-- 原因输入弹窗（拒单/退单审核） -->
    <NModal
      v-model:show="reasonVisible"
      :title="reasonTitle"
      preset="dialog"
      style="width: 420px;"
      :show-icon="false"
      :mask-closable="false"
      positive-text="确认"
      negative-text="取消"
      @positive-click="handleReasonConfirm"
    >
      <NInput
        v-model:value="reasonText"
        type="textarea"
        placeholder="请输入原因（选填）"
        :rows="3"
      />
    </NModal>
  </div>
</template>

<script setup>
import { NDataTable, NInput, NModal, NSpin, useDialog, useMessage } from 'naive-ui'
import { computed, h, onMounted, onUnmounted, ref } from 'vue'
import {
  acceptOrder,
  approveRefund,
  completeOrder,
  deliverOrder,
  getOrderDashboard,
  getOrderDetail,
  getOrderPage,
  hotelRefund,
  prepareOrder,
  readyOrder,
  rejectOrder,
  rejectRefund,
} from '@/api/hotel'
import { AiCrudPage } from '@/components/ai-form'
import DictTag from '@/components/DictTag.vue'
import { useDict } from '@/composables/useDict'
import { useOrderNotification } from '@/composables/useOrderNotification'

defineOptions({ name: 'HotelOrder' })

const message = useMessage()
const dialog = useDialog()
const { dict } = useDict('hotel_order_status', 'hotel_pay_method')

const crudRef = ref(null)

// ==================== SSE 实时通知 ====================
const { connected, connect, disconnect, playSound } = useOrderNotification({
  onNewOrder: () => {
    crudRef.value?.refresh()
    loadDashboard()
  },
  onRefundRequest: () => {
    crudRef.value?.refresh()
    loadDashboard()
  },
})

/** 监听页面内通知事件（由 useOrderNotification 派发） */
function handleHotelNotification(e) {
  const { type, message: msg, level } = e.detail
  const nType = level === 'warning' ? 'warning' : 'info'
  $notification[nType]({
    title: type === 'new-order' ? '新订单' : '退单申请',
    content: msg,
    duration: 5000,
  })
}

onMounted(() => {
  loadDashboard()
  connect()
  // 页面加载时，检查是否有待接单订单，如果有则触发语音通知
  checkPendingOrders()
  window.addEventListener('hotel-notification', handleHotelNotification)
})

onUnmounted(() => {
  disconnect()
  window.removeEventListener('hotel-notification', handleHotelNotification)
})

// ==================== 看板统计 ====================
const dashboard = ref({
  pendingCount: 0,
  preparingCount: 0,
  deliveringCount: 0,
  todayTotal: 0,
  todayRevenue: '0.00',
})

async function loadDashboard() {
  try {
    const res = await getOrderDashboard()
    if (res.code === 200 && res.data) {
      dashboard.value = res.data
    }
  }
  catch (err) {
    // ignore
    void err
  }
}

/**
 * 页面加载时检查待接单订单，如果有则触发语音通知。
 * 这样刷新页面就能听到声音提醒了。
 */
async function checkPendingOrders() {
  try {
    // 查询待接单订单（status=1）
    const res = await getOrderPage({
      pageNum: 1,
      pageSize: 1,
      status: 1, // 待接单
    })

    if (res.code === 200 && res.data?.total > 0) {
      console.warn('[SSE] 📢 检测到待接单订单，触发语音通知')
      // 播放声音
      playSound('new-order')
      // 触发一次新订单通知（显示桌面弹窗）
      window.dispatchEvent(new CustomEvent('hotel-notification', {
        detail: {
          type: 'new-order',
          message: `您有 ${res.data.total} 个待接单订单`,
          level: 'info',
        },
      }))
    }
  }
  catch (err) {
    console.error('[SSE] 检查待接单订单失败:', err)
  }
}

// ==================== 搜索配置 ====================
const statusOptions = computed(() => {
  const list = dict.value.hotel_order_status || []
  return list.map(item => ({ label: item.label, value: Number(item.value) }))
})

const payMethodOptions = computed(() => dict.value.hotel_pay_method || [])

const searchSchema = computed(() => [
  {
    field: 'roomNo',
    label: '房间号',
    type: 'input',
    props: { placeholder: '请输入房间号' },
  },
  {
    field: 'status',
    label: '订单状态',
    type: 'select',
    props: { placeholder: '请选择状态', options: statusOptions.value },
  },
  {
    field: 'contactName',
    label: '联系人',
    type: 'input',
    props: { placeholder: '请输入联系人姓名' },
  },
  {
    field: 'payMethod',
    label: '支付方式',
    type: 'select',
    props: { placeholder: '请选择支付方式', options: payMethodOptions.value },
  },
])

// ==================== 状态标签渲染 ====================
function renderStatus(status) {
  return h(DictTag, { dictType: 'hotel_order_status', value: String(status), size: 'small' })
}

// ==================== 表格列配置 ====================
const tableColumns = computed(() => [
  { prop: 'orderNo', label: '订单号', width: 180 },
  { prop: 'roomNo', label: '房间号', width: 90 },
  { prop: 'contactName', label: '联系人', width: 90 },
  { prop: 'itemCount', label: '菜品数', width: 70 },
  {
    prop: 'totalAmount',
    label: '金额(元)',
    width: 100,
    render: row => `¥${row.totalAmount}`,
  },
  {
    prop: 'status',
    label: '状态',
    width: 110,
    render: row => renderStatus(row.status),
  },
  { prop: 'createTime', label: '下单时间', width: 172 },
  {
    label: '操作',
    width: 320,
    fixed: 'right',
    render: (row) => {
      const actions = []
      const s = row.status

      // 查看详情（所有状态）
      actions.push(h('a', {
        class: 'text-info cursor-pointer hover:opacity-80',
        onClick: () => openDetail(row),
      }, '详情'))

      // 接单（仅待接单）
      if (s === 1) {
        actions.push(h('a', {
          class: 'text-success cursor-pointer hover:opacity-80',
          onClick: () => handleAction('accept', row),
        }, '接单'))
        actions.push(h('a', {
          class: 'text-error cursor-pointer hover:opacity-80',
          onClick: () => handleAction('reject', row),
        }, '拒单'))
      }

      // 备餐（仅已接单）
      if (s === 2) {
        actions.push(h('a', {
          class: 'text-primary cursor-pointer hover:opacity-80',
          onClick: () => handleAction('prepare', row),
        }, '备餐'))
      }

      // 出餐（仅备餐中）
      if (s === 3) {
        actions.push(h('a', {
          class: 'text-success cursor-pointer hover:opacity-80',
          onClick: () => handleAction('ready', row),
        }, '出餐'))
      }

      // 配送（仅已出餐）
      if (s === 4) {
        actions.push(h('a', {
          class: 'text-primary cursor-pointer hover:opacity-80',
          onClick: () => handleAction('deliver', row),
        }, '配送'))
      }

      // 完成（仅配送中）
      if (s === 5) {
        actions.push(h('a', {
          class: 'text-success cursor-pointer hover:opacity-80',
          onClick: () => handleAction('complete', row),
        }, '完成'))
      }

      // 退单审核（仅退单待审核）
      if (s === 8) {
        actions.push(h('a', {
          class: 'text-success cursor-pointer hover:opacity-80',
          onClick: () => handleAction('approveRefund', row),
        }, '同意退单'))
        actions.push(h('a', {
          class: 'text-error cursor-pointer hover:opacity-80',
          onClick: () => handleAction('rejectRefund', row),
        }, '驳回'))
      }

      // 前台退单（除已完成、已退单、已拒单外）
      if (s !== 6 && s !== 7 && s !== 9) {
        actions.push(h('a', {
          class: 'text-warning cursor-pointer hover:opacity-80',
          onClick: () => handleAction('hotelRefund', row),
        }, '退单'))
      }

      return h('div', { class: 'flex gap-2' }, actions)
    },
  },
])

// ==================== 订单操作 ====================
const reasonVisible = ref(false)
const reasonTitle = ref('')
const reasonText = ref('')
const reasonCallback = ref(null)

function handleAction(action, row) {
  switch (action) {
    case 'accept':
      dialog.warning({
        title: '确认接单',
        content: `确认接受订单 ${row.orderNo} 吗？`,
        positiveText: '确认接单',
        negativeText: '取消',
        onPositiveClick: async () => {
          await acceptOrder(row.id)
          message.success('接单成功')
          crudRef.value?.refresh()
          loadDashboard()
        },
      })
      break
    case 'reject':
      openReasonModal('拒单', async (reason) => {
        await rejectOrder(row.id, reason)
        message.success('已拒单')
        crudRef.value?.refresh()
        loadDashboard()
      })
      break
    case 'prepare':
      dialog.warning({
        title: '开始备餐',
        content: `确认开始备餐 ${row.orderNo}？`,
        positiveText: '确认',
        negativeText: '取消',
        onPositiveClick: async () => {
          await prepareOrder(row.id)
          message.success('已开始备餐')
          crudRef.value?.refresh()
          loadDashboard()
        },
      })
      break
    case 'ready':
      dialog.warning({
        title: '出餐完成',
        content: `确认订单 ${row.orderNo} 出餐完成？`,
        positiveText: '确认出餐',
        negativeText: '取消',
        onPositiveClick: async () => {
          await readyOrder(row.id)
          message.success('已出餐')
          crudRef.value?.refresh()
          loadDashboard()
        },
      })
      break
    case 'deliver':
      dialog.warning({
        title: '开始配送',
        content: `确认开始配送订单 ${row.orderNo}？`,
        positiveText: '确认配送',
        negativeText: '取消',
        onPositiveClick: async () => {
          await deliverOrder(row.id)
          message.success('已开始配送')
          crudRef.value?.refresh()
          loadDashboard()
        },
      })
      break
    case 'complete':
      dialog.warning({
        title: '完成配送',
        content: `确认订单 ${row.orderNo} 配送完成？`,
        positiveText: '确认完成',
        negativeText: '取消',
        onPositiveClick: async () => {
          await completeOrder(row.id)
          message.success('订单已完成')
          crudRef.value?.refresh()
          loadDashboard()
        },
      })
      break
    case 'hotelRefund':
      openReasonModal('前台退单', async (reason) => {
        await hotelRefund(row.id, reason)
        message.success('退单成功')
        crudRef.value?.refresh()
        loadDashboard()
      })
      break
    case 'approveRefund':
      dialog.warning({
        title: '同意退单',
        content: `确认同意订单 ${row.orderNo} 的退单申请？`,
        positiveText: '同意退单',
        negativeText: '取消',
        onPositiveClick: async () => {
          await approveRefund(row.id)
          message.success('已同意退单')
          crudRef.value?.refresh()
          loadDashboard()
        },
      })
      break
    case 'rejectRefund':
      openReasonModal('驳回退单', async (reason) => {
        await rejectRefund(row.id, reason)
        message.success('已驳回退单申请')
        crudRef.value?.refresh()
        loadDashboard()
      })
      break
  }
}

function openReasonModal(title, callback) {
  reasonTitle.value = title
  reasonText.value = ''
  reasonCallback.value = callback
  reasonVisible.value = true
}

async function handleReasonConfirm() {
  if (reasonCallback.value) {
    await reasonCallback.value(reasonText.value || undefined)
  }
}

// ==================== 订单详情 ====================
const detailVisible = ref(false)
const detailLoading = ref(false)
const detailData = ref(null)

const detailItemColumns = [
  { title: '菜品名称', key: 'dishName', minWidth: 120 },
  { title: '规格', key: 'specDesc', width: 120, render: row => row.specDesc || '' },
  { title: '加料', key: 'additionsDesc', width: 120, render: row => row.additionsDesc || '' },
  { title: '数量', key: 'quantity', width: 60 },
  { title: '单价', key: 'unitPrice', width: 80, render: row => `¥${row.unitPrice}` },
  { title: '小计', key: 'subtotal', width: 80, render: row => `¥${row.subtotal}` },
  { title: '备注', key: 'note', width: 100, render: row => row.note || '' },
]

const calcItemsTotal = computed(() => {
  if (!detailData.value?.items)
    return '0.00'
  const sum = detailData.value.items.reduce((acc, item) => acc + Number(item.subtotal || 0), 0)
  return sum.toFixed(2)
})

const hasTimeInfo = computed(() => {
  if (!detailData.value)
    return false
  const d = detailData.value
  return d.acceptTime || d.readyTime || d.deliverTime || d.completeTime || d.refundTime || d.rejectReason || d.refundReason
})

async function openDetail(row) {
  detailVisible.value = true
  detailLoading.value = true
  detailData.value = null
  try {
    const res = await getOrderDetail(row.id)
    if (res.code === 200) {
      detailData.value = res.data
    }
  }
  catch {
    message.error('加载订单详情失败')
  }
  finally {
    detailLoading.value = false
  }
}
</script>

<style scoped>
.hotel-order-page {
  height: 100%;
}

/* ==================== 看板统计 ==================== */
.order-dashboard {
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 0 4px;
}

.dashboard-item {
  display: flex;
  flex-direction: column;
  align-items: center;
  min-width: 56px;
}

.dashboard-value {
  font-size: 18px;
  font-weight: 700;
  line-height: 1.2;
  color: #333;
}

.dashboard-value.warning {
  color: #f0a020;
}

.dashboard-value.primary {
  color: #2080f0;
}

.dashboard-value.success {
  color: #18a058;
}

.dashboard-label {
  font-size: 12px;
  color: #999;
  margin-top: 2px;
}

.dashboard-divider {
  width: 1px;
  height: 28px;
  background: #e8e8e8;
  margin: 0 4px;
}

/* ==================== SSE连接指示器 ==================== */
.sse-indicator {
  display: flex;
  align-items: center;
  margin-left: 4px;
}

.sse-dot {
  display: inline-block;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: #18a058;
  animation: sse-pulse 2s ease-in-out infinite;
}

@keyframes sse-pulse {
  0%,
  100% {
    opacity: 1;
  }
  50% {
    opacity: 0.4;
  }
}

/* ==================== 订单详情 ==================== */
.order-detail {
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.detail-section {
  padding-bottom: 12px;
  border-bottom: 1px solid #f0f0f0;
}

.detail-section:last-child {
  border-bottom: none;
  padding-bottom: 0;
}

.detail-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 12px;
}

.detail-order-no {
  font-size: 16px;
  font-weight: 700;
  color: #333;
}

.detail-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 8px 16px;
}

.detail-item {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.detail-label {
  font-size: 12px;
  color: #999;
}

.detail-value {
  font-size: 14px;
  color: #333;
}

.detail-note {
  margin-top: 8px;
  font-size: 13px;
  color: #666;
  padding: 6px 10px;
  background: #fafafa;
  border-radius: 4px;
}

.detail-amount-row {
  display: flex;
  gap: 24px;
  font-size: 14px;
  color: #333;
}

.detail-total {
  margin-left: auto;
  font-size: 16px;
  color: #f0a020;
}
</style>
