import { useRef, useState } from 'react';
import Taro, { useDidShow } from '@tarojs/taro';
import {
  Button,
  ConfigProvider,
  Empty,
  InfiniteLoading,
  Loading,
  Popup,
  PullToRefresh,
  SearchBar,
  Tabs,
  TabPane,
  Tag
} from '@nutui/nutui-react-taro';
import { View, Text, Image } from '@tarojs/components';
import { getGltUserTicket, pageGltUserTicket, updateGltUserTicket } from '@/api/glt/gltUserTicket';
import type { GltUserTicket } from '@/api/glt/gltUserTicket/model';
import { pageGltTicketOrder, removeGltTicketOrder, updateGltTicketOrder } from '@/api/glt/gltTicketOrder';
import type { GltTicketOrder } from '@/api/glt/gltTicketOrder/model';
import { BaseUrl } from '@/config/app';
import dayjs from "dayjs";
import { ensureLoggedIn } from '@/utils/auth';

const PAGE_SIZE = 10;
const PAY_REFRESH_HANDLED_KEY = 'user_ticket_from_pay_at_handled';

const UserTicketList = () => {
  const [ticketList, setTicketList] = useState<GltUserTicket[]>([]);
  const [ticketLoading, setTicketLoading] = useState(false);
  const [ticketHasMore, setTicketHasMore] = useState(true);
  const [searchValue, setSearchValue] = useState('');
  const [ticketPage, setTicketPage] = useState(1);
  const [ticketTotal, setTicketTotal] = useState(0);

  const [orderList, setOrderList] = useState<GltTicketOrder[]>([]);
  const [orderLoading, setOrderLoading] = useState(false);
  const [orderHasMore, setOrderHasMore] = useState(true);
  const [orderPage, setOrderPage] = useState(1);
  const [orderTotal, setOrderTotal] = useState(0);
  const [orderCancelLoadingById, setOrderCancelLoadingById] = useState<Record<number, boolean>>({});

  const [activeTab, setActiveTab] = useState<'ticket' | 'order'>(() => {
    const tab = Taro.getCurrentInstance().router?.params?.tab
    return tab === 'order' ? 'order' : 'ticket'
  });

  const [qrVisible, setQrVisible] = useState(false);
  const [qrTicket, setQrTicket] = useState<GltUserTicket | null>(null);
  const [qrImageUrl, setQrImageUrl] = useState('');
  const payAutoRefreshRunningRef = useRef(false);

  const sleep = (ms: number) => new Promise<void>((resolve) => setTimeout(resolve, ms));

  const parsePositiveNumberParam = (v: unknown) => {
    const n = Number(v);
    return Number.isFinite(n) && n > 0 ? n : undefined;
  };

  const getFromPayAtParam = () => {
    const params = Taro.getCurrentInstance().router?.params;
    return parsePositiveNumberParam((params as any)?.fromPayAt);
  };

  const shouldAutoRefreshAfterPay = (fromPayAt?: number) => {
    if (!fromPayAt) return false;
    const handled = parsePositiveNumberParam(Taro.getStorageSync(PAY_REFRESH_HANDLED_KEY)) || 0;
    return handled !== fromPayAt;
  };

  const getUserId = () => {
    const raw = Taro.getStorageSync('UserId');
    const id = Number(raw);
    return Number.isFinite(id) && id > 0 ? id : undefined;
  };

  const buildTicketQrContent = (ticket: GltUserTicket) => {
    // QR will be encrypted by `/qr-code/create-encrypted-qr-image`,
    // and decrypted on verifier side to get this payload.
    return JSON.stringify({
      userTicketId: ticket.id,
      qty: 1,
      userId: ticket.userId,
      t: Date.now()
    });
  };

  const buildEncryptedQrImageUrl = (businessType: string, data: string) => {
    const size = '300x300';
    const expireMinutes = 30;
    const base = BaseUrl?.replace(/\/+$/, '');
    return `${base}/qr-code/create-encrypted-qr-image?size=${encodeURIComponent(
      size
    )}&expireMinutes=${encodeURIComponent(String(expireMinutes))}&businessType=${encodeURIComponent(
      businessType
    )}&data=${encodeURIComponent(data)}`;
  };

  const openTicketQr = (ticket: GltUserTicket) => {
    if (!ticket?.id) {
      Taro.showToast({ title: '水票信息不完整', icon: 'none' });
      return;
    }
    if (ticket.status === 1) {
      Taro.showToast({ title: '该水票已冻结，无法核销', icon: 'none' });
      return;
    }
    if ((ticket.availableQty ?? 0) <= 0) {
      Taro.showToast({ title: '可用次数不足', icon: 'none' });
      return;
    }

    const content = buildTicketQrContent(ticket);
    setQrTicket(ticket);
    setQrImageUrl(buildEncryptedQrImageUrl('ticket', content));
    setQrVisible(true);
  };

  const goSendWater = async (ticket: GltUserTicket) => {
    if (!ticket?.id) {
      Taro.showToast({ title: '水票信息不完整', icon: 'none' });
      return;
    }
    if (Number(ticket.status) === 1) {
      Taro.showToast({ title: '该水票已冻结，无法下单', icon: 'none' });
      return;
    }
    const avail = Number(ticket.availableQty ?? 0);
    if (!Number.isFinite(avail) || avail <= 0) {
      Taro.showToast({ title: '可用次数不足', icon: 'none' });
      return;
    }
    const gid = Number(ticket.goodsId);
    const url =
      Number.isFinite(gid) && gid > 0 ? `/user/ticket/use?goodsId=${gid}` : '/user/ticket/use';
    if (!ensureLoggedIn(url)) return;
    await Taro.navigateTo({ url });
  };

  const goReleasePlanDetail = async (ticket: GltUserTicket) => {
    if (!ticket?.id) {
      Taro.showToast({ title: '水票信息不完整', icon: 'none' });
      return;
    }
    const url = `/user/ticket/release/index?userTicketId=${encodeURIComponent(String(ticket.id))}&templateName=${encodeURIComponent(
      String(ticket.templateName ?? '')
    )}&frozenQty=${encodeURIComponent(String(ticket.frozenQty ?? 0))}&releasedQty=${encodeURIComponent(
      String(ticket.releasedQty ?? 0)
    )}`;
    if (!ensureLoggedIn(url)) return;
    await Taro.navigateTo({ url });
  };

  const showTicketDetail = (ticket: GltUserTicket) => {
    const lines: string[] = [];
    if (ticket.templateName) lines.push(`水票：${ticket.templateName}`);
    lines.push(`可用：${ticket.availableQty ?? 0}`);
    lines.push(`总量：${ticket.totalQty ?? 0}`);
    lines.push(`已用：${ticket.usedQty ?? 0}`);
    lines.push(`冻结：${ticket.frozenQty ?? 0}`);
    lines.push(`已释放：${ticket.releasedQty ?? 0}`);
    if (ticket.orderNo) lines.push(`订单号：${ticket.orderNo}`);
    // Taro.showModal({
    //   title: '水票详情',
    //   content: lines.join('\n'),
    //   showCancel: false
    // });
  };

  const reloadTickets = async (isRefresh = true, keywords?: string) => {
    if (ticketLoading) return;

    const userId = getUserId();
    if (!userId) {
      setTicketList([]);
      setTicketTotal(0);
      setTicketHasMore(false);
      return;
    }

    if (isRefresh) {
      setTicketPage(1);
      setTicketList([]);
      setTicketHasMore(true);
    }

    setTicketLoading(true);
    try {
      const currentPage = isRefresh ? 1 : ticketPage;
      const res = await pageGltUserTicket({
        page: currentPage,
        limit: PAGE_SIZE,
        userId,
        keywords: (keywords ?? searchValue) || undefined
      });

      const nextList = isRefresh ? res.list : [...ticketList, ...res.list];
      setTicketList(nextList);
      const count = typeof res.count === 'number' ? res.count : nextList.length;
      setTicketTotal(count);
      setTicketHasMore(nextList.length < count);

      if (res.list.length > 0) {
        setTicketPage(currentPage + 1);
      } else {
        setTicketHasMore(false);
      }
    } catch (error) {
      console.error('获取水票列表失败:', error);
      Taro.showToast({ title: '获取水票失败', icon: 'error' });
      setTicketHasMore(false);
    } finally {
      setTicketLoading(false);
    }
  };

  const reloadOrders = async (isRefresh = true, keywords?: string) => {
    if (orderLoading) return;

    const userId = getUserId();
    if (!userId) {
      setOrderList([]);
      setOrderTotal(0);
      setOrderHasMore(false);
      return;
    }

    if (isRefresh) {
      setOrderPage(1);
      setOrderList([]);
      setOrderHasMore(true);
    }

    setOrderLoading(true);
    try {
      const currentPage = isRefresh ? 1 : orderPage;
      const res = await pageGltTicketOrder({
        page: currentPage,
        limit: PAGE_SIZE,
        userId,
        keywords: (keywords ?? searchValue) || undefined
      });

      const resList = res?.list || [];
      const safeList = resList.filter((o) => Number((o as any)?.deleted) !== 1);
      const nextList = isRefresh ? safeList : [...orderList, ...safeList];
      setOrderList(nextList);
      const serverCount = typeof res?.count === 'number' ? res.count : undefined;
      const total = typeof serverCount === 'number' ? serverCount : nextList.length;
      setOrderTotal(total);
      setOrderHasMore(typeof serverCount === 'number' ? nextList.length < serverCount : resList.length >= PAGE_SIZE);

      if (resList.length > 0) setOrderPage(currentPage + 1);
      else setOrderHasMore(false);
    } catch (error) {
      console.error('获取送水订单失败:', error);
      Taro.showToast({ title: '获取送水订单失败', icon: 'error' });
      setOrderHasMore(false);
    } finally {
      setOrderLoading(false);
    }
  };

  const handleSearch = (value: string) => {
    setSearchValue(value);
    if (activeTab === 'ticket') {
      reloadTickets(true, value);
    } else {
      reloadOrders(true, value);
    }
  };

  const handleRefresh = async () => {
    if (activeTab === 'ticket') {
      await reloadTickets(true);
    } else {
      await reloadOrders(true);
    }
  };

  const handleTabChange = (value: string | number) => {
    const tab = String(value) as 'ticket' | 'order';
    setActiveTab(tab);
    if (tab === 'ticket') {
      setTicketPage(1);
      setTicketList([]);
      setTicketHasMore(true);
      reloadTickets(true);
    } else {
      setOrderPage(1);
      setOrderList([]);
      setOrderHasMore(true);
      reloadOrders(true);
    }
  };

  const loadMoreTickets = async () => {
    if (!ticketLoading && ticketHasMore) {
      await reloadTickets(false);
    }
  };

  const loadMoreOrders = async () => {
    if (!orderLoading && orderHasMore) {
      await reloadOrders(false);
    }
  };

  const formatDateTime = (v?: string) => {
    if (!v) return '-';
    const d = dayjs(v);
    return d.isValid() ? d.format('YYYY年MM月DD日 HH:mm:ss') : v;
  };

  const formatDate = (v?: string) => {
    if (!v) return '-';
    const d = dayjs(v);
    return d.isValid() ? d.format('YYYY年MM月DD日') : v;
  };

  const getTicketAvailableQty = (t?: Partial<GltUserTicket> | null) => {
    if (!t) return 0;
    const anyT: any = t;
    const raw =
      anyT.availableQty ??
      anyT.availableNum ??
      anyT.availableCount ??
      anyT.remainQty ??
      anyT.remainNum ??
      anyT.remainCount;
    const n = Number(raw);
    if (Number.isFinite(n)) return n;

    const total = Number(anyT.totalQty ?? anyT.totalNum ?? anyT.totalCount ?? 0);
    const used = Number(anyT.usedQty ?? anyT.usedNum ?? anyT.usedCount ?? 0);
    const frozen = Number(anyT.frozenQty ?? anyT.frozenNum ?? anyT.frozenCount ?? 0);
    const computed =
      (Number.isFinite(total) ? total : 0) -
      (Number.isFinite(used) ? used : 0) -
      (Number.isFinite(frozen) ? frozen : 0);
    return Number.isFinite(computed) ? computed : 0;
  };

  const getTicketUsedQty = (t?: Partial<GltUserTicket> | null) => {
    if (!t) return 0;
    const anyT: any = t;
    const raw = anyT.usedQty ?? anyT.usedNum ?? anyT.usedCount;
    const n = Number(raw);
    return Number.isFinite(n) ? n : 0;
  };

  const rollbackUserTicketAfterOrderCancel = async (order: GltTicketOrder, before?: GltUserTicket | null) => {
    const orderId = Number(order?.id);
    const ticketId = Number(order?.userTicketId);
    const qty = Math.max(0, Math.floor(Number((order as any)?.totalNum ?? 0)));
    if (!Number.isFinite(orderId) || orderId <= 0) return;
    if (!Number.isFinite(ticketId) || ticketId <= 0) return;
    if (!Number.isFinite(qty) || qty <= 0) return;

    const rollbackKey = `glt_ticket_order_rollback:${orderId}`;
    if (Taro.getStorageSync(rollbackKey)) return;

    const after = await getGltUserTicket(ticketId);
    if (!after?.id) return;

    const beforeAvail = before ? getTicketAvailableQty(before) : undefined;
    const afterAvail = getTicketAvailableQty(after);
    const beforeUsed = before ? getTicketUsedQty(before) : undefined;
    const afterUsed = getTicketUsedQty(after);

    let needAvail = qty;
    if (typeof beforeAvail === 'number') {
      const delta = afterAvail - beforeAvail;
      if (delta >= qty) {
        Taro.setStorageSync(rollbackKey, Date.now());
        return; // backend already rolled back
      }
      if (delta > 0) needAvail = Math.max(0, qty - delta);
    }
    let needUsed = qty;
    if (typeof beforeUsed === 'number') {
      const delta = beforeUsed - afterUsed;
      if (delta >= qty) {
        needUsed = 0; // backend already rolled back used qty
      } else if (delta > 0) {
        needUsed = Math.max(0, qty - delta);
      }
    }

    if (needAvail <= 0 && needUsed <= 0) {
      Taro.setStorageSync(rollbackKey, Date.now());
      return;
    }

    const currentAvailRaw = Number((after as any)?.availableQty);
    const baseAvail = Number.isFinite(currentAvailRaw) ? currentAvailRaw : afterAvail;
    const safeBaseAvail = Number.isFinite(baseAvail) ? baseAvail : 0;

    const totalRaw = Number((after as any)?.totalQty ?? 0);
    const total = Number.isFinite(totalRaw) ? totalRaw : undefined;
    const frozenRaw = Number((after as any)?.frozenQty ?? 0);
    const frozen = Number.isFinite(frozenRaw) ? frozenRaw : 0;

    const currentUsedRaw = Number((after as any)?.usedQty);
    const baseUsed = Number.isFinite(currentUsedRaw) ? currentUsedRaw : afterUsed;
    const safeBaseUsed = Number.isFinite(baseUsed) ? baseUsed : 0;
    let nextUsed = safeBaseUsed - needUsed;
    if (nextUsed < 0) nextUsed = 0;

    const maxAvail = typeof total === 'number' ? Math.max(0, total - frozen - nextUsed) : undefined;

    let nextAvail = safeBaseAvail + needAvail;
    if (typeof maxAvail === 'number' && Number.isFinite(maxAvail) && nextAvail > maxAvail) nextAvail = maxAvail;
    if (nextAvail < 0) nextAvail = 0;

    await updateGltUserTicket({
      ...after,
      availableQty: nextAvail,
      usedQty: nextUsed
    });

    Taro.setStorageSync(rollbackKey, Date.now());
  };

  // Allow users to modify/cancel before delivery starts (e.g. 待派单 / 待配送).
  const isTicketOrderPendingDelivery = (order: GltTicketOrder) => {
    if (!order?.id) return false;
    if (Number(order.status) === 1) return false;
    if (Number((order as any)?.deleted) === 1) return false;
    if (order.receiveConfirmTime || order.sendEndTime || order.sendStartTime) return false;

    const ds = Number((order as any)?.deliveryStatus);
    // If backend didn't set deliveryStatus yet, treat it as pending.
    if (!Number.isFinite(ds)) return true;
    // 0/10: before delivery starts
    return ds === 0 || ds === 10;
  };

  const handleOrderModify = async (order: GltTicketOrder) => {
    if (!order?.id) {
      Taro.showToast({ title: '订单信息不完整', icon: 'none' });
      return;
    }
    if (!isTicketOrderPendingDelivery(order)) {
      Taro.showToast({ title: '仅配送未开始的订单可修改', icon: 'none' });
      return;
    }
    Taro.navigateTo({ url: `/user/ticket/use?orderId=${order.id}` });
  };

  const handleOrderCancel = async (order: GltTicketOrder) => {
    if (!order?.id) {
      Taro.showToast({ title: '订单信息不完整', icon: 'none' });
      return;
    }
    if (!isTicketOrderPendingDelivery(order)) {
      Taro.showToast({ title: '仅配送未开始的订单可取消', icon: 'none' });
      return;
    }
    if (orderCancelLoadingById[order.id]) return;

    const modal = await Taro.showModal({
      title: '取消订单',
      content: '确定要取消该订单吗？取消后无法恢复。',
      confirmText: '确认取消'
    });
    if (!modal.confirm) return;

    try {
      setOrderCancelLoadingById((prev) => ({ ...prev, [order.id as number]: true }));
      Taro.showLoading({ title: '取消中...' });
      let beforeTicket: GltUserTicket | null = null;
      if (order.userTicketId) {
        beforeTicket = await getGltUserTicket(Number(order.userTicketId)).catch(() => null);
      }
      try {
        await updateGltTicketOrder({ id: order.id, deleted: 1 });
      } catch (e) {
        await removeGltTicketOrder(order.id);
      }
      try {
        await rollbackUserTicketAfterOrderCancel(order, beforeTicket);
        Taro.showToast({ title: '订单已取消，水票已退回', icon: 'none' });
      } catch (e) {
        console.error('取消订单后退回水票失败:', e);
        await Taro.showModal({
          title: '取消成功',
          content: '订单已取消，但水票退回失败，请稍后刷新“我的水票”确认，或联系客服处理。',
          showCancel: false
        });
      }
      await reloadOrders(true);
    } catch (e) {
      console.error('取消送水订单失败:', e);
      Taro.showToast({ title: '取消失败，请重试', icon: 'none' });
    } finally {
      Taro.hideLoading();
      setOrderCancelLoadingById((prev) => ({ ...prev, [order.id as number]: false }));
    }
  };

  const getTicketOrderStatusMeta = (order: GltTicketOrder) => {
    if (order.status === 1) return { text: '已冻结', type: 'warning' as const };

    const ds = order.deliveryStatus
    if (ds === 40 || order.receiveConfirmTime) return { text: '已完成', type: 'success' as const };
    if (ds === 30 || order.sendEndTime) return { text: '待确认收货', type: 'primary' as const };
    if (ds === 20 || order.sendStartTime) return { text: '配送中', type: 'primary' as const };
    if (ds === 10 || order.riderId) return { text: '待配送', type: 'warning' as const };
    return { text: '待派单', type: 'primary' as const };
  };

  const canUserConfirmReceive = (order: GltTicketOrder) => {
    if (!order?.id) return false
    if (order.status === 1) return false
    if (order.deliveryStatus === 40) return false
    if (order.receiveConfirmTime) return false
    // 必须是“已送达”后才能确认收货
    return !!order.sendEndTime || order.deliveryStatus === 30
  }

  const handleUserConfirmReceive = async (order: GltTicketOrder) => {
    if (!order?.id) return
    if (!canUserConfirmReceive(order)) return

    const modal = await Taro.showModal({
      title: '确认收货',
      content: '请确认已收到本次送水，确认后将无法撤销。',
      confirmText: '确认收货'
    })
    if (!modal.confirm) return

    try {
      Taro.showLoading({ title: '提交中...' })
      const now = dayjs().format('YYYY-MM-DD HH:mm:ss')
      await updateGltTicketOrder({
        id: order.id,
        deliveryStatus: 40,
        receiveConfirmTime: now,
        receiveConfirmType: 10
      })
      Taro.showToast({ title: '已确认收货', icon: 'success' })
      await reloadOrders(true)
    } catch (e) {
      console.error('确认收货失败:', e)
      Taro.showToast({ title: '确认失败，请重试', icon: 'none' })
    } finally {
      Taro.hideLoading()
    }
  }

  useDidShow(() => {
    void (async () => {
      const tabParam = Taro.getCurrentInstance().router?.params?.tab;
      const nextTab = tabParam === 'ticket' || tabParam === 'order' ? tabParam : undefined;

      if (nextTab && nextTab !== activeTab) {
        setActiveTab(nextTab);
      }

      const tabToLoad = nextTab || activeTab;
      if (tabToLoad === 'ticket') {
        await reloadTickets(true);

        const fromPayAt = getFromPayAtParam();
        if (shouldAutoRefreshAfterPay(fromPayAt) && !payAutoRefreshRunningRef.current) {
          payAutoRefreshRunningRef.current = true;
          try {
            Taro.setStorageSync(PAY_REFRESH_HANDLED_KEY, fromPayAt);
            // 支付后水票可能异步入账：自动再刷新几次，避免用户手动下拉刷新。
            for (const delayMs of [800, 1500, 2500]) {
              await sleep(delayMs);
              await reloadTickets(true);
            }
          } finally {
            payAutoRefreshRunningRef.current = false;
          }
        }
      } else {
        await reloadOrders(true);
      }
    })();
  })

  return (
    <ConfigProvider>
      {/* 搜索栏 */}
      <View className="bg-white px-4 py-3 hidden">
        <SearchBar
          placeholder="搜索水票"
          value={searchValue}
          onChange={setSearchValue}
          onSearch={handleSearch}
        />
      </View>

      {/* Tab切换 */}
      <View className="bg-white">
        <Tabs value={activeTab} onChange={handleTabChange}>
          <TabPane title="我的水票" value="ticket"></TabPane>
          <TabPane title="送水订单" value="order"></TabPane>
        </Tabs>
      </View>

      {activeTab === 'ticket' && ticketTotal > 0 && (
        <View className="px-4 py-2 text-sm text-gray-500 bg-gray-50 hidden">
          共 {ticketTotal} 条水票记录
        </View>
      )}

      {activeTab === 'order' && orderTotal > 0 && (
        <View className="px-4 py-2 text-sm text-gray-500 bg-gray-50 hidden">
          共 {orderTotal} 条送水订单
        </View>
      )}

      {/* 列表 */}
      <PullToRefresh onRefresh={handleRefresh} headHeight={60}>
        <View style={{ height: 'calc(100vh)', overflowY: 'auto' }} id="ticket-scroll">
          {activeTab === 'ticket' && ticketList.length === 0 && !ticketLoading ? (
            <View
              className="flex flex-col justify-center items-center"
              style={{ height: 'calc(100vh - 160px)' }}
            >
              <Empty
                description="暂无水票"
                style={{ backgroundColor: 'transparent' }}
              />
            </View>
          ) : activeTab === 'order' && orderList.length === 0 && !orderLoading ? (
            <View
              className="flex flex-col justify-center items-center"
              style={{ height: 'calc(100vh - 160px)' }}
            >
              <Empty description="暂无送水订单" style={{ backgroundColor: 'transparent' }} />
            </View>
          ) : activeTab === 'ticket' ? (
            <InfiniteLoading
              target="ticket-scroll"
              hasMore={ticketHasMore}
              onLoadMore={loadMoreTickets}
              loadingText={
                <View className="flex justify-center items-center py-4">
                  <Loading />
                  <View className="ml-2">加载中...</View>
                </View>
              }
              loadMoreText={
                <View className="text-center py-4 text-gray-500">
                  {ticketList.length === 0 ? '暂无数据' : '没有更多了'}
                </View>
              }
            >
              <View className="px-4 py-3">
                {ticketList.map((item, index) => (
                  <View
                    key={String(item.id ?? `${item.templateId ?? 't'}-${index}`)}
                    className="bg-white rounded-xl p-4 mb-3"
                    onClick={() => showTicketDetail(item)}
                  >
                    <View className="flex items-start justify-between">
                      <View className="flex-1 pr-3">
                        <Text className="text-base font-semibold text-gray-900">
                          票号：{item.id}
                        </Text>
                        <View className="mt-1">
                          <Text className="text-xs text-gray-500">套票名称：{item.templateName}</Text>
                        </View>
                        {item.orderNo && (
                          <View className="mt-1">
                            <Text className="text-xs text-gray-500">订单编号：{item.orderNo}</Text>
                          </View>
                        )}
                        {item.createTime && (
                          <View className="mt-1">
                            <Text className="text-xs text-gray-400">下单时间：{dayjs(item.createTime).format('YYYY年MM月DD日 HH:mm:ss')}</Text>
                          </View>
                        )}
                      </View>
                      <View className="flex flex-col items-end gap-2">
                        <Button
                          size="small"
                          type="primary"
                          disabled={(item.availableQty ?? 0) <= 0 || item.status === 1}
                          onClick={(e) => {
                            e.stopPropagation();
                            void goSendWater(item);
                          }}
                        >
                          立即送水
                        </Button>
                        {/*<Tag type={item.status === 1 ? 'danger' : 'success'}>*/}
                        {/*  {item.status === 1 ? '冻结' : '正常'}*/}
                        {/*</Tag>*/}
                        <Button
                          size="small"
                          type="primary"
                          style={{ display: 'none'}}
                          disabled={(item.availableQty ?? 0) <= 0 || item.status === 1}
                          onClick={(e) => {
                            // Avoid triggering card click.
                            e.stopPropagation();
                            openTicketQr(item);
                          }}
                        >
                          出示核销码
                        </Button>
                      </View>
                    </View>

                    <View className="mt-3 flex justify-between">
                      <View className="flex flex-col items-center">
                        <Text className="text-lg font-bold text-blue-600 text-center">{item.availableQty ?? 0}</Text>
                        <Text className="text-xs text-gray-500">可用水票</Text>
                      </View>
                      <View className="flex flex-col items-center">
                        <Text className="text-lg text-gray-900 text-center">{item.usedQty ?? 0}</Text>
                        <Text className="text-xs text-gray-500">已用水票</Text>
                      </View>
                      <View
                        className="flex flex-col items-center"
                        hoverClass="opacity-70"
                        onClick={(e) => {
                          e.stopPropagation();
                          void goReleasePlanDetail(item);
                        }}
                      >
                        <Text className="text-lg text-gray-900 text-center">{item.frozenQty ?? 0}</Text>
                        <Text className="text-xs text-gray-500">剩余赠票</Text>
                      </View>
                    </View>
                  </View>
                ))}
              </View>
            </InfiniteLoading>
          ) : (
            <InfiniteLoading
              target="ticket-scroll"
              hasMore={orderHasMore}
              onLoadMore={loadMoreOrders}
              loadingText={
                <View className="flex justify-center items-center py-4">
                  <Loading />
                  <View className="ml-2">加载中...</View>
                </View>
              }
              loadMoreText={
                <View className="text-center py-4 text-gray-500">
                  {orderList.length === 0 ? '暂无数据' : '没有更多了'}
                </View>
              }
            >
              <View className="px-4 py-3">
                {orderList.map((item, index) => (
                  <View
                    key={String(item.id ?? `order-${index}`)}
                    className="bg-white rounded-xl p-4 mb-3"
                  >
                    <View className="flex items-start justify-between">
                      <View className="flex-1 pr-3">
                        <Text className="text-base font-semibold text-gray-900">
                          票号：{item.userTicketId ?? '-'}
                        </Text>
                        <View className="mt-1">
                          <Text className="text-xs text-gray-500">送水数量：{item.totalNum ?? 0}</Text>
                        </View>
                        <View className="mt-1">
                          <Text className="text-xs text-gray-500">配送时间：{formatDate(item.sendTime)}</Text>
                        </View>
                      </View>
                      {(() => {
                        const meta = getTicketOrderStatusMeta(item);
                        return <Tag type={meta.type}>{meta.text}</Tag>;
                      })()}
                    </View>
                    <View className="mt-2 text-xs text-gray-500">
                      <Text>订单号：{item.id ?? '-'}</Text>
                    </View>
                    <View className="mt-1 text-xs text-gray-500">
                      <Text>收货地址：{item.address || '-'}</Text>
                    </View>
                    <View className="mt-1">
                      <Text className="text-xs text-gray-500">下单时间：{formatDateTime(item.createTime)}</Text>
                    </View>
                    {/*{item.storeName ? (*/}
                    {/*  <View className="mt-1 text-xs text-gray-500">*/}
                    {/*    <Text>门店：{item.storeName}</Text>*/}
                    {/*  </View>*/}
                    {/*) : null}*/}
                    {item.sendStartTime ? (
                      <View className="mt-1 text-xs text-gray-500">
                        <Text>开始配送：{formatDateTime(item.sendStartTime)}</Text>
                      </View>
                    ) : null}
                    {item.sendEndTime ? (
                      <View className="mt-1 text-xs text-gray-500">
                        <Text>送达时间：{formatDateTime(item.sendEndTime)}</Text>
                      </View>
                    ) : null}
                    {item.receiveConfirmTime ? (
                      <View className="mt-1 text-xs text-gray-500">
                        <Text>确认收货：{formatDateTime(item.receiveConfirmTime)}</Text>
                      </View>
                    ) : null}
                    {item.sendEndImg ? (
                      <View className="mt-3">
                        <Image src={item.sendEndImg} mode="aspectFill" style={{ width: '100%', height: '160px', borderRadius: '8px' }} />
                      </View>
                    ) : null}
                    {canUserConfirmReceive(item) ? (
                      <View className="mt-3 flex justify-end">
                        <Button
                          type="primary"
                          size="small"
                          onClick={() => handleUserConfirmReceive(item)}
                        >
                          确认收货
                        </Button>
                      </View>
                    ) : null}

                    {item.id ? (
                      <View className="mt-3 flex justify-end gap-2">
                        <Button
                          size="small"
                          disabled={
                            !isTicketOrderPendingDelivery(item) ||
                            !!orderCancelLoadingById[item.id as number]
                          }
                          onClick={(e) => {
                            e.stopPropagation();
                            void handleOrderModify(item);
                          }}
                        >
                          修改订单
                        </Button>
                        <Button
                          size="small"
                          type="danger"
                          disabled={
                            !isTicketOrderPendingDelivery(item) ||
                            !!orderCancelLoadingById[item.id as number]
                          }
                          onClick={(e) => {
                            e.stopPropagation();
                            void handleOrderCancel(item);
                          }}
                        >
                          取消订单
                        </Button>
                      </View>
                    ) : null}
                  </View>
                ))}
              </View>
            </InfiniteLoading>
          )}
        </View>
      </PullToRefresh>

      {/* 核销二维码 */}
      <Popup
        visible={qrVisible}
        position="center"
        closeable
        onClose={() => setQrVisible(false)}
        style={{ width: '90%' }}
      >
        <View className="p-6">
          <View className="mb-4">
            <Text className="text-lg font-bold">水票核销码</Text>
          </View>

          {qrTicket && (
            <View className="bg-gray-50 rounded-lg p-3 mb-4">
              <View className="flex justify-between mb-2">
                <Text className="text-sm text-gray-600">票号</Text>
                <Text className="text-sm text-gray-900">{qrTicket.id}</Text>
              </View>
              <View className="flex justify-between">
                <Text className="text-sm text-gray-600">可用次数</Text>
                <Text className="text-sm text-gray-900">{qrTicket.availableQty ?? 0}</Text>
              </View>
            </View>
          )}

          <View className="text-center mb-4">
            <View className="p-4 bg-white border border-gray-200 rounded-lg">
              {qrImageUrl ? (
                <View className="flex flex-col justify-center items-center">
                  <Image
                    src={qrImageUrl}
                    mode="aspectFit"
                    style={{ width: '200px', height: '200px' }}
                  />
                  <Text className="text-sm text-gray-400 mt-2 px-2">
                    请向配送员出示此二维码
                  </Text>
                </View>
              ) : (
                <View
                  className="bg-gray-100 rounded flex items-center justify-center mx-auto"
                  style={{ width: '200px', height: '200px' }}
                >
                  <Text className="text-gray-500 text-sm">生成中...</Text>
                </View>
              )}
            </View>
          </View>

          <Button
            type="primary"
            block
            onClick={() => {
              if (!qrTicket) return;
              const content = buildTicketQrContent(qrTicket);
              setQrImageUrl(buildEncryptedQrImageUrl('ticket', content));
            }}
          >
            刷新二维码
          </Button>
        </View>
      </Popup>
    </ConfigProvider>
  );
};

export default UserTicketList;
