<script setup lang="ts">
import { computed, onMounted, ref } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { showToast, showDialog } from 'vant'

import { fetchOrderChat } from '@/features/chats/api/chats'
import { createDispute } from '@/features/disputes/api/disputes'
import { uploadFile } from '@/shared/api/files'
import { centToYuan, formatMoney } from '@/shared/utils/money'
import {
  acceptCheckout,
  cancelOrder,
  confirmCheckout,
  confirmReceive,
  counterCheckout,
  fetchHandoffRecords,
  fetchOrder,
  startOrderPayment,
  submitCheckout,
  submitHandoff,
  type HandoffRecord,
  type Order,
  type PaymentOrder,
} from '@/features/orders/api/orders'
import { useSessionStore } from '@/stores/session'
import { handoffStatusLabel, orderStatusLabel } from '@/shared/utils/statusLabels'
import { formatDateTime } from '@/shared/utils/time'
import { formatListingNo } from '@/shared/utils/listingDisplay'

const route = useRoute()
const router = useRouter()
const session = useSessionStore()
const loading = ref(false)
const cancelling = ref(false)
const paying = ref(false)
const handoffing = ref(false)
const confirming = ref(false)
const returning = ref(false)
const completing = ref(false)
const countering = ref(false)
const acceptingCheckout = ref(false)
const rejectingCheckout = ref(false)
const disputing = ref(false)
const uploadingEvidence = ref(false)
const openingChat = ref(false)
const order = ref<Order | null>(null)
const handoffRecords = ref<HandoffRecord[]>([])
const listingCode = computed(() =>
  order.value ? formatListingNo(order.value.listing_no, order.value.listing_id) : '-'
)
const handoffContent = ref('')
const checkoutForm = ref({
  content: '',
  consumable_amount: 0,
  coin_consumed_m: 0,
  other_amount: 0,
  evidenceText: '',
})
const resourceUsage = ref<Record<string, number>>({})
const counterForm = ref({
  consumable_amount: 0,
  coin_consumed_m: 0,
  other_amount: 0,
  deposit_deduct_amount: 0,
  reason: '',
  evidenceText: '',
})
const rejectReason = ref('')
const disputeType = ref('cannot_login')
const disputeDescription = ref('')
const disputeEvidenceText = ref('')

// Show state controls
const activeNames = ref<string[]>([])
const showDisputePopup = ref(false)
const showCounterPopup = ref(false)
const showRejectPopup = ref(false)

const isOwner = computed(() => order.value?.owner_id === session.userId)
const isRenter = computed(() => order.value?.renter_id === session.userId)
const orderAmountLabel = computed(() => (isOwner.value ? '预计租金' : '支付租金'))
const orderRentDisplayAmount = computed(() => (order.value ? orderRentAmount(order.value) : 0))
const ownerIncomeDisplayAmount = computed(() =>
  order.value ? ownerActualIncome(order.value) : null
)
const ownerIncomeLabel = computed(() =>
  order.value?.status === 'completed' ? '实际到手' : '结账预计到手'
)
const canOpenDispute = computed(() => {
  if (!order.value || (!isOwner.value && !isRenter.value)) return false
  return ![
    'completed',
    'cancelled',
    'closed',
    'disputing',
    'checkout_disputing',
    'abnormal',
  ].includes(order.value.status)
})
const isCheckoutDisputeStage = computed(() => {
  return (
    !!order.value &&
    ['pending_checkout_confirm', 'pending_checkout_accept'].includes(order.value.status)
  )
})
const checkoutResources = computed(() => {
  const resources = readSnapshotResources()
  return resources.filter(item => item.quantity > 0)
})
const resourceChargeAmount = computed(() => {
  return roundMoney(
    checkoutResources.value.reduce((sum, item) => {
      if (!isChargedResource(item)) return sum
      const used = readResourceUsage(item.key)
      return sum + used * item.unitPrice
    }, 0)
  )
})
const snapshotHafCoinM = computed(() => {
  const snapshot = readSnapshot()
  return roundQuantity(readNumber(snapshot?.haf_coin_amount) / 1000000)
})
const remainingHafCoinM = computed(() => {
  return roundQuantity(
    Math.max(snapshotHafCoinM.value - Number(checkoutForm.value.coin_consumed_m || 0), 0)
  )
})

onMounted(loadOrder)

async function loadOrder() {
  loading.value = true
  try {
    order.value = await fetchOrder(String(route.params.id))
    handoffRecords.value = await fetchHandoffRecords(String(route.params.id))
    hydrateResourceUsage()
    hydrateCounterForm()
  } catch {
    showToast({ message: '加载订单失败', icon: 'cross' })
  } finally {
    loading.value = false
  }
}

async function handleCancel() {
  if (!order.value) return
  showDialog({
    title: '取消订单',
    message: '确定取消订单并释放账号吗？',
    showCancelButton: true,
  }).then(async () => {
    cancelling.value = true
    try {
      await cancelOrder(order.value!.id)
      showToast({ message: '订单已取消，账号已释放', icon: 'passed' })
      await router.push('/m/orders')
    } catch (error) {
      showToast({ message: readError(error, '取消失败'), icon: 'cross' })
    } finally {
      cancelling.value = false
    }
  })
}

async function handlePay() {
  if (!order.value) return
  paying.value = true
  try {
    const payment = await startOrderPayment(order.value.id)
    if (payment.paid) {
      showToast({ message: '支付成功，等待号主交接', icon: 'passed' })
      await loadOrder()
    } else {
      openPaymentCashier(payment)
    }
  } catch (error) {
    showToast({ message: readError(error, '支付失败'), icon: 'cross' })
  } finally {
    paying.value = false
  }
}

function openPaymentCashier(payment: PaymentOrder) {
  const payURL = payment.jspay_url || payment.td_code || payment.jspay_info || ''
  if (payURL && /^https?:\/\//i.test(payURL)) {
    window.location.href = payURL
    return
  }
  showDialog({
    title: '订单支付',
    message: payURL || '支付单已创建，请稍后刷新订单状态。',
    confirmButtonText: '知道了',
  })
}

