﻿

// 方块号仓 - 用户端 H5 App
const { useState, useEffect, useRef } = React;

// App 客户端检测（URL 参数 + UA）
(function(){
  var params = new URLSearchParams(window.location.search);
  var isApp = params.get("client") === "app" || /NKHCApp/.test(navigator.userAgent);
  if (isApp) {
    document.documentElement.classList.add("is-app-client");
    document.body.classList.add("is-app-client");
    console.log("[App] client mode detected");
  }
})();

// ===== Emergency fallback: ensure NK.Store has required methods =====
(function() {
  window.NK = window.NK || {};
  window.NK.Store = window.NK.Store || {};
  console.log("[BOOT] NK.Store keys:", Object.keys(window.NK.Store));
  console.log("[BOOT] switchTab type:", typeof window.NK.Store.switchTab);
  console.log("[BOOT] appBackFromNative type:", typeof window.NK.Store.appBackFromNative);

  if (typeof window.NK.Store.switchTab !== "function") {
    console.error("[BOOT] NK.Store.switchTab missing, installing emergency fallback");
    window.NK.Store.switchTab = function(page, params) {
      params = params || {};
      console.warn("[FALLBACK] switchTab(" + page + ") - using navigate fallback");
      if (typeof window.NK.Store.navigate === "function") {
        return window.NK.Store.navigate(page, params);
      }
      console.error("[FALLBACK] Store.navigate also missing!");
    };
  }

  if (typeof window.NK.Store.appBackFromNative !== "function") {
    console.error("[BOOT] appBackFromNative missing, installing fallback");
    window.NK.Store.appBackFromNative = function() {
      var page = window.NK.Store.get("page");
      console.warn("[FALLBACK] appBackFromNative, current page:", page);
      if (typeof window.NK.Store.back === "function") {
        return window.NK.Store.back();
      }
      return false;
    };
  }

  if (typeof window.NK.Store.appBack !== "function") {
    window.NK.Store.appBack = window.NK.Store.appBackFromNative;
  }
})();

