console.log("[EscortOrderChatPage] bubble shell loaded");

var EscortOrderChatPage = function () {
  var React = window.React;
  var useState = React.useState;
  var useEffect = React.useEffect;
  var useRef = React.useRef;
  var NK = window.NK || {};

  var pageParams = (NK.Store && typeof NK.Store.get === "function") ? (NK.Store.get("pageParams") || {}) : {};
  var initialConversationId = Number(pageParams.conversationId || 0);
  if (!initialConversationId || isNaN(initialConversationId)) initialConversationId = 0;
  var pageLatestOrder = pageParams.latestOrder && typeof pageParams.latestOrder === "object" ? pageParams.latestOrder : null;
  var latestOrderId = pageLatestOrder ? Number(pageLatestOrder.orderId || pageLatestOrder.id || 0) : 0;
  if (!latestOrderId || isNaN(latestOrderId)) latestOrderId = 0;
  var pageRole = pageParams.role || "buyer";
  var rawId = pageParams.orderId || pageParams.id || pageParams.escortOrderId || latestOrderId;
  var orderId = Number(rawId);
  if (!orderId || isNaN(orderId)) orderId = 0;
  var noOrderMode = initialConversationId > 0 && pageParams.latestOrder === null;
  if (noOrderMode) orderId = 0;
  var isBoosterView = false;
  var msgJustify = "flex-start";
  var msgBorderRadius = "4px 12px 12px 12px";

  var tryGetSnapshot = function () {
    if (pageParams.escortOrderSnapshot && Number(pageParams.escortOrderSnapshot.id || pageParams.escortOrderSnapshot.orderId) === orderId) return pageParams.escortOrderSnapshot;
    try {
      var key = "escort_order_chat_" + orderId;
      var raw = sessionStorage.getItem(key);
      if (raw) { var parsed = JSON.parse(raw); if (parsed && Number(parsed.id || parsed.orderId) === orderId) return parsed; }
    } catch (e) {}
    return null;
  };

  var snapshot = tryGetSnapshot();
  var pageLatestOrderMatches = pageLatestOrder && Number(pageLatestOrder.orderId || pageLatestOrder.id) === orderId;
  var initialOrder = pageLatestOrderMatches ? pageLatestOrder : (snapshot || null);

  var _u = useState;
  var _conversationIdState = _u(initialConversationId); var conversationId = _conversationIdState[0]; var setConversationId = _conversationIdState[1];
  var _loadingArr = _u(!initialOrder && !noOrderMode); var loading = _loadingArr[0]; var setLoading = _loadingArr[1];
  var _errorMsgArr = _u(!orderId && !initialOrder && !noOrderMode ? "\u8BA2\u5355\u53C2\u6570\u7F3A\u5931\uFF0C\u8BF7\u8FD4\u56DE\u540E\u91CD\u8BD5"  : ""); var errorMsg = _errorMsgArr[0]; var setErrorMsg = _errorMsgArr[1];
    var _displayOrder = _u(initialOrder);
  var displayOrder = _displayOrder[0];
  var setDisplayOrder = _displayOrder[1];
  var _latestOrderState = _u(initialOrder); var latestOrder = _latestOrderState[0]; var setLatestOrder = _latestOrderState[1];
  var _orderDetailReady = _u(noOrderMode); var orderDetailReady = _orderDetailReady[0]; var setOrderDetailReady = _orderDetailReady[1];
  var _activeOrderIdState = _u(orderId); var activeOrderId = _activeOrderIdState[0]; var setActiveOrderId = _activeOrderIdState[1];
  var _orderActionSubmitting = _u(""); var orderActionSubmitting = _orderActionSubmitting[0]; var setOrderActionSubmitting = _orderActionSubmitting[1];
  var _starting = useState(false);
  var starting = _starting[0];
  var setStarting = _starting[1];
  var _showBoosterModal = useState(false);
  var showBoosterModal = _showBoosterModal[0];
  var setShowBoosterModal = _showBoosterModal[1];
  var _selectedFiles = useState([]);
  var selectedFiles = _selectedFiles[0];
  var setSelectedFiles = _selectedFiles[1];
  var _uploading = useState(false);
  var uploading = _uploading[0];
  var setUploading = _uploading[1];
  var _completing = useState(false);
  // Conversation mode state
  var _conversationData = useState(null); var conversationData = _conversationData[0]; var setConversationData = _conversationData[1];
  var _convLoading = useState(true); var convLoading = _convLoading[0]; var setConvLoading = _convLoading[1];
  var _currentOrder = useState(null); var currentOrder = _currentOrder[0]; var setCurrentOrder = _currentOrder[1];
  var _allOrders = useState([]); var allOrders = _allOrders[0]; var setAllOrders = _allOrders[1];
  var completing = _completing[0];
  var setCompleting = _completing[1];
  var _showReviewModal = useState(false);
  var showReviewModal = _showReviewModal[0];
  var setShowReviewModal = _showReviewModal[1];
  var _reviewRating = useState("good");
  var reviewRating = _reviewRating[0];
  var setReviewRating = _reviewRating[1];
  var _reviewText = useState("");
  var reviewText = _reviewText[0];
  var setReviewText = _reviewText[1];
  var _reviewImages = useState([]);
  var reviewImages = _reviewImages[0];
  var setReviewImages = _reviewImages[1];
  var _imMessages = useState([]); var imMessages = _imMessages[0]; var setImMessages = _imMessages[1];
  var _imInput = useState(""); var imInput = _imInput[0]; var setImInput = _imInput[1];
  var _imLoading = useState(conversationId > 0); var imLoading = _imLoading[0]; var setImLoading = _imLoading[1];
  var _imSending = useState(false); var imSending = _imSending[0]; var setImSending = _imSending[1];
  var _imUploading = useState(false); var imUploading = _imUploading[0]; var setImUploading = _imUploading[1];
  var _imError = useState(""); var imError = _imError[0]; var setImError = _imError[1];
  var _conversationConnecting = useState(initialConversationId <= 0 && orderId > 0 && pageRole === "buyer"); var conversationConnecting = _conversationConnecting[0]; var setConversationConnecting = _conversationConnecting[1];
  var _conversationInitError = useState(""); var conversationInitError = _conversationInitError[0]; var setConversationInitError = _conversationInitError[1];
  var _previewImImage = useState(null); var previewImImage = _previewImImage[0]; var setPreviewImImage = _previewImImage[1];
  var imScrollRef = useRef(null);
  var imSocketCleanupRef = useRef(null);
  var imSocketConversationRef = useRef(0);
  var orderMutationInFlightRef = useRef(false);
  var activeOrderIdRef = useRef(orderId);

  function extractImMessages(data) {
    if (Array.isArray(data)) return data;
    if (data && Array.isArray(data.list)) return data.list;
    return [];
  }

  function sortImMessages(list) {
    return list.sort(function(a, b) {
      var aTime = new Date((a && (a.created_at || a.createdAt)) || 0).getTime();
      var bTime = new Date((b && (b.created_at || b.createdAt)) || 0).getTime();
      if (isNaN(aTime)) aTime = 0;
      if (isNaN(bTime)) bTime = 0;
      if (aTime !== bTime) return aTime - bTime;
      var aId = Number(a && a.id);
      var bId = Number(b && b.id);
      if (!isNaN(aId) && !isNaN(bId)) return aId - bId;
      return 0;
    });
  }

  function parseImCardData(value) {
    if (value && typeof value === "object") return value;
    if (!value || typeof value !== "string") return {};
    try { return JSON.parse(value); } catch (err) { return {}; }
  }

  function getLatestImMessageId(list) {
    return (Array.isArray(list) ? list : []).reduce(function(maxId, item) {
      var id = Number(item && item.id);
      return !isNaN(id) && id > maxId ? id : maxId;
    }, 0);
  }

  function mergeUniqueImMessages(existing, incoming) {
    var merged = [];
    var indexById = {};
    function add(item) {
      if (!item || item.id == null) return;
      var key = String(item.id);
      if (indexById[key] !== undefined) {
        merged[indexById[key]] = Object.assign({}, merged[indexById[key]], item);
        return;
      }
      indexById[key] = merged.length;
      merged.push(item);
    }
    (Array.isArray(existing) ? existing : []).forEach(add);
    (Array.isArray(incoming) ? incoming : [incoming]).forEach(add);
    return sortImMessages(merged);
  }

  function appendUniqueImMessages(incoming) {
    setImMessages(function(prev) {
      return mergeUniqueImMessages(prev, incoming);
    });
  }

  function markImRead(lastMessageId) {
    if (!conversationId || !NK.Api || !NK.Api.Im) return;
    var payload = lastMessageId ? { last_read_message_id: lastMessageId } : {};
    NK.Api.Im.markRead(conversationId, payload).catch(function() {});
  }

  function refreshImHistory(targetConversationId) {
    var targetId = Number(targetConversationId || 0);
    if (!targetId || !NK.Api || !NK.Api.Im) return Promise.resolve([]);
    return NK.Api.Im.messages(targetId, { after_id: 0, limit: 100 }).then(function(res) {
      if (!res || res.code !== 0) return [];
      var history = sortImMessages(extractImMessages(res.data).slice());
      appendUniqueImMessages(history);
      var latestMessageId = getLatestImMessageId(history);
      if (latestMessageId) NK.Api.Im.markRead(targetId, { last_read_message_id: latestMessageId }).catch(function() {});
      return history;
    }).catch(function() { return []; });
  }

  function ensureBuyerBoosterConversation(boosterId) {
    if (conversationId > 0) {
      setConversationConnecting(false);
      return Promise.resolve(conversationId);
    }
    if (pageRole !== "buyer" && !orderId) {
      setConversationConnecting(false);
      setConversationInitError("会话参数缺失，请返回后重试");
      return Promise.resolve(0);
    }
    var targetBoosterId = Number(boosterId || 0);
    if (!targetBoosterId || isNaN(targetBoosterId)) {
      setConversationConnecting(false);
      setConversationInitError("订单缺少打手信息，暂时无法连接会话");
      return Promise.resolve(0);
    }
    setConversationConnecting(true);
    setConversationInitError("");
    var conversationRequest = orderId
      ? NK.Api.Im.escortOrderConversation({ order_id: Number(orderId) })
      : NK.Api.Escort.buyerBoosterConversation({ boosterUserId: targetBoosterId });
    return conversationRequest.then(function(res) {
      var nextConversationId = Number(res && res.data && (res.data.conversation_id || res.data.id));
      if (!res || res.code !== 0 || !nextConversationId || isNaN(nextConversationId)) {
        throw new Error((res && res.message) || "会话连接失败");
      }
      setConversationId(nextConversationId);
      return refreshImHistory(nextConversationId).then(function() { return nextConversationId; });
    }).catch(function(err) {
      setConversationInitError((err && err.message) || "会话连接失败，请稍后重试");
      return 0;
    }).finally(function() {
      setConversationConnecting(false);
    });
  }

  useEffect(function() {
    var cancelled = false;
    setImMessages([]);
    setImError("");
    if (!conversationId) {
      setImLoading(false);
      return function() { cancelled = true; };
    }
    if (!NK.Api || !NK.Api.Im) {
      setImLoading(false);
      setImError("聊天服务暂不可用");
      return function() { cancelled = true; };
    }
    setImLoading(true);
    NK.Api.Im.messages(conversationId, { after_id: 0, limit: 100 }).then(function(res) {
      if (cancelled) return;
      if (res && res.code === 0) {
        var history = sortImMessages(extractImMessages(res.data).slice());
        setImMessages(function(prev) { return mergeUniqueImMessages(prev, history); });
        markImRead(getLatestImMessageId(history) || null);
      } else {
        setImError((res && res.message) || "消息加载失败");
      }
    }).catch(function() {
      if (!cancelled) setImError("消息加载失败，请稍后重试");
    }).finally(function() {
      if (!cancelled) setImLoading(false);
    });
    return function() { cancelled = true; };
  }, [conversationId]);

  useEffect(function() {
    if (!conversationId || typeof NK.UserImSocket === "undefined") return;
    var token = (NK.Api && NK.Api.getToken) ? NK.Api.getToken() : "";
    if (!token) return;
    imSocketConversationRef.current = conversationId;
    NK.UserImSocket.connect(token);

    var joinCurrentConversation = function() {
      NK.UserImSocket.joinConversation(conversationId);
    };
    var offNewMessage = NK.UserImSocket.on("im:new_message", function(data) {
      if (!data) return;
      var incoming = data.message || data.data || null;
      if (!incoming || incoming.id == null) return;
      var incomingConversationId = data.conversation_id || incoming.conversation_id || incoming.conversationId;
      if (String(incomingConversationId || "") !== String(conversationId)) return;
      appendUniqueImMessages(incoming);
      markImRead(incoming.id);
    });
    var offConnect = NK.UserImSocket.on("connect", joinCurrentConversation);
    imSocketCleanupRef.current = function() {
      offNewMessage();
      offConnect();
    };
    if (NK.UserImSocket.isConnected()) joinCurrentConversation();

    return function() {
      if (imSocketCleanupRef.current) {
        imSocketCleanupRef.current();
        imSocketCleanupRef.current = null;
      }
      if (imSocketConversationRef.current === conversationId) {
        NK.UserImSocket.leaveConversation(conversationId);
        imSocketConversationRef.current = 0;
      }
    };
  }, [conversationId]);

  useEffect(function() {
    var timer = setTimeout(function() {
      var container = imScrollRef.current;
      if (container) container.scrollTop = container.scrollHeight;
    }, 0);
    return function() { clearTimeout(timer); };
  }, [imMessages]);

  function sendImText() {
    var text = String(imInput || "").trim();
    if (!conversationId || !text || imSending) return;
    setImSending(true);
    NK.Api.Im.sendMessage(conversationId, { msg_type: "text", content: text }).then(function(res) {
      if (res && res.code === 0 && res.data) {
        appendUniqueImMessages(res.data);
        setImInput("");
      } else {
        alert((res && res.message) || "发送失败，请重试");
      }
    }).catch(function() {
      alert("发送失败，请重试");
    }).finally(function() {
      setImSending(false);
    });
  }

  function selectAndSendImImage() {
    if (!conversationId || imUploading) return;
    var inputEl = document.createElement("input");
    inputEl.type = "file";
    inputEl.accept = "image/*";
    inputEl.onchange = function(e) {
      var file = e.target.files && e.target.files[0];
      if (!file) return;
      var formData = new FormData();
      formData.append("image", file);
      setImUploading(true);
      NK.Api.Im.uploadImage(formData).then(function(uploadRes) {
        if (!uploadRes || uploadRes.code !== 0 || !uploadRes.data || !uploadRes.data.url) {
          throw new Error((uploadRes && uploadRes.message) || "图片上传失败");
        }
        return NK.Api.Im.sendMessage(conversationId, { msg_type: "image", image_url: uploadRes.data.url });
      }).then(function(messageRes) {
        if (messageRes && messageRes.code === 0 && messageRes.data) {
          appendUniqueImMessages(messageRes.data);
        } else {
          throw new Error((messageRes && messageRes.message) || "图片发送失败");
        }
      }).catch(function(err) {
        alert((err && err.message) || "图片发送失败，请重试");
      }).finally(function() {
        setImUploading(false);
      });
    };
    inputEl.click();
  }

  function formatImTime(value) {
    if (!value) return "";
    var date = new Date(value);
    if (isNaN(date.getTime())) return "";
    var now = new Date();
    var pad2 = function(number) { return String(number).padStart(2, "0"); };
    var timeText = pad2(date.getHours()) + ":" + pad2(date.getMinutes());
    var sameYear = date.getFullYear() === now.getFullYear();
    var sameDay = sameYear && date.getMonth() === now.getMonth() && date.getDate() === now.getDate();
    if (sameDay) return timeText;
    var monthDay = pad2(date.getMonth() + 1) + "/" + pad2(date.getDate());
    if (sameYear) return monthDay + " " + timeText;
    return date.getFullYear() + "/" + monthDay + " " + timeText;
  }

  function openEscortAftersaleSupport(cardData) {
    var targetOrderId = Number((cardData && cardData.order_id) || activeOrderIdRef.current || orderId || 0);
    if (!targetOrderId || isNaN(targetOrderId)) {
      alert("订单参数无效，请刷新后重试");
      return;
    }
    NK.Store.navigate("supportChat", {
      orderId: targetOrderId,
      source: "escort_order",
      serviceType: "aftersale"
    });
  }

  function applyRealOrderDetail(detail, expectedOrderId, allowActivate) {
    if (!detail) return null;
    var detailId = Number(detail.id || detail.orderId || 0);
    var expectedId = Number(expectedOrderId || detailId || 0);
    var activeId = Number(activeOrderIdRef.current || 0);
    if (!detailId || detailId !== expectedId) return null;
    if (activeId && activeId !== detailId && allowActivate !== true) return null;
    if (activeId !== detailId) {
      activeOrderIdRef.current = detailId;
      setActiveOrderId(detailId);
    }
    setDisplayOrder(detail);
    setCurrentOrder(detail);
    setLatestOrder(detail);
    setConversationData(function(prev) {
      return prev ? Object.assign({}, prev, { currentOrder:detail, latestOrder:detail }) : prev;
    });
    setAllOrders(function(prev) {
      var list = Array.isArray(prev) ? prev.slice() : [];
      var replaced = false;
      list = list.map(function(item) {
        if (Number(item && (item.id || item.orderId)) === detailId) {
          replaced = true;
          return detail;
        }
        return item;
      });
      if (!replaced && detailId) list.push(detail);
      return list;
    });
    try {
      if (detailId) sessionStorage.setItem("escort_order_chat_" + detailId, JSON.stringify(detail));
    } catch (e) {}
    setOrderDetailReady(true);
    return detail;
  }

  async function refreshCurrentOrderDetail(targetOrderId, options) {
    var targetId = Number(targetOrderId || activeOrderIdRef.current || orderId || 0);
    if (!targetId || isNaN(targetId)) throw new Error("订单ID缺失");
    if (!options || options.silent !== true) setOrderDetailReady(false);
    var detailRes = await NK.Api.Escort.chatDetail(targetId);
    if (!detailRes || detailRes.code !== 0 || !detailRes.data) {
      throw new Error((detailRes && (detailRes.message || detailRes.msg)) || "订单状态刷新失败，请重新进入页面");
    }
    return applyRealOrderDetail(detailRes.data, targetId, !!(options && options.activate));
  }

  // (forced loading exit removed - loading is now properly managed via setLoading)

    // Poll order status: immediate first fetch + 4s interval + visibility refresh
  React.useEffect(function () {
    if (!activeOrderId) return;
    var stopped = false;
    var polledOrderId = Number(activeOrderId);

    var refreshOrderStatus = async function () {
      try {
        var res = await NK.Api.Escort.getOrderStatus(polledOrderId);
        if (stopped) return;
        if (Number(activeOrderIdRef.current || 0) !== polledOrderId) return;
        if (!res || res.code !== 0) return;
        var data = res.data;
        if (!data) return;

        setDisplayOrder(function(prev) {
          if (!prev) return prev;
          if (Number(prev.id || prev.orderId || 0) !== polledOrderId) return prev;
          var updated = Object.assign({}, prev);
          var needsUpdate = false;
          if (data.boosterUserId !== undefined && data.boosterUserId !== prev.boosterUserId && data.boosterUserId !== prev.booster_user_id) {
            updated.boosterUserId = data.boosterUserId;
            needsUpdate = true;
          }
          if (data.status !== undefined && data.status !== prev.status) {
            updated.status = data.status;
            needsUpdate = true;
          }
          if (data.boosterCompleted !== undefined && data.boosterCompleted !== (prev.boosterCompleted || prev.booster_completed)) {
            updated.boosterCompleted = data.boosterCompleted;
            needsUpdate = true;
          }
          if (data.boosterCompleteImages !== undefined && data.boosterCompleteImages !== prev.boosterCompleteImages) {
            updated.boosterCompleteImages = data.boosterCompleteImages;
            try { updated.boosterCompleteImage = JSON.parse(data.boosterCompleteImages || "[]")[0] || ""; } catch(e) {}
            needsUpdate = true;
          }
          if (needsUpdate) {
            try {
              var key = "escort_order_chat_" + polledOrderId;
              sessionStorage.setItem(key, JSON.stringify(updated));
            } catch(e) {}
            return updated;
          }
          return prev;
        });
      } catch(e) {
        // Silently ignore polling errors
      }
    };

    // Fire immediately on mount - don't wait 4 seconds
    refreshOrderStatus();

    // Then poll every 4 seconds
    var intervalId = setInterval(refreshOrderStatus, 4000);

    // Refresh when page becomes visible again
    var onVisible = function () {
      if (document.visibilityState === "visible") {
        refreshOrderStatus();
      }
    };
    document.addEventListener("visibilitychange", onVisible);

    return function () {
      stopped = true;
      clearInterval(intervalId);
      document.removeEventListener("visibilitychange", onVisible);
    };
  }, [activeOrderId]);

  // Load conversation detail on mount
  React.useEffect(function () {
    if (noOrderMode) {
      setLoading(false);
      setConvLoading(false);
      setErrorMsg("");
      setOrderDetailReady(true);
      return;
    }
    var isConvMode = pageParams.conversationMode === true;
    var buyerId = pageParams.buyerUserId;
    var boosterId = pageParams.boosterUserId;
    var role = pageRole;
    
    if (!isConvMode && !orderId) { setLoading(false); setConvLoading(false); return; }
    
    var loadConv = async function () {
      try {
        if (isConvMode && buyerId && boosterId && !orderId) {
          // Direct conversation load
          var res = await NK.Api.Escort.conversationDetail({ role: role, buyerUserId: buyerId, boosterUserId: boosterId });
          if (res && res.code === 0 && res.data) {
            setAllOrders(res.data.orders || []);
            if (res.data.currentOrder) {
              var appliedConversationOrder = applyRealOrderDetail(res.data.currentOrder);
              if (appliedConversationOrder) {
                setConversationData(Object.assign({}, res.data, { currentOrder:appliedConversationOrder, latestOrder:appliedConversationOrder }));
              }
            } else {
              setConversationData(res.data);
            }
            setErrorMsg("");
          }
          if (role === "buyer" && !conversationId) {
            await ensureBuyerBoosterConversation(boosterId);
          }
        } else if (orderId) {
          // Always resolve the exact requested order before rendering transaction actions.
          var detail = await refreshCurrentOrderDetail(orderId, { silent:true });
          if (detail) {
            var bid = detail.buyerUserId || detail.buyer_user_id;
            var boid = detail.boosterUserId || detail.booster_user_id;
            if (!conversationId) {
              await ensureBuyerBoosterConversation(boid);
            }
            if (bid && boid) {
              var convRes = await NK.Api.Escort.conversationDetail({ role: role, buyerUserId: bid, boosterUserId: boid });
              if (convRes && convRes.code === 0 && convRes.data && Number(activeOrderIdRef.current || 0) === Number(detail.id || detail.orderId || 0)) {
                setConversationData(Object.assign({}, convRes.data, { currentOrder:detail, latestOrder:detail }));
                setAllOrders((convRes.data.orders || []).map(function(item) {
                  return Number(item && (item.id || item.orderId)) === orderId ? detail : item;
                }));
              }
              setErrorMsg("");
            } else {
              setErrorMsg("");
            }
          }
        }
        if (conversationId > 0) await refreshImHistory(conversationId);
      } catch(e) {
        console.error("[EscortOrderChat] conversation load failed:", e);
        setErrorMsg("订单数据加载失败，请返回后重试");
        if (!conversationId) {
          setConversationConnecting(false);
          setConversationInitError("会话连接失败，请返回后重试");
        }
      }
      setLoading(false);
      setConvLoading(false);
    };
    loadConv();
  }, []);

  function h(tag, attrs) {
    var children = [];
    for (var i = 2; i < arguments.length; i++) { if (arguments[i] != null) children.push(arguments[i]); }
    attrs = attrs || {};
    if (attrs.className) { attrs.class = attrs.className; delete attrs.className; }
    return React.createElement.apply(React, [tag, attrs].concat(children));
  }


  async function handleStart() {
    var targetOrderId = Number(activeOrderIdRef.current || orderId || 0);
    if (starting || orderMutationInFlightRef.current || !targetOrderId) return;
    orderMutationInFlightRef.current = true;
    setStarting(true);
    try {
      var res = await NK.Api.Escort.startOrder(targetOrderId);
      console.log("[start] result:", res);
      if (!res || res.code !== 0) throw new Error((res && (res.message || res.msg)) || "\u5F00\u59CB\u8BA2\u5355\u5931\u8D25");
      await refreshCurrentOrderDetail(targetOrderId);
      await refreshImHistory(conversationId);
      alert("\u8BA2\u5355\u5DF2\u5F00\u59CB");
    } catch(err) {
      console.error("[start] failed:", err);
      alert(err.message || "\u5F00\u59CB\u8BA2\u5355\u5931\u8D25");
    } finally {
      setStarting(false);
      orderMutationInFlightRef.current = false;
    }
  }
  // Booster: open upload modal (do NOT open file picker immediately)
  function handleBoosterComplete() {
    setShowBoosterModal(true);
  }


  // Open file picker for booster screenshot upload
  function triggerFilePicker() {
    var inp = document.createElement("input");
    inp.type = "file";
    inp.accept = "image/*";
    inp.multiple = true;
    inp.onchange = function(e) {
      var files = e.target.files;
      if (files && files.length > 0) {
        var newFiles = [];
        for (var i = 0; i < files.length && (selectedFiles.length + newFiles.length) < 5; i++) {
          newFiles.push(files[i]);
        }
        if (selectedFiles.length + newFiles.length >= 5) {
          alert("最多上传5张图片");
        }
        setSelectedFiles(selectedFiles.concat(newFiles).slice(0, 5));
      }
    };
    inp.click();
  }
  // Booster: upload and submit (multi-image)
  async function handleUploadAndSubmit() {
    if (!selectedFiles || selectedFiles.length === 0) { alert("请先上传订单完成截图"); return; }
    if (uploading || orderMutationInFlightRef.current) return;
    var targetOrderId = Number(activeOrderIdRef.current || orderId || 0);
    if (!targetOrderId || isNaN(targetOrderId)) return;
    orderMutationInFlightRef.current = true;
    setUploading(true);
    try {
      var imageUrls = [];
      for (var fi = 0; fi < selectedFiles.length; fi++) {
        var uploadRes = await NK.Api.Upload.image(selectedFiles[fi]);
        if (!uploadRes || uploadRes.code !== 0 || !uploadRes.data) throw new Error("图片上传失败，请重试");
        var url = uploadRes.data.url || uploadRes.data.path || uploadRes.data;
        if (typeof url !== "string") url = JSON.stringify(url);
        imageUrls.push(url);
      }
      var res = await NK.Api.Escort.boosterCompleteOrder(targetOrderId, { screenshotUrls: imageUrls });
      if (!res || res.code !== 0) throw new Error((res && (res.message || res.msg)) || "提交失败");
      await refreshCurrentOrderDetail(targetOrderId);
      await refreshImHistory(conversationId);
      setShowBoosterModal(false);
      setSelectedFiles([]);
      alert("服务截图已提交");
    } catch(err) {
      console.error("[booster-complete] failed:", err);
      alert(err.message || "提交失败");
    } finally {
      setUploading(false);
      orderMutationInFlightRef.current = false;
    }
  }

  // Buyer: open review modal (or show "in service")
  function handleBuyerComplete() {
    var boosterDone = displayOrder && (displayOrder.boosterCompleted || displayOrder.booster_completed || displayOrder.boosterCompleteImage || displayOrder.boosterCompleteImages);
    if (!boosterDone) {
      alert("打手尚未提交服务截图");
      return;
    }
    setShowReviewModal(true);
  }

  // Buyer: submit review and complete order
  async function doCompleteOrder() {
    if (completing || orderMutationInFlightRef.current) return;
    var targetOrderId = Number(activeOrderIdRef.current || orderId || 0);
    if (!targetOrderId || isNaN(targetOrderId)) return;
    orderMutationInFlightRef.current = true;
    setCompleting(true);
    try {
      // Upload review images if any
      var uploadedUrls = [];
      for (var ri = 0; ri < reviewImages.length; ri++) {
        var uploadRes = await NK.Api.Upload.image(reviewImages[ri]);
        if (uploadRes && uploadRes.code === 0 && uploadRes.data) {
          var url = uploadRes.data.url || uploadRes.data.path || uploadRes.data;
          if (typeof url === "string") uploadedUrls.push(url);
        }
      }
            console.log("[EscortOrderChatPage] review submit", { reviewRating: reviewRating, reviewText: reviewText });
      var res = await NK.Api.Escort.completeOrder(targetOrderId, {
        rating: reviewRating,
        reviewText: reviewText,
        reviewImages: uploadedUrls
      });
      if (!res || res.code !== 0) throw new Error((res && (res.message || res.msg)) || "完成订单失败");
      await refreshCurrentOrderDetail(targetOrderId);
      await refreshImHistory(conversationId);
      setShowReviewModal(false);
      alert("订单已完成，感谢评价");
    } catch(err) {
      console.error("[complete] failed:", err);
      alert(err.message || "完成订单失败");
    } finally {
      setCompleting(false);
      orderMutationInFlightRef.current = false;
    }
  }
  function goBack() {
    if (NK.Store && NK.Store.back) { NK.Store.back(); } else { window.history.back(); }
  }

  function fmtPrice(v) {
    var n = parseFloat(v);
    if (isNaN(n)) return "\u00A50.00";
    return "\u00A5" + n.toFixed(2);
  }

  var S = {
    bg: "#EDEDED", primary: "#1677ff", primaryLight: "#e6f4ff",
    green: "#16a34a", greenBg: "#f0fdf4", textPrimary: "#1F2937",
    textSecondary: "#6B7280", textMuted: "#9CA3AF", border: "#E5E7EB"
  };

// === Loading ===
  if (loading && !noOrderMode) {
    return h("div", { style: { display:"flex", flexDirection:"column", alignItems:"center", justifyContent:"center", height:"100vh", background:S.bg } },
      h("div", { style: { textAlign:"center" } },
        h("div", { style: { width:32, height:32, borderRadius:"50%", border:"3px solid #E5E7EB", borderTopColor:S.primary, animation:"spin 0.8s linear infinite", margin:"0 auto 12px" } }),
        h("div", { style: { color:S.textSecondary, fontSize:14, marginBottom:8 } }, "\u52A0\u8F7D\u4E2D..."),
        h("div", { style: { fontSize:11, color:S.textMuted } }, "orderId: " + (orderId || "N/A"))
      )
    );
  }

  // === Error ===
  if (errorMsg && !noOrderMode) {
    return h("div", { style: { display:"flex", flexDirection:"column", alignItems:"center", justifyContent:"center", height:"100vh", background:S.bg } },
      h("div", { style: { background:"#fff", borderRadius:12, padding:24, boxShadow:"0 2px 8px rgba(0,0,0,0.08)", maxWidth:300, textAlign:"center" } },
        h("div", { style: { fontSize:32, marginBottom:8 } }, "\u26A0\uFE0F"),
        h("div", { style: { color:S.textPrimary, fontSize:15, marginBottom:4 } }, errorMsg),
        h("div", { style: { fontSize:11, color:S.textMuted, marginBottom:16 } }, "orderId: " + (orderId || "N/A")),
        h("button", { onClick: goBack, style: { padding:"8px 24px", borderRadius:8, border:"none", background:S.primary, color:"#fff", fontSize:14, cursor:"pointer" } }, "\u8FD4\u56DE")
      )
    );
  }

  // === No order data ===
  if (!displayOrder && !noOrderMode) {
    return h("div", { style: { display:"flex", flexDirection:"column", alignItems:"center", justifyContent:"center", height:"100vh", background:S.bg } },
      h("div", { style: { textAlign:"center", padding:24 } },
        h("div", { style: { color:S.textPrimary, fontSize:15, marginBottom:16 } }, "\u8BA2\u5355\u6570\u636E\u52A0\u8F7D\u5931\u8D25\uFF0C\u8BF7\u8FD4\u56DE\u540E\u91CD\u8BD5"),
        h("button", { onClick: goBack, style: { padding:"8px 24px", borderRadius:8, border:"none", background:S.primary, color:"#fff", fontSize:14, cursor:"pointer" } }, "\u8FD4\u56DE")
      )
    );
  }

  // === Main shell page ===
  var o = displayOrder || {};
  var role = pageRole || o.role || "buyer";
  isBoosterView = role === "booster";
  msgJustify = isBoosterView ? "flex-end" : "flex-start";
  msgBorderRadius = isBoosterView ? "12px 4px 12px 12px" : "4px 12px 12px 12px";
  var status = Number(o.status) || 0;
  var isDesignatedOrder = (o.assignMode === "specified" || o.assign_mode === "specified") && (displayOrder.boosterUserId || displayOrder.booster_user_id);

  // Status text: always use local mapping, ignore snapshot.statusText to avoid encoding issues
  var STATUS_MAP = {
    20: "\u652F\u4ED8\u6210\u529F\uFF0C\u7B49\u5F85\u6253\u624B\u63A5\u5355",
    30: "\u7B49\u5F85\u4E70\u5BB6\u5F00\u59CB\u8BA2\u5355",
    40: "\u8BA2\u5355\u5DF2\u5F00\u59CB",
    60: "\u7B49\u5F85\u4E70\u5BB6\u786E\u8BA4",
    70: "\u4EA4\u6613\u5B8C\u6210",
    120: "\u8BA2\u5355\u5DF2\u53D6\u6D88"
  };
  var statusText = STATUS_MAP[status] || ("\u72B6\u6001" + status);

  var serviceName = o.serviceName || o.serviceTitle || o.title || "\u62A4\u822A\u670D\u52A1";
  var cover = o.cover || o.coverImage || "";
  var price = Number(o.price || o.amount || 0);
  var specName = o.specName || "";
  var serverName = o.serverName || o.gameServer || "";
  var boosterName = o.boosterName || "\u63A5\u5355\u6253\u624B";
  var boosterUserId = o.boosterUserId || o.booster_user_id || o.boosterId || pageParams.boosterUserId || null;
  var boosterAvatar = o.boosterAvatar || o.booster_avatar || o.boosterHeadImg || o.booster_head_img || o.boosterUserAvatar || o.avatar || "";
  var buyerName = o.buyerName || (o.buyerUserId ? "\u7528\u6237" + o.buyerUserId : "\u4E70\u5BB6");
  var buyerAvatar = o.buyerAvatar || o.buyer_avatar || "";
  var remark = o.remark || "";
  var accountId = o.accountId || "";
  var specId = o.specId || o.spec_id || null;
  var svcId = o.serviceId || o.service_id || null;
  var bizType = o.bizType || o.businessType || o.gameType || "naikuai";
  var gameLabel = (bizType === "naikuai" || bizType === "\u5976\u5757") ? "\u5976\u5757" : (bizType === "delta" || bizType === "\u4E09\u89D2\u6D32") ? "\u4E09\u89D2\u6D32" : "\u5976\u5757";

  // Open booster public profile (buyer only)
  function openBoosterPublicProfile() {
    if (role !== "buyer") return;
    var buid = boosterUserId;
    if (!buid) { alert("\u6253\u624B\u4FE1\u606F\u7F3A\u5931\uFF0C\u6682\u65F6\u65E0\u6CD5\u67E5\u770B\u4E3B\u9875"); return; }
    NK.Store.navigate("boosterPublicProfile", { boosterUserId: buid });
  }

  // Default avatar: colored circle with first character of name
  function renderAvatar(name, size, onClick, avatarUrl) {
    size = size || 36;
    var hasAvatar = avatarUrl && String(avatarUrl).trim();
    if (hasAvatar) {
      return h("div", {
        onClick: onClick || undefined,
        style: {
          width: size, height: size, borderRadius: "50%", overflow: "hidden",
          flexShrink: 0, background: "#F3F4F6",
          cursor: typeof onClick === "function" ? "pointer" : "default"
        }
      }, h("img", {
        src: avatarUrl,
        style: { width: "100%", height: "100%", objectFit: "cover", display: "block" },
        onError: function(e) { e.currentTarget.style.display = "none"; }
      }));
    }
    var colors = ["#1677ff", "#16a34a", "#f59e0b", "#ef4444", "#8b5cf6", "#ec4899"];
    var idx = 0;
    if (name) {
      var sum = 0;
      for (var ci = 0; ci < name.length; ci++) sum += name.charCodeAt(ci);
      idx = sum % colors.length;
    }
    var initial = (name && name.length > 0) ? name.charAt(0) : "?";
    var hasClick = typeof onClick === "function";
    var avatarStyle = {
      width: size, height: size, borderRadius: "50%", background: colors[idx],
      display: "flex", alignItems: "center", justifyContent: "center",
      color: "#fff", fontSize: Math.floor(size * 0.45), fontWeight: 700,
      flexShrink: 0, userSelect: "none",
      cursor: hasClick ? "pointer" : "default"
    };
    return h("div", { onClick: onClick || undefined, style: avatarStyle }, initial);
  }

  // === Designated order card handlers ===
  async function handleAcceptOrder(targetOrderId) {
    if (orderActionSubmitting || orderMutationInFlightRef.current) return;
    if (!confirm("确认接单？")) return;
    orderMutationInFlightRef.current = true;
    setOrderActionSubmitting("accept");
    var previousActiveOrderId = Number(activeOrderIdRef.current || orderId || 0);
    var acceptCommitted = false;
    try {
      var acceptedOrderId = Number(targetOrderId || (displayOrder && (displayOrder.id || displayOrder.orderId)) || activeOrderIdRef.current || orderId);
      if (!acceptedOrderId || isNaN(acceptedOrderId)) { alert("订单ID缺失"); return; }
      activeOrderIdRef.current = acceptedOrderId;
      setActiveOrderId(acceptedOrderId);
      setOrderDetailReady(false);
      var res = await NK.Api.Escort.acceptOrder(acceptedOrderId);
      if (!res || res.code !== 0) throw new Error((res && res.message) || "接单失败");
      acceptCommitted = true;
      var acceptedOrder = await refreshCurrentOrderDetail(acceptedOrderId);
      if (!acceptedOrder || Number(acceptedOrder.id || acceptedOrder.orderId || 0) !== acceptedOrderId) {
        throw new Error("接单状态同步失败，请刷新后重试");
      }
      await refreshImHistory(conversationId);
      alert("接单成功");
    } catch(e) {
      if (!acceptCommitted) {
        activeOrderIdRef.current = previousActiveOrderId;
        setActiveOrderId(previousActiveOrderId);
        setOrderDetailReady(true);
      }
      console.error("[EscortOrderChat] accept failed", e);
      alert((e && e.message) || "接单失败，请重试");
    } finally {
      setOrderActionSubmitting("");
      orderMutationInFlightRef.current = false;
    }
  }

  function findTimelineOrder(targetOrderId) {
    var targetId = Number(targetOrderId || 0);
    if (!targetId || isNaN(targetId)) return null;
    var candidates = [displayOrder, currentOrder].concat(Array.isArray(allOrders) ? allOrders : []);
    for (var oi = 0; oi < candidates.length; oi++) {
      var item = candidates[oi];
      if (item && Number(item.id || item.orderId) === targetId) return item;
    }
    return null;
  }

  return h("div", { style: { display:"flex", flexDirection:"column", height:"100dvh", maxHeight:"100dvh", overflow:"hidden", background:S.bg, fontFamily:"-apple-system,BlinkMacSystemFont,Segoe UI,sans-serif" } },

    // === Header ===
    h("div", { style: { display:"flex", alignItems:"center", padding:"10px 16px", background:"#fff", borderBottom:"1px solid "+S.border, flexShrink:0 } },
      h("button", { onClick: goBack, style: { border:"none", background:"none", fontSize:20, padding:"4px 8px", cursor:"pointer", color:S.textPrimary, marginRight:4, lineHeight:1 } }, "\u2190"),
      h("div", { style: { flex:1, fontSize:17, fontWeight:600, color:S.textPrimary, overflow:"hidden", textOverflow:"ellipsis", whiteSpace:"nowrap", textAlign:"center", marginRight:36 } }, noOrderMode ? (pageParams.targetName || pageParams.boosterName || "私聊") : "\u62A4\u822A\u8BA2\u5355")
    ),

    // === Order card ===
    !noOrderMode ? h("div", { style: { padding:"12px 16px", background:"#fff", borderBottom:"1px solid "+S.border, flexShrink:0 } },
      h("div", { style: { display:"flex", alignItems:"center" } },
        // Service image with fallback placeholder
        cover
          ? h("img", { src: cover, style: { width:52, height:52, borderRadius:8, objectFit:"cover", marginRight:12, flexShrink:0, background:"#F3F4F6" }, onError: function(e) { e.target.style.display = "none"; } })
          : h("div", { style: { width:52, height:52, borderRadius:8, marginRight:12, flexShrink:0, background:"#F3F4F6", display:"flex", alignItems:"center", justifyContent:"center", color:"#9CA3AF", fontSize:22 } }, "\uD83D\uDEE1\uFE0F"),
        h("div", { style: { flex:1, minWidth:0 } },
          h("div", { style: { fontSize:14, fontWeight:600, color:S.textPrimary, marginBottom:3, overflow:"hidden", textOverflow:"ellipsis", whiteSpace:"nowrap" } }, serviceName),
          specName ? h("div", { style: { fontSize:12, color:S.textSecondary, marginBottom:3 } }, "\u89C4\u683C\uFF1A" + specName) : null,
          h("div", { style: { fontSize:12, color:S.textSecondary } }, h("span", { style: { color:"#EF4444", fontWeight:600 } }, fmtPrice(price))),
          serverName ? h("div", { style: { fontSize:11, color:S.textMuted, marginTop:2 } }, "\u533A\u670D\uFF1A" + serverName) : null
        )
      ),
      h("div", { style: { marginTop:10, display:"flex", alignItems:"center", justifyContent:"space-between" } },
        h("span", { style: { fontSize:11, padding:"2px 10px", borderRadius:4, background:S.greenBg, color:S.green, fontWeight:500 } }, orderDetailReady ? statusText : "\u6B63\u5728\u540C\u6B65\u8BA2\u5355\u72B6\u6001"),
        // Action button per status - NO booster name line above button
        orderDetailReady && status === 30 && role === "buyer" ? h("button", { onClick: handleStart, disabled: starting, style: { padding:"6px 16px", borderRadius:8, border:"none", background:S.primary, color:"#fff", fontSize:12, fontWeight:600, cursor:"pointer" } }, (starting ? "\u5F00\u59CB\u4E2D..." : "\u5F00\u59CB\u8BA2\u5355")) : orderDetailReady && status === 30 && role === "booster" ? h("span", { style: { fontSize:12, color:S.textMuted } }, "\u7B49\u5F85\u4E70\u5BB6\u5F00\u59CB\u8BA2\u5355") : null,
        orderDetailReady && status === 40 && role === "buyer" ? ((displayOrder.boosterCompleted || displayOrder.booster_completed || displayOrder.boosterCompleteImage || displayOrder.boosterCompleteImages) ? h("button", { onClick: handleBuyerComplete, style: { padding:"6px 16px", borderRadius:8, border:"none", background:S.green, color:"#fff", fontSize:12, fontWeight:600, cursor:"pointer" } }, "\u8BA2\u5355\u5B8C\u6210") : h("span", { style: { fontSize:12, color:S.textMuted, padding:"6px 16px", borderRadius:8, background:"#F3F4F6" } }, "\u670D\u52A1\u4E2D")) :
              orderDetailReady && status === 40 && role === "booster" ? ((displayOrder.boosterCompleted || displayOrder.booster_completed || displayOrder.boosterCompleteImage || displayOrder.boosterCompleteImages) ? h("span", { style: { fontSize:12, color:S.textMuted, padding:"6px 16px", borderRadius:8, background:"#F3F4F6" } }, "\u5DF2\u63D0\u4EA4\u670D\u52A1\u622A\u56FE") : h("button", { onClick: handleBoosterComplete, style: { padding:"6px 16px", borderRadius:8, border:"none", background:S.green, color:"#fff", fontSize:12, fontWeight:600, cursor:"pointer" } }, "\u670D\u52A1\u5B8C\u6210")) : null,
        orderDetailReady && status === 60 && role === "buyer" ? h("button", { onClick: handleBuyerComplete, style: { padding:"6px 16px", borderRadius:8, border:"none", background:S.green, color:"#fff", fontSize:12, fontWeight:600, cursor:"pointer" } }, "\u8BA2\u5355\u5B8C\u6210") : null,
        orderDetailReady && status === 60 && role === "booster" ? h("span", { style: { fontSize:12, color:S.textMuted } }, "\u7B49\u5F85\u4E70\u5BB6\u786E\u8BA4\u5B8C\u6210") : null
      )
    ) : null,


    // === Chat area ===
    h("div", { ref: imScrollRef, style: { flex:1, minHeight:0, overflowY:"auto", WebkitOverflowScrolling:"touch", overscrollBehavior:"contain", padding:"12px 14px", display:"flex", flexDirection:"column", gap:14 } },
      conversationConnecting ? h("div", { style: { textAlign:"center", fontSize:12, color:S.textSecondary, padding:"8px 12px", background:"#F8FAFC", borderRadius:8 } }, "正在连接会话...") : null,
      conversationInitError ? h("div", { style: { textAlign:"center", fontSize:12, color:"#EF4444", padding:"8px 12px", background:"#FEF2F2", borderRadius:8 } }, conversationInitError) : null,
      imError ? h("div", { style: { textAlign:"center", fontSize:12, color:"#EF4444", padding:"8px 12px", background:"#FEF2F2", borderRadius:8 } }, imError) : null,
      imLoading ? h("div", { style: { textAlign:"center", fontSize:13, color:S.textMuted, padding:"20px 0" } }, "消息加载中...") : null,
      !imLoading && imMessages.length === 0 ? h("div", { style: { textAlign:"center", fontSize:13, color:S.textMuted, padding:"24px 0" } }, noOrderMode ? "暂无消息，可以开始聊天" : "暂无聊天消息") : null,
      imMessages.map(function(msg) {
        var senderRole = msg.sender_role || msg.senderRole || "";
        var isMine = String(senderRole) === String(role);
        var isSystemMessage = senderRole === "system" || msg.msg_type === "system";
        var createdAt = msg.created_at || msg.createdAt;
        var cardData = parseImCardData(msg.card_data || msg.cardData);
        var isCompletionCertificate = msg.msg_type === "order_card" && cardData.card_type === "escort_completion_certificate";
        var isAcceptedOrderCard = msg.msg_type === "order_card" && cardData.card_type === "escort_order_detail";
        var isPendingAcceptCard = msg.msg_type === "order_card" && cardData.card_type === "escort_pending_accept";
        if (isSystemMessage) {
          var isOrderStart = cardData.event_type === "escort_order_started" && cardData.order_id;
          var isSupportEntry = cardData.event_type === "escort_support_tip" || msg.content === "如有问题可前往联系客服";
          return h(React.Fragment, { key: "im-" + msg.id },
            isOrderStart ? h("div", { style: { display:"flex", alignItems:"center", gap:10, margin:"6px 0 2px" } },
              h("span", { style: { flex:1, height:1, background:S.border } }),
              h("span", { style: { color:S.textMuted, fontSize:10, whiteSpace:"nowrap" } }, "订单 #" + cardData.order_id),
              h("span", { style: { flex:1, height:1, background:S.border } })
            ) : null,
            h("div", { style: { textAlign:"center", margin:"4px 0" } },
              isSupportEntry ? h("button", {
                type:"button",
                onClick:function() { openEscortAftersaleSupport(cardData); },
                onMouseDown:function(e) { e.currentTarget.style.opacity = "0.55"; },
                onMouseUp:function(e) { e.currentTarget.style.opacity = "1"; },
                onMouseLeave:function(e) { e.currentTarget.style.opacity = "1"; },
                onTouchStart:function(e) { e.currentTarget.style.opacity = "0.55"; },
                onTouchEnd:function(e) { e.currentTarget.style.opacity = "1"; },
                style: { border:"none", background:"transparent", padding:"5px 10px", color:S.primary, fontSize:12, lineHeight:1.4, cursor:"pointer", transition:"opacity 120ms ease" }
              }, "如有问题，可前往联系客服") :
              h("span", { style: { display:"inline-block", padding:"3px 10px", borderRadius:8, background:"#E1E1E1", color:S.textMuted, fontSize:11 } }, msg.content || "")
            )
          );
        }
        var senderName = msg.sender_nickname || msg.senderNickname || (senderRole === "booster" ? boosterName : buyerName);
        var senderAvatar = msg.sender_avatar || msg.senderAvatar || (senderRole === "booster" ? boosterAvatar : buyerAvatar);
        var avatarClick = role === "buyer" && senderRole === "booster" ? openBoosterPublicProfile : undefined;
        function renderImMessageRow(contentNode) {
          var avatarNode = renderAvatar(senderName, 34, avatarClick, senderAvatar);
          var contentColumn = h("div", { style: { maxWidth:"78%", minWidth:0, display:"flex", flexDirection:"column", alignItems:isMine ? "flex-end" : "flex-start" } },
            contentNode,
            h("span", { style: { marginTop:3, color:S.textMuted, fontSize:10 } }, formatImTime(createdAt))
          );
          return h("div", { key:"im-" + msg.id, style: { width:"100%", display:"flex", justifyContent:isMine ? "flex-end" : "flex-start", alignItems:"flex-start", gap:8 } },
            isMine ? contentColumn : avatarNode,
            isMine ? avatarNode : contentColumn
          );
        }
        if (isPendingAcceptCard) {
          var pendingOrderId = Number(cardData.order_id || 0);
          var pendingOrder = findTimelineOrder(pendingOrderId) || {};
          var pendingStatus = Number(pendingOrder.status !== undefined ? pendingOrder.status : cardData.status) || 20;
          if (pendingStatus === 20) {
            var hasAcceptedEvent = imMessages.some(function(timelineMessage) {
              var timelineCardData = parseImCardData(timelineMessage && (timelineMessage.card_data || timelineMessage.cardData));
              return Number(timelineCardData.order_id || 0) === pendingOrderId && timelineCardData.event_type === "escort_order_accepted_card";
            });
            if (hasAcceptedEvent) pendingStatus = 30;
          }
          var pendingServiceTitle = pendingOrder.serviceTitle || pendingOrder.serviceName || cardData.service_title || "\u62A4\u822A\u670D\u52A1";
          var pendingCover = pendingOrder.coverImage || pendingOrder.cover || cardData.cover_image || "";
          var pendingSpec = pendingOrder.specName || cardData.spec_name || "\u5168\u533A\u670D";
          var pendingServer = pendingOrder.gameServer || pendingOrder.serverName || cardData.game_server || "\u672A\u586B\u5199\u670D\u52A1\u5668";
          var pendingAmount = pendingOrder.amount !== undefined ? pendingOrder.amount : cardData.amount;
          var pendingAssignmentMode = String(pendingOrder.assignMode || pendingOrder.assign_mode || cardData.assign_mode || "").toLowerCase();
          var pendingStatusText = pendingStatus === 20 ? "\u7B49\u5F85\u6253\u624B\u63A5\u5355" : pendingStatus === 30 ? "\u6253\u624B\u5DF2\u63A5\u5355" : pendingStatus === 40 ? "\u8BA2\u5355\u5DF2\u5F00\u59CB" : pendingStatus === 60 ? "\u7B49\u5F85\u4E70\u5BB6\u786E\u8BA4" : pendingStatus === 70 ? "\u8BA2\u5355\u5DF2\u5B8C\u6210" : pendingStatus === 120 ? "\u8BA2\u5355\u5DF2\u53D6\u6D88" : ("\u72B6\u6001" + pendingStatus);
          return renderImMessageRow(
            h("div", { style: { width:"min(100%, 320px)", boxSizing:"border-box", padding:"12px 14px", borderRadius:isMine ? "12px 4px 12px 12px" : "4px 12px 12px 12px", background:"#fff", border:"1px solid "+S.border, boxShadow:"0 1px 2px rgba(0,0,0,0.05)", color:S.textPrimary } },
              h("div", { style: { display:"flex", alignItems:"center", justifyContent:"space-between", gap:10, marginBottom:10 } },
                h("div", { style: { fontSize:14, fontWeight:700 } }, pendingStatusText),
                h("span", { style: { flexShrink:0, padding:"2px 7px", borderRadius:4, background:pendingStatus === 20 ? S.primaryLight : "#F3F4F6", color:pendingStatus === 20 ? S.primary : S.textSecondary, fontSize:10, fontWeight:600 } }, "#" + (cardData.order_no || pendingOrder.orderNo || pendingOrderId))
              ),
              h("div", { style: { display:"flex", gap:10, padding:"10px", background:"#F8FAFC", borderRadius:8, marginBottom:pendingStatus === 20 ? 10 : 0 } },
                pendingCover ? h("img", { src:pendingCover, style: { width:48, height:48, borderRadius:6, objectFit:"cover", flexShrink:0 } }) : null,
                h("div", { style: { flex:1, minWidth:0 } },
                  h("div", { style: { fontSize:12, fontWeight:600, marginBottom:3, overflow:"hidden", textOverflow:"ellipsis", whiteSpace:"nowrap" } }, pendingServiceTitle),
                  h("div", { style: { fontSize:11, color:S.textSecondary, marginBottom:2 } }, pendingSpec + " · " + fmtPrice(pendingAmount)),
                  h("div", { style: { fontSize:11, color:S.textMuted, overflow:"hidden", textOverflow:"ellipsis", whiteSpace:"nowrap" } }, pendingServer)
                )
              ),
              orderDetailReady && pendingStatus === 20 ? h("div", { style: { display:"flex", gap:8 } },
                role === "buyer" ? h("button", { onClick:function() { openEscortAftersaleSupport({ order_id:pendingOrderId }); }, disabled:!!orderActionSubmitting, style: { flex:1, height:34, borderRadius:6, border:"1px solid "+S.border, background:"#fff", color:S.primary, fontSize:12, fontWeight:600, cursor:orderActionSubmitting ? "not-allowed" : "pointer", opacity:orderActionSubmitting ? 0.6 : 1 } }, "\u8054\u7CFB\u5BA2\u670D") : null,
                role === "booster" ? h("button", { onClick:function() { handleAcceptOrder(pendingOrderId); }, disabled:!!orderActionSubmitting, style: { flex:1, height:34, borderRadius:6, border:"none", background:S.primary, color:"#fff", fontSize:12, fontWeight:600, cursor:orderActionSubmitting ? "not-allowed" : "pointer", opacity:orderActionSubmitting ? 0.6 : 1 } }, orderActionSubmitting === "accept" ? "\u63A5\u5355\u4E2D..." : "\u540C\u610F\u63A5\u5355") : null
              ) : null
            )
          );
        }
        if (isAcceptedOrderCard) {
          return renderImMessageRow(
            h("div", { style: { width:"min(100%, 320px)", boxSizing:"border-box", padding:"12px 14px", borderRadius:isMine ? "12px 4px 12px 12px" : "4px 12px 12px 12px", background:"#fff", border:"1px solid "+S.border, boxShadow:"0 1px 2px rgba(0,0,0,0.05)", color:S.textPrimary, fontSize:12, lineHeight:1.75 } },
              h("div", { style: { fontSize:14, fontWeight:700, marginBottom:6 } }, "\u672C\u6B21\u8BA2\u5355\u8BE6\u60C5"),
              h("div", null, "\u3010" + (cardData.game_label || gameLabel) + "\u3011"),
              h("div", null, "\u670D\u52A1\u540D\u79F0\uFF1A" + (cardData.service_title || serviceName)),
              cardData.account_id ? h("div", null, "\u8D26\u53F7ID\uFF1A" + cardData.account_id) : null,
              cardData.game_server ? h("div", null, "\u670D\u52A1\u5668\uFF1A" + cardData.game_server) : null,
              h("div", null, "\u91D1\u989D\uFF1A" + fmtPrice(cardData.amount)),
              h("div", null, "\u5907\u6CE8\uFF1A" + (cardData.remark || "\u65E0"))
            )
          );
        }
        if (isCompletionCertificate) {
          var certificateImages = Array.isArray(cardData.image_urls) ? cardData.image_urls.filter(Boolean) : [];
          return renderImMessageRow(
            h("div", { style: { width:"min(100%, 320px)", boxSizing:"border-box", padding:"12px 14px", borderRadius:isMine ? "12px 4px 12px 12px" : "4px 12px 12px 12px", background:"#fff", border:"1px solid "+S.border, boxShadow:"0 1px 2px rgba(0,0,0,0.05)" } },
              h("div", { style: { fontSize:14, fontWeight:700, color:S.textPrimary, marginBottom:4 } }, "订单服务凭证"),
              h("div", { style: { fontSize:10, color:S.textMuted, marginBottom:certificateImages.length > 0 ? 9 : 0 } },
                "订单 #" + (cardData.order_id || "-") + (cardData.service_title ? " · " + cardData.service_title : "")
              ),
              certificateImages.length > 0 ? h("div", { style: { display:"flex", flexWrap:"wrap", gap:6 } },
                certificateImages.map(function(imageUrl, imageIndex) {
                  return h("img", { key:imageIndex, src:imageUrl, onClick:function() { setPreviewImImage(imageUrl); }, onLoad:function() { var container = imScrollRef.current; if (container) container.scrollTop = container.scrollHeight; }, style: { width:72, height:72, objectFit:"cover", borderRadius:6, border:"1px solid "+S.border, cursor:"pointer" } });
                })
              ) : null
            )
          );
        }
        return renderImMessageRow(
          msg.msg_type === "image" && msg.image_url
            ? h("img", { src:msg.image_url, onClick:function() { setPreviewImImage(msg.image_url); }, onLoad:function() { var container = imScrollRef.current; if (container) container.scrollTop = container.scrollHeight; }, style: { maxWidth:"100%", maxHeight:220, objectFit:"contain", borderRadius:10, border:"1px solid "+S.border, cursor:"pointer", background:"#fff" } })
            : h("div", { style: { padding:"9px 13px", borderRadius:isMine ? "12px 4px 12px 12px" : "4px 12px 12px 12px", background:isMine ? S.primary : "#fff", color:isMine ? "#fff" : S.textPrimary, fontSize:14, lineHeight:1.55, wordBreak:"break-word", whiteSpace:"pre-wrap", boxShadow:"0 1px 2px rgba(0,0,0,0.06)" } }, msg.content || "")
        );
      })
    ),
    // === Bottom IM input bar ===
    conversationId > 0 ? h("div", { style: { display:"flex", alignItems:"center", padding:"7px 12px", paddingBottom:"calc(7px + env(safe-area-inset-bottom, 0px))", background:"#F7F7F7", borderTop:"1px solid "+S.border, gap:7, flexShrink:0 } },
    h("button", { onClick:selectAndSendImImage, disabled:imUploading, style: { height:34, padding:"0 10px", borderRadius:6, border:"1px solid "+S.border, background:"#fff", color:S.textSecondary, fontSize:12, cursor:imUploading ? "not-allowed" : "pointer", flexShrink:0 } }, imUploading ? "上传中" : "图片"),
    h("input", { type:"text", value:imInput, maxLength:2000, placeholder:"想跟TA说点什么...", disabled:imSending, onChange:function(e) { setImInput(e.target.value); }, onKeyDown:function(e) { if (e.key === "Enter" && !e.shiftKey) { e.preventDefault(); sendImText(); } }, style: { flex:1, minWidth:0, height:34, boxSizing:"border-box", borderRadius:6, background:"#fff", padding:"0 12px", fontSize:13, color:S.textPrimary, border:"1px solid "+S.border, outline:"none" } }),
    h("button", { onClick:sendImText, disabled:imSending || !String(imInput || "").trim(), style: { height:34, padding:"0 14px", borderRadius:6, border:"none", background:imSending || !String(imInput || "").trim() ? "#A0C4FF" : S.primary, color:"#fff", fontSize:13, fontWeight:600, cursor:imSending || !String(imInput || "").trim() ? "not-allowed" : "pointer", flexShrink:0 } }, imSending ? "发送中" : "发送")
    ) : null,
    previewImImage ? h("div", { onClick:function() { setPreviewImImage(null); }, style: { position:"fixed", inset:0, zIndex:2000, background:"rgba(0,0,0,0.85)", display:"flex", alignItems:"center", justifyContent:"center", cursor:"pointer" } },
      h("img", { src:previewImImage, onClick:function(e) { e.stopPropagation(); }, style: { maxWidth:"92%", maxHeight:"90%", objectFit:"contain", borderRadius:4 } })
    ) : null,
    // === Modals ===
    showBoosterModal ? h("div", { style: { position:"fixed", top:0, left:0, right:0, bottom:0, background:"rgba(0,0,0,0.5)", display:"flex", alignItems:"flex-end", justifyContent:"center", zIndex:1000, onClick: function(e) { if (e.target === e.currentTarget) { setShowBoosterModal(false); setSelectedFiles([]); } } } },
      h("div", { style: { background:"#fff", borderRadius:"16px 16px 0 0", width:"100%", maxWidth:500, padding:"20px 16px 24px", maxHeight:"80vh", overflowY:"auto" }, onClick: function(e) { e.stopPropagation(); } },
        h("div", { style: { fontSize:16, fontWeight:700, color:S.textPrimary, marginBottom:16, textAlign:"center" } }, "\u63D0\u4EA4\u670D\u52A1\u5B8C\u6210\u622A\u56FE"),
        h("div", { style: { background:S.bg, borderRadius:10, padding:12, marginBottom:16, fontSize:13, lineHeight:1.8, color:S.textSecondary } },
          h("div", null, "\u670D\u52A1\u5668\uFF1A" + (serverName || "\u672A\u586B\u5199")),
          h("div", null, "\u8D26\u53F7ID\uFF1A" + (accountId || "\u672A\u586B\u5199")),
          h("div", null, "\u91D1\u989D\uFF1A" + fmtPrice(price)),
          h("div", null, "\u670D\u52A1\u540D\u79F0\uFF1A" + serviceName)
        ),
        selectedFiles && selectedFiles.length > 0 ? h("div", { style: { display:"flex", flexWrap:"wrap", gap:8, marginBottom:12 } },
          selectedFiles.map(function(file, fileIdx) {
            return h("div", { key: fileIdx, style: { position:"relative", width:80, height:80, borderRadius:8, overflow:"hidden", border:"1px solid "+S.border, flexShrink:0 } },
              h("img", { src: URL.createObjectURL(file), style: { width:"100%", height:"100%", objectFit:"cover" } }),
              h("div", { onClick: function() { var arr = selectedFiles.slice(); arr.splice(fileIdx, 1); setSelectedFiles(arr); }, style: { position:"absolute", top:2, right:2, width:20, height:20, borderRadius:"50%", background:"rgba(0,0,0,0.6)", color:"#fff", fontSize:12, display:"flex", alignItems:"center", justifyContent:"center", cursor:"pointer" } }, "\u00D7")
            );
          }),
          selectedFiles.length < 5 ? h("div", { onClick: triggerFilePicker, style: { width:80, height:80, borderRadius:8, border:"2px dashed "+S.border, display:"flex", alignItems:"center", justifyContent:"center", color:S.textMuted, fontSize:24, cursor:"pointer", flexShrink:0 } }, "+") : null
        ) : h("div", { onClick: triggerFilePicker, style: { border:"2px dashed "+S.border, borderRadius:10, padding:"30px 0", textAlign:"center", color:S.textMuted, fontSize:13, cursor:"pointer", marginBottom:12 } }, "\u70B9\u51FB\u4E0A\u4F20\u622A\u56FE"),
        h("div", { style: { display:"flex", gap:10 } },
          h("button", { onClick: function() { setShowBoosterModal(false); setSelectedFiles([]); }, style: { flex:1, padding:"12px", borderRadius:10, border:"1px solid "+S.border, background:"#fff", color:S.textSecondary, fontSize:14, cursor:"pointer" } }, "\u53D6\u6D88"),
          h("button", { onClick: handleUploadAndSubmit, disabled: uploading || !selectedFiles || selectedFiles.length === 0, style: { flex:1, padding:"12px", borderRadius:10, border:"none", background:(uploading || !selectedFiles || selectedFiles.length === 0) ? "#A0C4FF" : S.primary, color:"#fff", fontSize:14, fontWeight:600, cursor:"pointer" } }, uploading ? "\u4E0A\u4F20\u4E2D..." : "\u5B8C\u6210\u4E0A\u4F20")
        )
      )
    ) : null,

    showReviewModal ? h("div", { style: { position:"fixed", top:0, left:0, right:0, bottom:0, background:"rgba(0,0,0,0.5)", display:"flex", alignItems:"flex-end", justifyContent:"center", zIndex:1000, onClick: function(e) { if (e.target === e.currentTarget) setShowReviewModal(false); } } },
      h("div", { style: { background:"#fff", borderRadius:"16px 16px 0 0", width:"100%", maxWidth:500, padding:"20px 16px 24px", maxHeight:"85vh", overflowY:"auto" }, onClick: function(e) { e.stopPropagation(); } },
        h("div", { style: { display:"flex", alignItems:"center", justifyContent:"space-between", marginBottom:16 } },
          h("div", { style: { fontSize:16, fontWeight:700, color:S.textPrimary } }, "你觉得本次服务体验如何？"),
          h("div", { onClick: function() { setShowReviewModal(false); }, style: { fontSize:22, color:S.textMuted, cursor:"pointer", lineHeight:1, padding:"0 4px" } }, "×")
        ),
        h("div", { style: { display:"flex", justifyContent:"space-around", marginBottom:16 } },
          ["good","middle","bad"].map(function(r) {
            var label = r === "good" ? "好评" : r === "middle" ? "中评" : "差评";
            var emoji = r === "good" ? "😊" : r === "middle" ? "😐" : "😞";
            var isSelected = reviewRating === r;
            return h("div", { key: r, onClick: function() { setReviewRating(r); }, style: { display:"flex", flexDirection:"column", alignItems:"center", padding:"10px 16px", borderRadius:12, cursor:"pointer", border:isSelected ? "2px solid "+S.primary : "2px solid "+S.border, background:isSelected ? S.primaryLight : "#fff", transition:"all 0.2s" } },
              h("div", { style: { fontSize:28, marginBottom:4 } }, emoji),
              h("div", { style: { fontSize:13, fontWeight:isSelected?600:400, color:isSelected ? S.primary : S.textSecondary } }, label)
            );
          })
        ),
        h("textarea", { value: reviewText, onInput: function(e) { setReviewText(e.target.value); }, placeholder: "分享服务感受，帮助更多小伙伴~", style: { width:"100%", minHeight:72, borderRadius:10, border:"1px solid "+S.border, padding:10, fontSize:13, resize:"vertical", outline:"none", boxSizing:"border-box", fontFamily:"inherit", marginBottom:12 } }),
        h("div", { style: { marginBottom:16 } },
          reviewImages && reviewImages.length > 0 ? h("div", { style: { display:"flex", flexWrap:"wrap", gap:8 } },
            reviewImages.map(function(file, fileIdx) {
              return h("div", { key: fileIdx, style: { position:"relative", width:64, height:64, borderRadius:8, overflow:"hidden", border:"1px solid "+S.border, flexShrink:0 } },
                h("img", { src: URL.createObjectURL(file), style: { width:"100%", height:"100%", objectFit:"cover" } }),
                h("div", { onClick: function() { var arr = reviewImages.slice(); arr.splice(fileIdx, 1); setReviewImages(arr); }, style: { position:"absolute", top:2, right:2, width:18, height:18, borderRadius:"50%", background:"rgba(0,0,0,0.6)", color:"#fff", fontSize:11, display:"flex", alignItems:"center", justifyContent:"center", cursor:"pointer" } }, "×")
              );
            }),
            reviewImages.length < 5 ? h("div", { onClick: function() { var inp = document.createElement("input"); inp.type = "file"; inp.accept = "image/*"; inp.multiple = true; inp.onchange = function(e) { var files = e.target.files; if (files && files.length > 0) { var arr = reviewImages.slice(); for (var fi = 0; fi < files.length && arr.length < 5; fi++) { arr.push(files[fi]); } setReviewImages(arr); } }; inp.click(); }, style: { width:64, height:64, borderRadius:8, border:"2px dashed "+S.border, display:"flex", alignItems:"center", justifyContent:"center", color:S.textMuted, fontSize:20, cursor:"pointer", flexShrink:0 } }, "+") : null
          ) : h("div", { onClick: function() { var inp = document.createElement("input"); inp.type = "file"; inp.accept = "image/*"; inp.multiple = true; inp.onchange = function(e) { var files = e.target.files; if (files && files.length > 0) { var arr = []; for (var fi = 0; fi < files.length && fi < 5; fi++) { arr.push(files[fi]); } setReviewImages(arr); } }; inp.click(); }, style: { border:"2px dashed "+S.border, borderRadius:10, padding:"16px 0", textAlign:"center", color:S.textMuted, fontSize:12, cursor:"pointer" } }, "上传图片（可选，最多5张）")
        ),
        h("button", { onClick: doCompleteOrder, disabled: completing, style: { width:"100%", padding:"12px", borderRadius:10, border:"none", background:completing ? "#A0C4FF" : S.primary, color:"#fff", fontSize:15, fontWeight:600, cursor:"pointer" } }, completing ? "提交中..." : "确认订单完成")
      )
    ) : null  );
};

window.NK = window.NK || {};
NK.EscortOrderChatPage = EscortOrderChatPage;