async function handleSubmitHandoff() {
  if (!order.value) return
  if (!handoffContent.value.trim()) {
    showToast({ message: '请填写交接说明', icon: 'warning-o' })
    return
  }
  handoffing.value = true
  try {
    await submitHandoff(order.value.id, handoffContent.value)
    handoffContent.value = ''
    showToast({ message: '交接说明已提交', icon: 'passed' })
    await loadOrder()
  } catch (error) {
    showToast({ message: readError(error, '提交交接失败'), icon: 'cross' })
  } finally {
    handoffing.value = false
  }
}

async function handleConfirmReceive() {
  if (!order.value) return
  confirming.value = true
  try {
    await confirmReceive(order.value.id)
    showToast({ message: '已确认收号，订单进入使用中', icon: 'passed' })
    await loadOrder()
  } catch (error) {
    showToast({ message: readError(error, '确认收号失败'), icon: 'cross' })
  } finally {
    confirming.value = false
  }
}

async function handleSubmitCheckout() {
  if (!order.value) return
  returning.value = true
  try {
    const consumableAmount = resourceChargeAmount.value
    checkoutForm.value.consumable_amount = consumableAmount
    await submitCheckout(order.value.id, {
      content: checkoutContentWithSummary(),
      consumable_amount: consumableAmount,
      coin_consumed_m: checkoutForm.value.coin_consumed_m,
      other_amount: checkoutForm.value.other_amount,
      evidence_urls: linesToList(checkoutForm.value.evidenceText),
    })
    checkoutForm.value = {
      content: '',
      consumable_amount: 0,
      coin_consumed_m: 0,
      other_amount: 0,
      evidenceText: '',
    }
    resourceUsage.value = {}
    showToast({ message: '结账已发起，等待号主确认', icon: 'passed' })
    await loadOrder()
  } catch (error) {
    showToast({ message: readError(error, '发起结账失败'), icon: 'cross' })
  } finally {
    returning.value = false
  }
}

async function handleConfirmCheckout() {
  if (!order.value) return
  showDialog({
    title: '确认结账',
    message: '确认账号状态和扣款金额无误吗？确认后订单将完成。',
    showCancelButton: true,
  }).then(async () => {
    completing.value = true
    try {
      await confirmCheckout(order.value!.id)
      showToast({ message: '结账已确认，订单完成', icon: 'passed' })
      await loadOrder()
    } catch (error) {
      showToast({ message: readError(error, '确认结账失败'), icon: 'cross' })
    } finally {
      completing.value = false
    }
  })
}

async function handleCounterCheckout() {
  if (!order.value) return
  countering.value = true
  try {
    const reasonText = counterForm.value.reason.trim()
    await counterCheckout(order.value.id, {
      content: reasonText,
      consumable_amount: counterForm.value.consumable_amount,
      coin_consumed_m: counterForm.value.coin_consumed_m,
      other_amount: counterForm.value.other_amount,
      deposit_deduct_amount: counterForm.value.deposit_deduct_amount,
      reason: reasonText,
      evidence_urls: linesToList(counterForm.value.evidenceText),
    })
    showToast({ message: '结账修正已提交，等待租客确认', icon: 'passed' })
    showCounterPopup.value = false
    await loadOrder()
  } catch (error) {
    showToast({ message: readError(error, '修改结账失败'), icon: 'cross' })
  } finally {
    countering.value = false
  }
}

async function handleAcceptCheckout() {
  if (!order.value) return
  showDialog({
    title: '同意修正',
    message: '确定同意号主的结账修正提案吗？同意后订单将完成结算。',
    showCancelButton: true,
  }).then(async () => {
    acceptingCheckout.value = true
    try {
      await acceptCheckout(order.value!.id)
      showToast({ message: '已确认修正结账，订单完成', icon: 'passed' })
      await loadOrder()
    } catch (error) {
      showToast({ message: readError(error, '确认修正失败'), icon: 'cross' })
    } finally {
      acceptingCheckout.value = false
    }
  })
}

async function handleRejectCheckout() {
  if (!order.value) return
  if (!rejectReason.value.trim()) {
    showToast({ message: '请填写不同意原因', icon: 'warning-o' })
    return
  }
  rejectingCheckout.value = true
  try {
    await createDispute(order.value.id, {
      type: 'checkout_dispute',
      description: rejectReason.value,
      evidence_urls: [],
    })
    rejectReason.value = ''
    showToast({ message: '已拒绝修正并提交争议', icon: 'passed' })
    showRejectPopup.value = false
    await loadOrder()
  } catch (error) {
    showToast({ message: readError(error, '提交拒绝失败'), icon: 'cross' })
  } finally {
    rejectingCheckout.value = false
  }
}

async function handleCreateDispute() {
  if (!order.value) return
  if (!disputeDescription.value.trim()) {
    showToast({ message: '请填写争议经过说明', icon: 'warning-o' })
    return
  }
  disputing.value = true
  try {
    const evidence_urls = linesToList(disputeEvidenceText.value)
    await createDispute(order.value.id, {
      type: isCheckoutDisputeStage.value ? 'checkout_dispute' : disputeType.value,
      description: disputeDescription.value,
      evidence_urls,
    })
    disputeDescription.value = ''
    disputeEvidenceText.value = ''
    showToast({ message: '申诉已提交，订单进入仲裁', icon: 'passed' })
    showDisputePopup.value = false
    await loadOrder()
  } catch (error) {
    showToast({ message: readError(error, '提交申诉失败'), icon: 'cross' })
  } finally {
    disputing.value = false
  }
}