function App() {
  const [page, setPage] = useState(NK.Store.get('page'));
  const [user, setUser] = useState(NK.Store.get('user'));
  const [adminPage, setAdminPage] = useState(NK.Store.get('adminPage'));
  const [publishFormActive, setPublishFormActive] = useState(false);
 var [imUnread, setImUnread] = useState(0);
  var imUnreadRefreshInFlightRef = useRef(false);
  var imUnreadDebounceTimerRef = useRef(null);
  var imUnreadSocketCleanupRef = useRef(null);

  function refreshImUnreadDebounced() {
    if (imUnreadRefreshInFlightRef.current) return;
    if (imUnreadDebounceTimerRef.current) {
      clearTimeout(imUnreadDebounceTimerRef.current);
    }
    imUnreadDebounceTimerRef.current = setTimeout(function() {
      imUnreadRefreshInFlightRef.current = true;
      window.fetchImUnread();
    }, 400);
  }

  useEffect(() => {
    const unsub1 = NK.Store.subscribe('page', setPage);
    const unsub2 = NK.Store.subscribe('user', setUser);
    const unsub3 = NK.Store.subscribe('adminPage', setAdminPage);
    const unsub4 = NK.Store.subscribe('publishFormActive', setPublishFormActive);
    return () => { unsub1(); unsub2(); unsub3(); unsub4(); };
  }, []);

  // Preload publish page static card images for instant display
  useEffect(() => {
    var urls = [
      "/assets/publish/finished-account.webp",
      "/assets/publish/initial-account.webp"
    ];
    urls.forEach(function (src) {
      var img = new Image();
      img.src = src;
    });
  }, []);

    // Unified back icon (chevron-left SVG)
  NK.BackIcon = function(props) {
    var size = (props && props.size) || 22;
    var color = (props && props.color) || '#111827';
    return React.createElement('svg', {
      width: size, height: size, viewBox: '0 0 24 24',
      fill: 'none', stroke: color, strokeWidth: 1.875,
      strokeLinecap: 'round', strokeLinejoin: 'round'
    }, React.createElement('path', { d: 'm15 18-6-6 6-6' }));
  };

  // 全屏图片预览（可复用）
  NK.ImagePreview = function(props) {
    var images = props.images || [];
    var index = props.index || 0;
    var onClose = props.onClose || function(){};
    var onIndexChange = props.onIndexChange || null;
    if (!images.length) return null;
    var current = images[Math.max(0, Math.min(index, images.length - 1))];
    return React.createElement('div', {
      className: 'image-preview-mask',
      onClick: function(e) { if (e.target === e.currentTarget) onClose(); }
    },
      React.createElement('div', { className: 'image-preview-close', onClick: onClose },
        React.createElement('svg', { viewBox: '0 0 24 24', fill: 'none', stroke: '#fff', strokeWidth: 2.5, strokeLinecap: 'round' },
          React.createElement('path', { d: 'M18 6 6 18' }), React.createElement('path', { d: 'm6 6 12 12' })
        )
      ),
      React.createElement('img', { src: current, alt: '' }),
      images.length > 1 && React.createElement('div', { className: 'image-preview-index' }, (index + 1) + '/' + images.length),
      images.length > 1 && index > 0 && React.createElement('div', {
        className: 'image-preview-nav image-preview-prev',
        onClick: function(e) { e.stopPropagation(); if (onIndexChange) onIndexChange(index - 1); }
      }, React.createElement('svg', { viewBox: '0 0 24 24', fill: 'none', stroke: '#fff', strokeWidth: 2.5, strokeLinecap: 'round' },
        React.createElement('path', { d: 'm15 18-6-6 6-6' })
      )),
      images.length > 1 && index < images.length - 1 && React.createElement('div', {
        className: 'image-preview-nav image-preview-next',
        onClick: function(e) { e.stopPropagation(); if (onIndexChange) onIndexChange(index + 1); }
      }, React.createElement('svg', { viewBox: '0 0 24 24', fill: 'none', stroke: '#fff', strokeWidth: 2.5, strokeLinecap: 'round' },
        React.createElement('path', { d: 'm9 18 6-6-6-6' })
      ))
    );
  };

    const handleTab = (tabPage) => {
    console.log("[Tab] click", tabPage, {
      hasStore: !!(window.NK && window.NK.Store),
      switchTabType: typeof (window.NK && window.NK.Store && window.NK.Store.switchTab),
      storeKeys: (window.NK && window.NK.Store) ? Object.keys(window.NK.Store) : []
    });
    NK.Store.switchTab(tabPage); if (tabPage === 'messages') window.fetchImUnread();
  };

  // ---- inline SVG tab icons (linear style, 24x24, stroke:currentColor) ----
  const svgAttrs = { width: 24, height: 24, viewBox: '0 0 24 24', fill: 'none', stroke: 'currentColor', strokeWidth: 2, strokeLinecap: 'round', strokeLinejoin: 'round' };
  const tabIcons = {
    home: React.createElement('svg', svgAttrs,
      React.createElement('path', { d: 'M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z' }),
      React.createElement('polyline', { points: '9 22 9 12 15 12 15 22' })
    ),
    publish: React.createElement('svg', svgAttrs,
      React.createElement('circle', { cx: 12, cy: 12, r: 10 }),
      React.createElement('line', { x1: 12, y1: 8, x2: 12, y2: 16 }),
      React.createElement('line', { x1: 8, y1: 12, x2: 16, y2: 12 })
    ),
    messages: React.createElement('svg', svgAttrs,
      React.createElement('path', { d: 'M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z' })
    ),
    dynamics: React.createElement('svg', svgAttrs,
      React.createElement('circle', { cx: 12, cy: 12, r: 10 }),
      React.createElement('path', { d: 'M12 6v6l4 2' })
    ),
    escortHome: React.createElement('svg', svgAttrs,
      React.createElement('path', { d: 'M15 21v-5a1 1 0 0 0-1-1h-4a1 1 0 0 0-1 1v5' }),
      React.createElement('path', { d: 'M17.774 10.31a1.12 1.12 0 0 0-1.549 0 2.5 2.5 0 0 1-3.451 0 1.12 1.12 0 0 0-1.548 0 2.5 2.5 0 0 1-3.452 0 1.12 1.12 0 0 0-1.549 0 2.5 2.5 0 0 1-3.77-3.248l2.889-4.184A2 2 0 0 1 7 2h10a2 2 0 0 1 1.653.873l2.895 4.192a2.5 2.5 0 0 1-3.774 3.244' }),
      React.createElement('path', { d: 'M4 10.95V19a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-8.05' })
    ),
    mine: React.createElement('svg', svgAttrs,
      React.createElement('path', { d: 'M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2' }),
      React.createElement('circle', { cx: 12, cy: 7, r: 4 })
    ),
  };

  const tabs = [
    { key: 'home',      label: '\u9996\u9875' },
    { key: 'escortHome', label: '\u670D\u52A1' },
    { key: 'dynamics',  label: '\u52A8\u6001' },
    { key: 'messages',  label: '\u6D88\u606F' },
    { key: 'mine',      label: '\u6211\u7684' }
  ];

  // 组件为 undefined 时显示错误提示
  const s = function(Comp, name) {
    if (!Comp) {
      console.error('[App] MISSING component:', name, { productDetailType: typeof NK.ProductDetailPage, myProductDetailType: typeof NK.MyProductDetailPage, keys: Object.keys(NK||{}) });
      return React.createElement('div', {className: 'page-error', style: {padding: 40, textAlign: 'center', color: '#ff4d4f'}},
        React.createElement('div', {style: {fontSize: 48, marginBottom: 12}}, '\u26A0\uFE0F'),
        React.createElement('div', {style: {fontSize: 16, fontWeight: 700, marginBottom: 8}}, '\u9875\u9762\u7EC4\u4EF6\u52A0\u8F7D\u5931\u8D25'),
        React.createElement('div', {style: {fontSize: 14, color: '#999'}}, '\u7EC4\u4EF6: ' + name + ' \u672A\u5B9A\u4E49')
      );
    }
    return React.createElement(Comp);
  };

  const renderContent = () => {
  console.log('[BOOT] ProductDetailPage type:', typeof NK.ProductDetailPage);
  console.log('[BOOT] MyProductDetailPage type:', typeof NK.MyProductDetailPage);
    console.log('[App] NK keys count:', Object.keys(window.NK || {}).length);
    switch (page) {
      case 'login':       return s(NK.AuthPage, 'AuthPage');
      case 'detail':      return s(NK.ProductDetailPage, 'ProductDetailPage');
      case 'myProductDetail': return s(NK.MyProductDetailPage, 'MyProductDetailPage');
      case 'tradeRoom':   return s(NK.TradeRoomPage, 'TradeRoomPage');
      case 'publish':      return s(NK.PublishPage, 'PublishPage');
      case 'messages':    return s(NK.MessagesPage, 'MessagesPage');
      case 'orders':      return s(NK.OrdersPage, 'OrdersPage');
      case 'payment':    return s(NK.PaymentPage, 'PaymentPage');
      case 'mine':        return s(NK.ProfilePage, 'ProfilePage');
      case 'myProducts':  return s(NK.MyProductsPage, 'MyProductsPage');
      case 'admin':
        return adminPage === 'audit' ? s(NK.AdminAuditPage, 'AdminAuditPage') : s(NK.AdminLoginPage, 'AdminLoginPage');
      case 'myAppeals':   return s(NK.MyAppealsPage, 'MyAppealsPage');
      case 'appealDetail': return s(NK.AppealDetailPage, 'AppealDetailPage');
      case 'bargainCreate': return s(NK.BargainCreatePage, 'BargainCreatePage');
      case 'bargainSession': return s(NK.BargainSessionPage, 'BargainSessionPage');
      case 'bargainList':   return s(NK.BargainListPage, 'BargainListPage');
      case 'adminDisputes': return s(NK.AdminDisputesPage, 'AdminDisputesPage');
      case 'wallet':      return s(NK.WalletPage, 'WalletPage');
      case 'walletTransactions': return s(NK.WalletTransactionsPage, 'WalletTransactionsPage');
      case 'favorites':   return s(NK.FavoritePage, 'FavoritePage');
      case 'withdraw':    return s(NK.WithdrawPage, 'WithdrawPage');
      case 'withdrawRecords': return s(NK.WithdrawRecordsPage, 'WithdrawRecordsPage');
      case 'profileEdit': return s(NK.ProfileEditPage, 'ProfileEditPage');
      case 'noPermission': return s(NK.NoPermissionPage, 'NoPermissionPage');
      case 'escortHome':  return s(NK.EscortHomePage, 'EscortHomePage');
      case 'escortDetail': return s(NK.EscortDetailPage, 'EscortDetailPage');
      case 'escortPay':    return s(NK.EscortPayPage, 'EscortPayPage');
      case 'dashouJoin':   return s(NK.DaShouJoinPage, 'DaShouJoinPage');
      case 'boosterCenter': return s(NK.BoosterCenterPage, 'BoosterCenterPage');
      case 'dynamics':   return s(NK.DynamicsPage, 'DynamicsPage');
      case 'dynamicNoticeDetail': return s(NK.DynamicNoticeDetailPage, 'DynamicNoticeDetailPage');
      case 'boosterHall':  return s(NK.BoosterHallPage, 'BoosterHallPage');
      case 'escortOrderChat': return s(NK.EscortOrderChatPage, 'EscortOrderChatPage');
      case 'escortOrderDetail': return s(NK.EscortOrderDetailPage, 'EscortOrderDetailPage');
      case 'adminDisputeDetail': return s(NK.AdminDisputeDetailPage, 'AdminDisputeDetailPage');
      case 'supportChat':   return s(NK.SupportChatPage, 'SupportChatPage');
      case 'boosterPublicProfile': return s(NK.BoosterPublicProfilePage, 'BoosterPublicProfilePage');
      case 'home':
      default:           return s(NK.HomePage, 'HomePage');
    }
  };

  // TabBar 显示逻辑
  
  window.loadAllMessageUnreadTotal = function() {
    var total = 0;
    if (typeof NK !== 'undefined' && NK.Api && NK.Api.Im && NK.Api.Im.conversations) {
      return NK.Api.Im.conversations({}).then(function(res) {
        if (res && res.code === 0 && Array.isArray(res.data)) {
          res.data.forEach(function(c) { total += (c.unread_count || 0); });
        }
        return total;
      }).catch(function() { return 0; });
    }
    return Promise.resolve(0);
  };

  window.fetchImUnread = function() {
    window.loadAllMessageUnreadTotal().then(function(total) {
      setImUnread(total);
    }).catch(function() {}).finally(function() {
      imUnreadRefreshInFlightRef.current = false;
    });
  };

  // Poll unread every 30s
  useEffect(function() {
    window.fetchImUnread();
    var timer = setInterval(window.fetchImUnread, 30000);
    return function() { clearInterval(timer); };
  }, []);

  // Refresh unread when page changes to messages
 useEffect(function() {
   if (page === 'messages') window.fetchImUnread();
 }, [page]);

  // Socket lifecycle: connect on login, reconnect on user change, disconnect on logout
  useEffect(function() {
    var token = NK.Api.getToken();
    if (!token) {
      if (typeof NK.UserImSocket !== "undefined") {
        NK.UserImSocket.disconnect();
      }
      setImUnread(0);
      return;
    }
    if (typeof NK.UserImSocket === "undefined") return;
    NK.UserImSocket.connect(token);
    if (imUnreadSocketCleanupRef.current) {
      imUnreadSocketCleanupRef.current();
      imUnreadSocketCleanupRef.current = null;
    }
    var offUnread = NK.UserImSocket.on("im:unread_updated", refreshImUnreadDebounced);
    var offConvUpdated = NK.UserImSocket.on("im:conversation_updated", refreshImUnreadDebounced);
    var offNewMsg = NK.UserImSocket.on("im:new_message", refreshImUnreadDebounced);
    imUnreadSocketCleanupRef.current = function() {
      offUnread();
      offConvUpdated();
      offNewMsg();
    };
    return function() {
      if (imUnreadSocketCleanupRef.current) {
        imUnreadSocketCleanupRef.current();
        imUnreadSocketCleanupRef.current = null;
      }
    };
  }, [user]);

 const showTabBar = page === 'home' || page === 'messages' || page === 'mine' || page === 'dynamics' || page === 'escortHome';

  // 拥有 back-header 的页面不显示 app-header
  const hasOwnHeader = page === 'detail' || page === 'myProductDetail' || page === 'myProducts' || page === 'orders' || page === 'tradeRoom' || page === 'bargainCreate' || page === 'bargainSession' || page === 'bargainList' || page === 'escortHome' || page === 'escortDetail' || page === 'escortPay' || page === 'dashouJoin' || page === 'boosterCenter' || page === 'boosterHall' || page === 'escortOrderChat' || page === 'escortOrderDetail' || page === 'boosterPublicProfile' || page === 'dynamicNoticeDetail' || page === 'supportChat' || page === 'profileEdit';

  const isTabActive = (tabKey) => tabKey === page;

  var containerCls = 'app-container' + (hasOwnHeader ? ' no-app-header' : '') + (page === 'escortDetail' ? ' escort-page' : '');
  return React.createElement('div', { className: containerCls },
    !hasOwnHeader && React.createElement('div', { className: 'app-header' },
      React.createElement('div', { className: 'header-left' },
        React.createElement('span', { style: { fontSize: 20 } }, '\uD83C\uDFDB'),
        React.createElement('span', { className: 'header-title' }, '\u65B9\u5757\u53F7\u4ED3')
      ),
      React.createElement('div', { className: 'header-right' },
        user
          ? React.createElement('span', {
              className: 'header-btn',
              onClick: () => { NK.Api.clearToken(); NK.Store.setAll({ user: null, page: 'home' }); }
            }, (user.nickname || user.phone || '\u6211').substring(0, 4))
          : React.createElement('span', {
              className: 'header-btn',
              onClick: () => NK.Store.navigate('login')
            }, '\u767B\u5F55')
      )
    ),

    React.createElement('div', { className: 'app-content' }, renderContent()),

    showTabBar && React.createElement('div', { className: 'app-tabbar' },
      tabs.map(tab => {
        var active = isTabActive(tab.key);
        return React.createElement('div', {
          key: tab.key,
          className: 'tab-item' + (active ? ' active' : ''),
          onClick: function() { handleTab(tab.key); }
        },
          React.createElement('span', { className: 'tab-icon' },
            tabIcons[tab.key],
            tab.key === 'messages' && imUnread > 0 ? React.createElement('span', { style: { position: 'absolute', top: -2, right: -8, background: '#ff4d4f', color: '#fff', fontSize: 10, borderRadius: 10, padding: '1px 5px', minWidth: 16, textAlign: 'center', lineHeight: '16px', fontWeight: 600 } }, imUnread > 99 ? '99+' : String(imUnread)) : null
          ),
          React.createElement('span', { className: 'tab-label' }, tab.label)
        );
      })
    )
  );
}

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(React.createElement(App));