async function handleEvidenceUpload(event: Event) {
  const input = event.target as HTMLInputElement
  const file = input.files?.[0]
  input.value = ''
  if (!file) return
  uploadingEvidence.value = true
  try {
    const uploaded = await uploadFile(file, 'dispute')
    disputeEvidenceText.value = [disputeEvidenceText.value, uploaded.url].filter(Boolean).join('\n')
    showToast({ message: '证据文件已上传', icon: 'passed' })
  } catch (error) {
    showToast({ message: readError(error, '上传失败'), icon: 'cross' })
  } finally {
    uploadingEvidence.value = false
  }
}

async function handleCounterEvidenceUpload(event: Event) {
  const input = event.target as HTMLInputElement
  const file = input.files?.[0]
  input.value = ''
  if (!file) return
  uploadingEvidence.value = true
  try {
    const uploaded = await uploadFile(file, 'dispute')
    counterForm.value.evidenceText = [counterForm.value.evidenceText, uploaded.url]
      .filter(Boolean)
      .join('\n')
    showToast({ message: '证据文件已上传', icon: 'passed' })
  } catch (error) {
    showToast({ message: readError(error, '上传失败'), icon: 'cross' })
  } finally {
    uploadingEvidence.value = false
  }
}

function readError(error: unknown, fallback: string) {
  if (typeof error === 'object' && error && 'response' in error) {
    const response = (error as { response?: { data?: { message?: string } } }).response
    return response?.data?.message || fallback
  }
  return fallback
}

function orderRentedAt() {
  return order.value?.rented_at
}

function orderEstimatedEndAt() {
  if (!order.value) return undefined
  const rentedAt = orderRentedAt()
  const durationHours = Number(order.value.estimated_duration_hours || 0)
  if (!rentedAt || durationHours <= 0) return undefined
  return new Date(new Date(rentedAt).getTime() + durationHours * 60 * 60 * 1000).toISOString()
}

interface CheckoutResource {
  key: string
  label: string
  price: string
  mode: string
  quantity: number
  unitPrice: number
}

function readSnapshot(): any {
  const snapshot = order.value?.account_snapshot
  if (isRecord(snapshot)) return snapshot
  return null
}

function readAssetSummary(): any {
  const summary = readSnapshot()?.asset_summary
  if (isRecord(summary)) return summary
  return null
}

function readSnapshotResources(): CheckoutResource[] {
  const resources = readAssetSummary()?.resources
  if (!Array.isArray(resources)) return []
  return resources
    .filter(isRecord)
    .map(item => {
      const key = String(item.key || item.label || '')
      const label = String(item.label || key || '额外消耗品')
      const price = String(item.price || '')
      return {
        key,
        label,
        price,
        mode: String(item.mode || '收费'),
        quantity: readNumber(item.quantity),
        unitPrice: readUnitPrice(price),
      }
    })
    .filter(item => item.key && item.quantity > 0)
}

function hydrateResourceUsage() {
  const next: Record<string, number> = {}
  for (const item of checkoutResources.value) {
    next[item.key] = Math.min(
      Math.max(Number(resourceUsage.value[item.key] || 0), 0),
      item.quantity
    )
  }
  resourceUsage.value = next
}

function readResourceUsage(key: string) {
  return Math.max(Number(resourceUsage.value[key] || 0), 0)
}

function isChargedResource(item: CheckoutResource) {
  return item.mode !== '赠送'
}

function resourceLineAmount(item: CheckoutResource) {
  return roundMoney(readResourceUsage(item.key) * item.unitPrice)
}

function checkoutContentWithSummary() {
  const lines = [checkoutForm.value.content.trim()].filter(Boolean)
  const usedResources = checkoutResources.value.filter(item => readResourceUsage(item.key) > 0)
  if (usedResources.length) {
    lines.push(
      `额外消耗品：${usedResources
        .map(
          item =>
            `${item.label} ${readResourceUsage(item.key)}/${item.quantity}${
              isChargedResource(item) ? `，金额¥${money(resourceLineAmount(item))}` : '，赠送不扣款'
            }`
        )
        .join('；')}`
    )
  }
  if (Number(checkoutForm.value.coin_consumed_m || 0) > 0) {
    lines.push(
      `哈夫币消耗：${quantity(Number(checkoutForm.value.coin_consumed_m))}M，预计剩余${quantity(
        remainingHafCoinM.value
      )}M`
    )
  }
  if (lines.length === 0) {
    lines.push('租客发起结账。')
  }
  return lines.join('\n')
}

function readUnitPrice(priceText: string) {
  const normalized = priceText.replace(/，/g, ',').trim()
  const fractionMatch = normalized.match(/(\d+(?:\.\d+)?)\s*元\s*\/\s*(\d+(?:\.\d+)?)/)
  if (fractionMatch) {
    const amount = Number(fractionMatch[1])
    const count = Number(fractionMatch[2])
    return count > 0 ? roundMoney(amount / count) : 0
  }
  const singleMatch = normalized.match(/(\d+(?:\.\d+)?)\s*元/)
  if (singleMatch) return Number(singleMatch[1])
  const fallback = normalized.match(/(\d+(?:\.\d+)?)/)
  return fallback ? Number(fallback[1]) : 0
}

function roundMoney(value: number) {
  return Math.round(Number(value || 0) * 10) / 10
}

function roundQuantity(value: number) {
  return Math.round(value * 100) / 100
}

function money(value: unknown) {
  return formatMoney(readNumber(value))
}

function formatHandoffRecordType(type: string) {
  const typeMap: Record<string, string> = {
    owner_handoff: '卖家交接',
    renter_checkout: '买家结账',
    owner_counter_checkout: '卖家反驳结账',
    renter_confirm_checkout: '买家确认结账',
    owner_accept_checkout: '卖家接受结账',
    admin_arbitration: '客服仲裁',
  }
  return typeMap[type] || type
}

function amountYuan(cent: unknown) {
  if (cent !== undefined && cent !== null) return centToYuan(readNumber(cent))
  return 0
}

function orderRentAmount(item: Order) {
  if (item.owner_id === session.userId) return amountYuan(item.owner_rent_amount_cent)
  if (item.renter_id === session.userId) return amountYuan(item.rent_amount_cent)
  return amountYuan(item.display_amount_cent)
}

function ownerActualIncome(item: Order) {
  if (item.owner_id !== session.userId) return null
  const value = item.checkout?.owner_income_amount_cent
  if (typeof value === 'number') return centToYuan(value)
  return null
}

function quantity(value: unknown) {
  const rounded = roundQuantity(readNumber(value))
  return Number.isInteger(rounded) ? `${rounded}` : rounded.toFixed(2)
}

function readNumber(value: unknown) {
  const number = Number(value || 0)
  return Number.isFinite(number) ? number : 0
}

function isRecord(value: unknown): value is Record<string, unknown> {
  return typeof value === 'object' && value !== null
}

function hydrateCounterForm() {
  if (!order.value?.checkout) return
  const checkout = order.value.checkout
  counterForm.value.consumable_amount = amountYuan(checkout.consumable_amount_cent)
  counterForm.value.coin_consumed_m = checkout.coin_consumed_m
  counterForm.value.other_amount = amountYuan(checkout.other_amount_cent)
  counterForm.value.deposit_deduct_amount = amountYuan(checkout.deposit_deduct_amount_cent)
}

function linesToList(value: string) {
  return value
    .split('\n')
    .map(item => item.trim())
    .filter(Boolean)
}

async function openOrderChat() {
  if (!order.value || openingChat.value) return
  openingChat.value = true
  try {
    const chat = await fetchOrderChat(order.value.id)
    router.push(`/m/chats/${chat.id}`)
  } catch {
    showToast({ message: '订单群聊暂不可用', icon: 'warning-o' })
  } finally {
    openingChat.value = false
  }
}

/* Status Theme Color Mapping */
function getStatusTagType(status: string) {
  if (['completed', 'received'].includes(status)) return 'success'
  if (['pending_payment', 'pending_confirm'].includes(status)) return 'warning'
  if (['renting'].includes(status)) return 'primary'
  if (['cancelled', 'closed'].includes(status)) return 'danger'
  return 'danger'
}

async function copyListingCode() {
  if (!order.value) return
  try {
    await navigator.clipboard.writeText(listingCode.value)
    showToast({ message: '商品编号已复制', icon: 'passed' })
  } catch {
    showToast({ message: '复制失败', icon: 'cross' })
  }
}
</script>

<template>
  <main class="mobile-order-detail-view">
    <header class="page-header">
      <button class="back-btn" @click="router.back()">
        <van-icon name="arrow-left" :size="20" />
      </button>
      <h1>订单详情</h1>
      <button
        v-if="order"
        class="chat-btn"
        type="button"
        :disabled="openingChat"
        @click="openOrderChat"
      >
        <van-icon name="chat-o" :size="19" />
      </button>
      <span v-else class="header-spacer"></span>
    </header>

    <van-loading v-if="loading" class="center-loading" size="24px" vertical>
      加载中...
    </van-loading>

    <template v-else-if="order">
      <!-- 状态及核心信息卡片 -->
      <section class="card-section info-card">
        <div class="card-header-row">
          <span class="order-no">{{ order.order_no }}</span>
          <van-tag :type="getStatusTagType(order.status)" size="medium">
            {{ orderStatusLabel(order.status) }}
          </van-tag>
        </div>
        <button class="listing-code-chip" type="button" @click="copyListingCode">
          商品编号 {{ listingCode }}
        </button>
        <h2 class="order-title">{{ order.title }}</h2>
        <div class="order-meta-grid">
          <div class="meta-item">
            <span class="meta-label">{{ orderAmountLabel }}</span>
            <strong class="meta-value accent">¥{{ money(orderRentDisplayAmount) }}</strong>
          </div>
          <div v-if="isOwner && ownerIncomeDisplayAmount !== null" class="meta-item">
            <span class="meta-label">{{ ownerIncomeLabel }}</span>
            <strong class="meta-value income">¥{{ money(ownerIncomeDisplayAmount) }}</strong>
          </div>
          <div class="meta-item">
            <span class="meta-label">押金</span>
            <strong class="meta-value">¥{{ money(amountYuan(order.deposit_amount_cent)) }}</strong>
            <span v-if="amountYuan(order.deposit_waived_amount_cent) > 0" class="meta-note"
              >已免押 ¥{{ money(amountYuan(order.deposit_waived_amount_cent)) }}</span
            >
          </div>
          <div class="meta-item">
            <span class="meta-label">交接状态</span>
            <strong class="meta-value">{{ handoffStatusLabel(order.handoff_status) }}</strong>
          </div>
        </div>
      </section>

      <!-- 时间节点卡片 -->
      <section class="card-section">
        <van-cell-group inset :border="false">
          <van-cell title="开始时间" :value="formatDateTime(orderRentedAt(), '未开始')" />
          <van-cell title="预计截止" :value="formatDateTime(orderEstimatedEndAt(), '未设置')" />
        </van-cell-group>
      </section>

      <!-- Renter Action: Pay / Cancel -->
      <section v-if="order.status === 'pending_payment'" class="card-section action-card">
        <p class="action-hint">订单已创建，请确认并在有效期内完成支付。过期订单将自动关闭。</p>
        <div class="action-buttons">
          <van-button
            v-if="isRenter"
            type="primary"
            block
            round
            :loading="paying"
            loading-text="支付中..."
            @click="handlePay"
          >
            支付订单
          </van-button>
          <van-button
            type="danger"
            block
            plain
            round
            :loading="cancelling"
            loading-text="取消中..."
            @click="handleCancel"
          >
            取消订单并释放账号
          </van-button>
        </div>
      </section>

      <!-- Handoff Panel: Owner Handoff Info Submission -->
      <section
        v-if="
          isOwner && order.status === 'pending_handoff' && order.handoff_status === 'pending_owner'
        "
        class="card-section action-card"
      >
        <h3 class="section-title">提交交接说明</h3>
        <p class="action-hint">提交登录所需的账号密码、密保注意事项或扫码交接联系方式。</p>
        <van-field
          v-model="handoffContent"
          rows="3"
          autosize
          label="交接说明"
          type="textarea"
          placeholder="请在这里填写登录方式、注意事项或扫码联系渠道"
          class="action-field"
        />
        <van-button
          type="primary"
          block
          round
          :loading="handoffing"
          loading-text="正在提交..."
          @click="handleSubmitHandoff"
        >
          提交交接说明
        </van-button>
      </section>

      <!-- Handoff Panel: Renter Confirm Handoff Received -->
      <section
        v-if="
          isRenter &&
          order.status === 'pending_handoff' &&
          order.handoff_status === 'pending_renter_confirm'
        "
        class="card-section action-card"
      >
        <h3 class="section-title">确认收到账号</h3>
        <p class="action-hint">
          请按照号主提交的交接说明进行登录测试，确认无误后点击下方按钮确认收号，租期将正式开始计算。
        </p>
        <div class="action-buttons">
          <van-button
            type="primary"
            block
            round
            :loading="confirming"
            loading-text="确认中..."
            @click="handleConfirmReceive"
          >
            确认收到账号
          </van-button>
          <van-button
            type="danger"
            block
            plain
            round
            :loading="cancelling"
            loading-text="取消中..."
            @click="handleCancel"
          >
            未收到/无法登录，取消订单
          </van-button>
        </div>
      </section>

      <!-- Handoff Records list -->
      <section class="card-section">
        <h3 class="section-title">交接日志 · 商品编号 {{ listingCode }}</h3>
        <van-empty
          v-if="handoffRecords.length === 0"
          image="search"
          description="暂无交接日志记录"
        />
        <div v-else class="log-timeline">
          <div v-for="record in handoffRecords" :key="record.id" class="log-item">
            <div class="log-dot"></div>
            <div class="log-content-wrap">
              <strong class="log-type">{{ formatHandoffRecordType(record.type) }}</strong>
              <p class="log-desc">{{ record.content }}</p>
              <span class="log-time">{{ formatDateTime(record.created_at) }}</span>
            </div>
          </div>
        </div>
      </section>

      <!-- Renter Action: Return Account & Initiate Checkout -->
      <section
        v-if="isRenter && ['renting', 'overdue'].includes(order.status)"
        class="card-section action-card"
      >
        <h3 class="section-title">退号发起结账</h3>
        <p class="action-hint">使用完毕，请输入在此期间消耗的物资与哈夫币进行结账申请。</p>

        <van-field
          v-model="checkoutForm.content"
          rows="3"
          autosize
          label="结账备注"
          type="textarea"
          placeholder="可在此说明物品消耗情况或归还留言"
          class="action-field"
        />

        <!-- Checkout resource usage selection -->
        <div v-if="checkoutResources.length" class="resource-usage-panel">
          <strong class="resource-panel-title">额外物资消耗登记</strong>
          <div v-for="item in checkoutResources" :key="item.key" class="resource-row">
            <div class="resource-meta">
              <span class="resource-name">{{ item.label }}</span>
              <span class="resource-price-text"
                >上限 {{ item.quantity }} · {{ item.mode }} · {{ item.price }}</span
              >
            </div>
            <div class="stepper-wrap">
              <van-stepper v-model="resourceUsage[item.key]" integer min="0" :max="item.quantity" />
              <span class="resource-line-amount">¥{{ money(resourceLineAmount(item)) }}</span>
            </div>
          </div>
          <div class="resource-panel-footer">
            <span>物资金额合计：</span>
            <strong>¥{{ money(resourceChargeAmount) }}</strong>
          </div>
        </div>

        <van-cell-group inset :border="false" class="action-field">
          <van-field label="消耗哈夫币" label-width="100px">
            <template #input>
              <div class="coin-input-wrap">
                <input
                  v-model.number="checkoutForm.coin_consumed_m"
                  type="number"
                  placeholder="消耗数量"
                  class="custom-inline-input"
                />
                <span class="input-unit">M</span>
              </div>
            </template>
          </van-field>
          <div class="coin-hint">
            订单快照 {{ quantity(snapshotHafCoinM) }}M，预计剩余 {{ quantity(remainingHafCoinM) }}M
          </div>
          <van-field label="其他押金赔付" label-width="100px">
            <template #input>
              <div class="coin-input-wrap">
                <input
                  v-model.number="checkoutForm.other_amount"
                  type="number"
                  placeholder="不含上方额外物资"
                  class="custom-inline-input"
                />
                <span class="input-unit">元</span>
              </div>
            </template>
          </van-field>
          <div class="deposit-deduct-hint">仅填写封禁、违规、资产损坏等需要从押金赔付的费用。</div>
        </van-cell-group>
        <div class="checkout-fee-preview">
          <div>
            <span>额外消耗品已用</span>
            <strong>¥{{ money(resourceChargeAmount) }}</strong>
            <em>计入实际结算租金</em>
          </div>
          <div>
            <span>其他押金赔付</span>
            <strong>¥{{ money(checkoutForm.other_amount) }}</strong>
            <em>从押金赔付扣除</em>
          </div>
        </div>

        <van-field
          v-model="checkoutForm.evidenceText"
          rows="2"
          autosize
          label="结账证据"
          type="textarea"
          placeholder="结账截图链接（每行一个）"
          class="action-field"
        />

        <van-button
          type="primary"
          block
          round
          :loading="returning"
          loading-text="正在提交结账..."
          @click="handleSubmitCheckout"
        >
          提交结账归还
        </van-button>
      </section>

      <!-- Checkout Details Display -->
      <section
        v-if="
          order.checkout &&
          ['pending_checkout_confirm', 'pending_checkout_accept'].includes(order.status)
        "
        class="card-section"
      >
        <h3 class="section-title">结账结算账单</h3>
        <van-cell-group inset :border="false">
          <van-cell
            title="实际结算租金"
            :value="`¥${money(amountYuan(order.checkout.display_amount_cent))}`"
          />
          <van-cell
            title="押金总额"
            :label="
              amountYuan(order.deposit_waived_amount_cent) > 0
                ? `已免押 ¥${money(amountYuan(order.deposit_waived_amount_cent))}`
                : ''
            "
            :value="`¥${money(amountYuan(order.checkout.deposit_amount_cent))}`"
          />
          <van-cell
            title="额外消耗品已用"
            :value="`¥${money(amountYuan(order.checkout.consumable_amount_cent))}`"
          />
          <van-cell
            title="押金赔付扣除"
            :value="`¥${money(amountYuan(order.checkout.deposit_deduct_amount_cent))}`"
            value-class="red-text"
          />
          <van-cell
            v-if="isRenter"
            title="退还租客"
            :value="`¥${money(amountYuan(order.checkout.renter_refund_amount_cent))}`"
            value-class="green-text"
          />
          <van-cell
            v-if="isOwner"
            title="号主最终收入"
            :value="`¥${money(amountYuan(order.checkout.owner_income_amount_cent))}`"
            value-class="green-text"
          />
          <van-cell
            v-if="order.checkout.content"
            title="结账备注"
            :label="order.checkout.content"
          />
          <van-cell
            v-if="order.checkout.owner_adjustment_reason"
            title="号主修正原因"
            :label="order.checkout.owner_adjustment_reason"
          />
        </van-cell-group>
      </section>

      <!-- Owner Action: Confirm Checkout / Make Counter Adjustment Proposal -->
      <section
        v-if="isOwner && order.status === 'pending_checkout_confirm'"
        class="card-section action-card"
      >
        <h3 class="section-title">结账处理</h3>
        <p class="action-hint">
          租客已发起结账并归还账号。确认无误后点击“确认结账”；若扣款不足，可以提出“修改结账”反向提案。
        </p>
        <div class="action-buttons">
          <van-button
            type="primary"
            block
            round
            :loading="completing"
            loading-text="处理中..."
            @click="handleConfirmCheckout"
          >
            同意并确认结账
          </van-button>
          <van-button type="warning" block plain round @click="showCounterPopup = true">
            修改扣款金额
          </van-button>
        </div>
      </section>

      <!-- Renter Action: Accept Counter Checkout Proposal / Refuse and Dispute -->
      <section
        v-if="isRenter && order.status === 'pending_checkout_accept'"
        class="card-section action-card"
      >
        <h3 class="section-title">号主结账修正审批</h3>
        <p class="action-hint">
          号主修改了您的结账申请并对押金进行了扣除。请审查，同意将完成结算，不同意将进入仲裁申诉。
        </p>
        <div class="action-buttons">
          <van-button
            type="primary"
            block
            round
            :loading="acceptingCheckout"
            loading-text="同意中..."
            @click="handleAcceptCheckout"
          >
            同意修正并结账
          </van-button>
          <van-button type="danger" block plain round @click="showRejectPopup = true">
            拒绝修正并提起申诉
          </van-button>
        </div>
      </section>

      <!-- Universal Action: File a Dispute -->
      <section v-if="canOpenDispute" class="card-section action-card">
        <van-button type="warning" block plain round @click="showDisputePopup = true">
          {{ isCheckoutDisputeStage ? '对结账发起申诉争议' : '发起订单申诉争议' }}
        </van-button>
      </section>

      <!-- Snapshot Account Details Accordion -->
      <section class="card-section">
        <van-collapse v-model="activeNames">
          <van-collapse-item title="查看订单账号快照信息" name="snapshot">
            <template v-if="readSnapshot()">
              <van-cell-group :border="false">
                <van-cell title="区服" :value="order.server_region" />
                <van-cell title="登录平台" :value="order.login_platform" />
                <van-cell title="烽火等级" :value="readAssetSummary()?.fire_level || '--'" />
                <van-cell title="绝密KD" :value="readAssetSummary()?.secret_kd || '--'" />
                <van-cell
                  title="常用登录地区"
                  :value="readAssetSummary()?.common_regions?.join('、') || '--'"
                />
                <van-cell title="封禁记录" :value="readAssetSummary()?.ban_record || '无'" />
                <van-cell title="体力等级" :value="readAssetSummary()?.stamina_level || '--'" />
                <van-cell title="负重等级" :value="readAssetSummary()?.load_level || '--'" />
                <van-cell title="账号备注" :label="readSnapshot()?.description || '无'" />
              </van-cell-group>
            </template>
            <template v-else>
              <div class="no-snapshot-hint">暂无快照数据</div>
            </template>
          </van-collapse-item>
        </van-collapse>
      </section>
    </template>

    <div v-else class="empty-wrap">
      <van-empty image="search" description="订单不存在或已被删除" />
    </div>

    <!-- POPUP: Owner Counter Checkout Adjustments -->
    <van-popup v-model:show="showCounterPopup" position="bottom" round class="mobile-popup-form">
      <header class="popup-header">
        <h3>修改结账扣款金额</h3>
        <button class="popup-close" @click="showCounterPopup = false">✕</button>
      </header>
      <div class="popup-body">
        <p class="form-hint-info">
          在此调整实际使用的租金项目和押金赔付金额，提案将交由租客二次确认。
        </p>
        <van-cell-group :border="false">
          <van-field label="额外消耗品已用">
            <template #input>
              <input
                v-model.number="counterForm.consumable_amount"
                type="number"
                class="custom-inline-input"
              />
            </template>
          </van-field>
          <van-field label="消耗哈夫币 M">
            <template #input>
              <input
                v-model.number="counterForm.coin_consumed_m"
                type="number"
                class="custom-inline-input"
              />
            </template>
          </van-field>
          <van-field label="其他押金扣款">
            <template #input>
              <input
                v-model.number="counterForm.other_amount"
                type="number"
                class="custom-inline-input"
              />
            </template>
          </van-field>
          <van-field label="押金赔付扣除" required>
            <template #input>
              <input
                v-model.number="counterForm.deposit_deduct_amount"
                type="number"
                class="custom-inline-input"
              />
            </template>
          </van-field>
        </van-cell-group>
        <van-field
          v-model="counterForm.reason"
          rows="2"
          autosize
          label="修改原因"
          type="textarea"
          placeholder="请说明调整扣款的原因，说服租客确认"
          class="popup-field"
        />
        <van-field
          v-model="counterForm.evidenceText"
          rows="2"
          autosize
          label="扣款证据"
          type="textarea"
          placeholder="证据链接（每行一个）"
          class="popup-field"
        />
        <div class="evidence-upload-row">
          <span>上传新证据截图：</span>
          <input type="file" accept="image/*" @change="handleCounterEvidenceUpload" />
        </div>
        <van-button
          type="warning"
          block
          round
          :loading="countering"
          loading-text="提交中..."
          @click="handleCounterCheckout"
          class="popup-submit"
        >
          提交提案给租客确认
        </van-button>
      </div>
    </van-popup>

    <!-- POPUP: Renter Reject Counter Proposal Reason -->
    <van-popup v-model:show="showRejectPopup" position="bottom" round class="mobile-popup-form">
      <header class="popup-header">
        <h3>拒绝修正扣款说明</h3>
        <button class="popup-close" @click="showRejectPopup = false">✕</button>
      </header>
      <div class="popup-body">
        <p class="form-hint-info">
          拒绝号主的修正提案后，订单将立即自动发起争议，由客服介入根据证据判定。
        </p>
        <van-field
          v-model="rejectReason"
          rows="3"
          autosize
          label="拒绝原因"
          type="textarea"
          placeholder="请详细叙述拒绝号主扣款的理由，这些信息将被客服作为判定依据"
          class="popup-field"
        />
        <van-button
          type="danger"
          block
          round
          :loading="rejectingCheckout"
          loading-text="发起争议中..."
          @click="handleRejectCheckout"
          class="popup-submit"
        >
          提交原因并提起争议
        </van-button>
      </div>
    </van-popup>

    <!-- POPUP: Create Generic Order Dispute -->
    <van-popup v-model:show="showDisputePopup" position="bottom" round class="mobile-popup-form">
      <header class="popup-header">
        <h3>发起申诉争议</h3>
        <button class="popup-close" @click="showDisputePopup = false">✕</button>
      </header>
      <div class="popup-body">
        <van-field v-if="!isCheckoutDisputeStage" label="申诉类型" class="popup-field">
          <template #input>
            <select v-model="disputeType" class="custom-select">
              <option value="cannot_login">无法登录</option>
              <option value="false_description">虚假描述</option>
              <option value="account_banned">账号被封</option>
              <option value="asset_loss">资产损失</option>
              <option value="haf_coin_dispute">哈夫币争议</option>
              <option value="handoff_timeout">超时未交接</option>
              <option value="return_timeout">超时未归还</option>
            </select>
          </template>
        </van-field>
        <van-field
          v-model="disputeDescription"
          rows="3"
          autosize
          label="经过说明"
          type="textarea"
          placeholder="请在此描述您的诉求、事件经过、时间点等详细情况"
          class="popup-field"
        />
        <van-field
          v-model="disputeEvidenceText"
          rows="2"
          autosize
          label="证据列表"
          type="textarea"
          placeholder="证据链接（每行一个）"
          class="popup-field"
        />
        <div class="evidence-upload-row">
          <span>上传证据截图：</span>
          <input type="file" accept="image/*" @change="handleEvidenceUpload" />
        </div>
        <van-button
          type="warning"
          block
          round
          :loading="disputing"
          loading-text="正在发起申诉..."
          @click="handleCreateDispute"
          class="popup-submit"
        >
          提交申诉客服仲裁
        </van-button>
      </div>
    </van-popup>
  </main>
</template>

<style scoped>
.mobile-order-detail-view {
  min-height: 100dvh;
  background: #f5f7fa;
  padding-bottom: 40px;
}

/* ========== Header ========== */
.page-header {
  position: sticky;
  top: 0;
  z-index: 10;
  display: flex;
  align-items: center;
  height: 48px;
  padding: 0 12px;
  background: #fff;
  border-bottom: 1px solid #eee;
}

.page-header h1 {
  flex: 1;
  margin: 0;
  font-size: 17px;
  font-weight: 700;
  text-align: center;
}

.back-btn,
.chat-btn {
  display: grid;
  width: 36px;
  height: 36px;
  place-items: center;
  border: none;
  background: none;
  color: #333;
  cursor: pointer;
}

.chat-btn:disabled {
  color: #a1a1aa;
}

.header-spacer {
  width: 36px;
}

.center-loading {
  display: flex;
  justify-content: center;
  padding: 60px 0;
}

/* ========== Card layout ========== */
.card-section {
  margin: 12px;
  background: #fff;
  border-radius: 12px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
  overflow: hidden;
  padding: 14px;
}

.info-card {
  padding: 16px;
}

.card-header-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 10px;
}

.order-no {
  font-size: 12px;
  color: #999;
  font-family: monospace;
}

.listing-code-chip {
  margin-bottom: 10px;
  padding: 4px 9px;
  border: 1px solid #dbeafe;
  border-radius: 999px;
  background: #eff6ff;
  color: #2563eb;
  font-size: 12px;
  font-weight: 800;
}

.order-title {
  font-size: 18px;
  font-weight: 700;
  color: #1a1a1a;
  margin: 0 0 14px 0;
}

.order-meta-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 8px;
  background: #f8f9fa;
  border-radius: 8px;
  padding: 10px;
}

.meta-item {
  display: flex;
  flex-direction: column;
  align-items: center;
}

.meta-label {
  font-size: 11px;
  color: #8c96a0;
  margin-bottom: 4px;
}

.meta-value {
  font-size: 13px;
  color: #2c3e50;
  font-weight: 600;
}

.meta-value.accent {
  color: #ff5f00;
  font-weight: 700;
}

.meta-value.income {
  color: #16a34a;
  font-weight: 700;
}

.meta-note {
  margin-top: 2px;
  font-size: 10px;
  color: #2563eb;
}

.action-card {
  padding: 16px;
}

.section-title {
  font-size: 15px;
  font-weight: 700;
  color: #2c3e50;
  margin: 0 0 8px 0;
}

.action-hint {
  font-size: 12px;
  color: #7f8c8d;
  line-height: 1.5;
  margin: 0 0 14px 0;
}

.action-buttons {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.action-field {
  background: #f8fafc;
  border-radius: 8px;
  margin-bottom: 12px;
  overflow: hidden;
}

/* ========== Log Timeline ========== */
.log-timeline {
  display: flex;
  flex-direction: column;
  position: relative;
  padding-left: 16px;
  margin-top: 10px;
}

.log-timeline::after {
  content: '';
  position: absolute;
  top: 6px;
  bottom: 6px;
  left: 4px;
  width: 1px;
  background: #e2e8f0;
}

.log-item {
  position: relative;
  padding-bottom: 16px;
}

.log-item:last-child {
  padding-bottom: 0;
}

.log-dot {
  position: absolute;
  top: 5px;
  left: -15px;
  z-index: 2;
  width: 7px;
  height: 7px;
  background: #1477ff;
  border-radius: 50%;
}

.log-content-wrap {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.log-type {
  font-size: 13px;
  color: #2d3748;
}

.log-desc {
  font-size: 12px;
  color: #718096;
  margin: 0;
  line-height: 1.4;
}

.log-time {
  font-size: 11px;
  color: #a0aec0;
}

/* ========== Resource Panel ========== */
.resource-usage-panel {
  background: #f8fafc;
  border-radius: 8px;
  padding: 12px;
  margin-bottom: 12px;
}

.resource-panel-title {
  display: block;
  font-size: 13px;
  font-weight: 700;
  margin-bottom: 10px;
  color: #2d3748;
}

.resource-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 8px 0;
  border-bottom: 1px dashed #e2e8f0;
}

.resource-row:last-child {
  border-bottom: none;
}

.resource-meta {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.resource-name {
  font-size: 13px;
  color: #2d3748;
  font-weight: 600;
}

.resource-price-text {
  font-size: 11px;
  color: #a0aec0;
}

.stepper-wrap {
  display: flex;
  align-items: center;
  gap: 8px;
}

.resource-line-amount {
  min-width: 50px;
  text-align: right;
  font-size: 13px;
  font-weight: 700;
  color: #ff5f00;
}

.resource-panel-footer {
  display: flex;
  justify-content: flex-end;
  align-items: baseline;
  margin-top: 10px;
  font-size: 12px;
  color: #4a5568;
}

.resource-panel-footer strong {
  font-size: 15px;
  color: #ff5f00;
}

.deposit-deduct-hint {
  padding: 0 16px 10px;
  color: #8a94a6;
  font-size: 12px;
  line-height: 1.5;
}

.checkout-fee-preview {
  display: grid;
  gap: 8px;
  margin: 0 16px 12px;
}

.checkout-fee-preview div {
  display: grid;
  gap: 4px;
  padding: 10px 12px;
  border-radius: 8px;
  background: #f8fafc;
}

.checkout-fee-preview span {
  color: #4a5568;
  font-size: 12px;
  font-weight: 700;
}

.checkout-fee-preview strong {
  color: #ff5f00;
  font-size: 16px;
  font-weight: 800;
}

.checkout-fee-preview em {
  color: #8a94a6;
  font-size: 11px;
  font-style: normal;
}

.coin-input-wrap {
  display: flex;
  align-items: center;
  width: 100%;
}

.custom-inline-input {
  border: none;
  background: transparent;
  outline: none;
  font-size: 14px;
  flex: 1;
}

.input-unit {
  font-size: 14px;
  color: #718096;
  margin-left: 6px;
}

.coin-hint {
  font-size: 11px;
  color: #a0aec0;
  padding: 0 16px 8px 16px;
  margin-top: -6px;
}

.no-snapshot-hint {
  text-align: center;
  padding: 10px;
  color: #cbd5e0;
  font-size: 13px;
}

/* ========== Popups ========== */
.mobile-popup-form {
  max-height: 85%;
  padding-bottom: env(safe-area-inset-bottom);
}

.popup-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 16px;
  border-bottom: 1px solid #edf2f7;
}

.popup-header h3 {
  margin: 0;
  font-size: 16px;
  font-weight: 700;
}

.popup-close {
  border: none;
  background: transparent;
  font-size: 16px;
  color: #a0aec0;
  cursor: pointer;
}

.popup-body {
  padding: 16px;
  overflow-y: auto;
}

.form-hint-info {
  font-size: 12px;
  color: #718096;
  line-height: 1.5;
  margin: 0 0 12px 0;
}

.popup-field {
  background: #f7fafc;
  border-radius: 8px;
  margin-bottom: 12px;
}

.evidence-upload-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  font-size: 13px;
  color: #4a5568;
  margin-bottom: 16px;
}

.popup-submit {
  margin-top: 10px;
}

.custom-select {
  border: none;
  background: transparent;
  width: 100%;
  font-size: 14px;
  color: #2d3748;
  outline: none;
}

/* Utilities */
.red-text {
  color: #ef4444;
}

.green-text {
  color: #10b981;
}

.empty-wrap {
  padding: 60px 0;
}
</style>
