// Shared components for Jiucun Wang prototype

const { useState, useEffect, useRef, useContext, createContext } = React;

// ============ App Context ============
const AppContext = createContext(null);

function useApp() {
  const ctx = useContext(AppContext);
  if (!ctx) throw new Error('useApp must be used within AppProvider');
  return ctx;
}

// ============ Toast ============
function useToast() {
  const [toast, setToast] = useState({ show: false, msg: '' });
  const timerRef = useRef(null);

  const showToast = (msg) => {
    setToast({ show: true, msg });
    if (timerRef.current) clearTimeout(timerRef.current);
    timerRef.current = setTimeout(() => {
      setToast({ show: false, msg: '' });
    }, 2000);
  };

  const ToastEl = () => (
    <div className={`toast ${toast.show ? 'show' : ''}`}>{toast.msg}</div>
  );

  return { showToast, ToastEl };
}

// ============ Bottom Sheet Modal ============
function BottomSheet({ show, onClose, title, children }) {
  return (
    <>
      <div
        className={`modal-overlay ${show ? 'show' : ''}`}
        onClick={onClose}
      />
      <div className={`bottom-sheet ${show ? 'show' : ''}`}>
        <div className="sheet-handle"></div>
        {title && <div className="sheet-title">{title}</div>}
        {children}
      </div>
    </>
  );
}

// ============ Bottom Navigation ============
const NAV_CONFIGS = {
  default: {
    theme: '',
    items: [
      { id: 'article-list', label: '文章', icon: '📝' },
      { id: 'archive', label: '存档', icon: '📦' },
      { id: 'apps', label: '应用', icon: '📱' },
      { id: 'feed', label: '说说', icon: '💭' },
      { id: 'messages', label: '消息', icon: '💬', badge: 0 },
      { id: 'profile', label: '我的', icon: '👤' },
    ],
  },
  video: {
    theme: 'theme-video',
    items: [
      { id: 'video-recommend', label: '推荐', icon: '🏠' },
      { id: 'video-follow', label: '关注', icon: '❤' },
      { id: 'fab', type: 'fab', icon: '＋' },
      { id: 'video-msg', label: '消息', icon: '💬', badge: 3 },
      { id: 'video-me', label: '我的', icon: '👤' },
    ],
  },
  memorial: {
    theme: 'theme-memorial',
    items: [
      { id: 'memorial-altar', label: '祭台', icon: '🕯️' },
      { id: 'memorial-msg', label: '留言', icon: '💬' },
      { id: 'memorial-album', label: '相册', icon: '📷' },
      { id: 'memorial-me', label: '我的', icon: '👤' },
    ],
  },
  love: {
    theme: 'theme-love',
    items: [
      { id: 'love-dynamic', label: '动态', icon: '💭' },
      { id: 'fab', type: 'fab', icon: '＋' },
      { id: 'love-album', label: '相册', icon: '📷' },
      { id: 'love-me', label: '我的', icon: '👤' },
    ],
  },
  accounting: {
    theme: 'theme-accounting',
    items: [
      { id: 'accounting-bills', label: '账单', icon: '📝' },
      { id: 'accounting-receivables', label: '往来', icon: '💼' },
      { id: 'accounting-stats', label: '统计', icon: '📊' },
      { id: 'accounting-accounts', label: '账户', icon: '💳' },
    ],
  },
  im: {
    theme: 'theme-im',
    items: [
      { id: 'im-chats', label: '会话', icon: '💬', badge: 8 },
      { id: 'im-groups', label: '群聊', icon: '👥' },
      { id: 'fab', type: 'fab', icon: '＋' },
      { id: 'im-contacts', label: '通讯录', icon: '📒' },
      { id: 'im-me', label: '我的', icon: '👤' },
    ],
  },
  member: {
    theme: 'theme-member',
    items: [
      { id: 'member-home', label: '会员主页', icon: '👑' },
      { id: 'member-plan', label: '套餐购买', icon: '💳' },
      { id: 'fab', type: 'fab', icon: '＋', label: '充值' },
      { id: 'member-rights', label: '权益中心', icon: '🎁' },
      { id: 'member-orders', label: '订单', icon: '📋' },
    ],
  },
  yellowpages: {
    theme: 'theme-yellowpages',
    items: [
      { id: 'yp-home', label: '黄页首页', icon: '🏢' },
      { id: 'yp-list', label: '企业名录', icon: '📇' },
      { id: 'fab', type: 'fab', icon: '＋' },
      { id: 'yp-im', label: '咨询消息', icon: '💬', badge: 1 },
      { id: 'yp-me', label: '我的企业', icon: '👤' },
    ],
  },
  sitemap: {
    theme: 'theme-sitemap',
    items: [
      { id: 'sm-home', label: '地图首页', icon: '🗺️' },
      { id: 'sm-index', label: '模块索引', icon: '📑' },
      { id: 'fab', type: 'fab', icon: '＋', label: '直达' },
      { id: 'sm-perm', label: '权限说明', icon: '🔒' },
      { id: 'sm-me', label: '我的入口', icon: '👤' },
    ],
  },
  orders: {
    theme: 'theme-orders',
    items: [
      { id: 'order-home', label: '订单首页', icon: '📋' },
      { id: 'order-all', label: '全部订单', icon: '📦' },
      { id: 'fab', type: 'fab', icon: '＋' },
      { id: 'order-refund', label: '售后退款', icon: '↩️' },
      { id: 'order-bill', label: '我的账单', icon: '💰' },
    ],
  },
  distribution: {
    theme: 'theme-distribution',
    items: [
      { id: 'dist-home', label: '分销首页', icon: '🤝' },
      { id: 'dist-material', label: '推广物料', icon: '📦' },
      { id: 'fab', type: 'fab', icon: '＋', label: '生成链接' },
      { id: 'dist-team', label: '下级管理', icon: '👥' },
      { id: 'dist-commission', label: '佣金明细', icon: '💰' },
    ],
  },
};

function BottomNav({ navType, activeId, onNav, onFab }) {
  const config = NAV_CONFIGS[navType] || NAV_CONFIGS.default;
  const items = config.items;
  const hasFab = items.some(i => i.type === 'fab');
  const normalItems = items.filter(i => i.type !== 'fab');

  return (
    <nav className="bottom-nav">
      {items.map((item, idx) => {
        if (item.type === 'fab') {
          return (
            <div
              key="fab"
              className="nav-fab"
              onClick={onFab}
              style={{ left: `${((idx + 0.5) / items.length) * 100}%` }}
            >
              {item.icon}
            </div>
          );
        }
        const isActive = activeId === item.id;
        return (
          <div
            key={item.id}
            className={`nav-item ${isActive ? 'active' : ''}`}
            onClick={() => onNav(item.id)}
          >
            <span className="nav-icon">{item.icon}</span>
            <span>{item.label}</span>
            {item.badge > 0 && <span className="nav-badge">{item.badge}</span>}
          </div>
        );
      })}
    </nav>
  );
}

// ============ App Header ============
function AppHeader({ title, subtitle, showBack, onBack, rightContent, showActions }) {
  const { currentUser, navigate, goBack, requireLogin, currentPage, setShowPublish, showToast } = useApp();

  const handleBack = () => {
    if (onBack) {
      onBack();
    } else {
      goBack();
    }
  };

  // 上下文智能发布：当前页面对应的发布面板
  const handlePlusClick = () => {
    if (!requireLogin(() => handlePlusClick(), 'login')) return;
    const page = currentPage || '';
    // 文章页 → 打开发文章
    if (page === 'article-list' || page === 'article-detail' || page === 'my-articles') {
      if (window.openArticlePublish) {
        window.openArticlePublish();
      } else if (setShowPublish) {
        setShowPublish(true);
      }
    }
    // 存档页 → 跳转到我的存档上传
    else if (page === 'archive' || page === 'my-archive') {
      if (navigate) navigate('my-archive');
      else showToast && showToast('前往我的存档上传');
    }
    // 说说页 → 打开发说说
    else if (page === 'feed') {
      if (window.openFeedPublish) {
        window.openFeedPublish();
      } else if (setShowPublish) {
        setShowPublish(true);
      } else {
        showToast && showToast('功能开发中');
      }
    }
    // 其他页 → 默认打开发说说
    else {
      if (window.openFeedPublish) {
        window.openFeedPublish();
      } else if (setShowPublish) {
        setShowPublish(true);
      } else {
        showToast && showToast('功能开发中');
      }
    }
  };

  const handleHomeClick = () => {
    navigate('home');
  };

  const handleServiceClick = () => {
    if (!requireLogin(() => handleServiceClick(), 'login')) return;
    if (window.showCustomerServiceModal) {
      window.showCustomerServiceModal();
    } else if (showToast) {
      showToast('客服功能加载中...');
    }
  };

  return (
    <header className="app-header">
      <div className="flex items-center gap-8">
        {showBack && (
          <div style={{ fontSize: '20px', cursor: 'pointer', width: 28, height: 28, display: 'flex', alignItems: 'center', justifyContent: 'center' }} onClick={handleBack}>←</div>
        )}
        <div className="logo">
          <div className="logo-icon">久</div>
          <div>
            <div style={{ fontSize: '15px', lineHeight: 1.2 }}>{title || '久存网'}</div>
            {subtitle && <div className="logo-sub">{subtitle}</div>}
          </div>
        </div>
      </div>
      <div className="header-right" style={{ display: 'flex', alignItems: 'center', gap: 14 }}>
        {rightContent}
        {showActions !== false && (
          <>
            <div style={iconBtnStyle} onClick={handlePlusClick} title="发布">＋</div>
            <div style={iconBtnStyle} onClick={handleHomeClick} title="首页">🏠</div>
            <div style={iconBtnStyle} onClick={handleServiceClick} title="客服">🎧</div>
          </>
        )}
      </div>
    </header>
  );
}

const iconBtnStyle = {
  width: 28,
  height: 28,
  display: 'flex',
  alignItems: 'center',
  justifyContent: 'center',
  fontSize: 16,
  cursor: 'pointer',
  borderRadius: '50%',
  color: 'var(--text-primary)',
};

// ============ Publish Sheet (通用发布面板) ============
const PUBLISH_OPTIONS = {
  default: [
    { id: 'video', label: '发布视频', icon: '🎬', color: '#FF4757' },
    { id: 'article', label: '发布文章', icon: '📝', color: '#2ED573' },
    { id: 'image', label: '发布图片', icon: '🖼️', color: '#1E90FF' },
    { id: 'doc', label: '发布文档', icon: '📄', color: '#FFA502' },
    { id: 'mood', label: '心情动态', icon: '💭', color: '#FF6B9D' },
  ],
  video: [
    { id: 'upload', label: '上传视频', icon: '📤', color: '#165DFF' },
    { id: 'shoot', label: '拍摄视频', icon: '📹', color: '#FF4757' },
    { id: 'live', label: '开启直播', icon: '🔴', color: '#FF6348' },
    { id: 'drafts', label: '草稿箱', icon: '📋', color: '#9CA3AF' },
  ],
  accounting: [
    { id: 'expense', label: '支出', icon: '💸', color: '#FF4757' },
    { id: 'income', label: '收入', icon: '💰', color: '#00B578' },
    { id: 'transfer', label: '转账', icon: '↔️', color: '#1E90FF' },
    { id: 'borrow', label: '借出/借入', icon: '🤝', color: '#FFA502' },
  ],
  im: [
    { id: 'chat', label: '新建会话', icon: '💬', color: '#3B82F6' },
    { id: 'group', label: '创建群聊', icon: '👥', color: '#8B5CF6' },
    { id: 'scan', label: '扫一扫', icon: '📷', color: '#00B578' },
    { id: 'add', label: '添加好友', icon: '➕', color: '#FFA502' },
  ],
  member: [
    { id: 'recharge', label: '充值久币', icon: '💰', color: '#DAA520' },
    { id: 'upgrade', label: '升级会员', icon: '⬆️', color: '#FF6B9D' },
    { id: 'gift', label: '赠送会员', icon: '🎁', color: '#2ED573' },
    { id: 'card', label: '生成名片', icon: '🎴', color: '#3B82F6' },
  ],
  yellowpages: [
    { id: 'publish', label: '发布信息', icon: '📢', color: '#D2691E' },
    { id: 'product', label: '上架产品', icon: '📦', color: '#FF6B9D' },
    { id: 'news', label: '发布动态', icon: '📰', color: '#3B82F6' },
    { id: 'template', label: '更换模板', icon: '🎨', color: '#9370DB' },
  ],
  sitemap: [
    { id: 'quick', label: '快捷入口', icon: '⚡', color: '#FFA502' },
    { id: 'search', label: '搜索功能', icon: '🔍', color: '#3B82F6' },
    { id: 'favorite', label: '我的收藏', icon: '⭐', color: '#DAA520' },
    { id: 'recent', label: '最近使用', icon: '🕐', color: '#00B578' },
  ],
  orders: [
    { id: 'new', label: '新建订单', icon: '📝', color: '#8B5CF6' },
    { id: 'pay', label: '去支付', icon: '💳', color: '#00B578' },
    { id: 'invoice', label: '开发票', icon: '🧾', color: '#FFA502' },
    { id: 'service', label: '联系客服', icon: '🎧', color: '#3B82F6' },
  ],
  distribution: [
    { id: 'link', label: '生成链接', icon: '🔗', color: '#DC2626' },
    { id: 'qrcode', label: '生成二维码', icon: '📱', color: '#F87171' },
    { id: 'poster', label: '生成海报', icon: '🖼️', color: '#F59E0B' },
    { id: 'card', label: '分享名片', icon: '🎴', color: '#8B5CF6' },
  ],
  memorial: [
    { id: 'flower', label: '敬献鲜花', icon: '🌼', color: '#FFB6C1' },
    { id: 'candle', label: '点烛祈福', icon: '🕯️', color: '#FFA502' },
    { id: 'message', label: '撰写寄语', icon: '💌', color: '#8B7355' },
    { id: 'album', label: '上传照片', icon: '📷', color: '#6B7280' },
  ],
  love: [
    { id: 'declaration', label: '发布宣言', icon: '💕', color: '#FF6B9D' },
    { id: 'photo', label: '上传照片', icon: '📷', color: '#FFB6C1' },
    { id: 'diary', label: '写日记', icon: '📔', color: '#DDA0DD' },
    { id: 'wish', label: '许愿瓶', icon: '🏺', color: '#87CEEB' },
  ],
};

function PublishSheet({ show, onClose, type, onSelect }) {
  const options = PUBLISH_OPTIONS[type] || PUBLISH_OPTIONS.default;
  return (
    <BottomSheet show={show} onClose={onClose} title="选择发布类型">
      <div className="publish-grid">
        {options.map(opt => (
          <div
            key={opt.id}
            className="publish-item"
            onClick={() => { onSelect(opt); onClose(); }}
          >
            <div
              className="publish-icon"
              style={{ background: `${opt.color}20`, color: opt.color }}
            >
              {opt.icon}
            </div>
            <span className="publish-label">{opt.label}</span>
          </div>
        ))}
      </div>
      <div style={{ height: 16 }}></div>
      <button className="btn btn-block" style={{ background: '#f2f3f5', color: '#4e5969' }} onClick={onClose}>
        取消
      </button>
    </BottomSheet>
  );
}

// ============ Segmented Control ============
function SegmentedControl({ options, value, onChange }) {
  return (
    <div className="seg-control">
      {options.map(opt => (
        <div
          key={opt.value}
          className={`seg-item ${value === opt.value ? 'active' : ''}`}
          onClick={() => onChange(opt.value)}
        >
          {opt.label}
        </div>
      ))}
    </div>
  );
}

// ============ Page Wrapper ============
function PageWrapper({ theme, children, className = '' }) {
  return (
    <div className={`page-container ${className}`}>
      {children}
    </div>
  );
}

// ============ Error Boundary ============
class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false, error: null };
  }
  static getDerivedStateFromError(error) {
    return { hasError: true, error };
  }
  componentDidCatch(error, info) {
    console.error('[ErrorBoundary] caught:', error, info);
    // 清理可能残留的全屏固定定位遮罩（子组件渲染中断时 fixed 元素可能残留拦截点击）
    try {
      const selectors = [
        '[data-pipe-modal="1"]',
      ];
      selectors.forEach(sel => {
        document.querySelectorAll(sel).forEach(el => el.remove());
      });
    } catch(e) {}
  }
  render() {
    if (this.state.hasError) {
      return this.props.fallback || (
        <div style={{ padding: 40, textAlign: 'center', color: 'var(--text-secondary)' }}>
          <div style={{ fontSize: 40, marginBottom: 12 }}>⚠️</div>
          <div style={{ marginBottom: 8 }}>页面加载异常</div>
          <div style={{ fontSize: 12, color: 'var(--text-tertiary)' }}>请尝试刷新页面</div>
        </div>
      );
    }
    return this.props.children;
  }
}

// ============ 客服列表弹窗 ============
function CustomerServiceModal({ show, onClose }) {
  const { api, showToast, navigate, requireLogin } = useApp();
  const [list, setList] = React.useState([]);
  const [loading, setLoading] = React.useState(false);

  React.useEffect(() => {
    if (show) {
      setLoading(true);
      if (api && api.get) {
        api.get('/customer-service/list').then(res => {
          if (res.success && res.data) setList(res.data);
          setLoading(false);
        }).catch(() => setLoading(false));
      } else {
        setList([
          { id: 101, nickname: '久存小助手', jiuLiaoId: 'cs_101', intro: '7×24小时在线，解答您的问题', status: 'online' },
          { id: 102, nickname: '会员专属客服', jiuLiaoId: 'cs_102', intro: '金卡及以上会员专享客服通道', status: 'online' },
          { id: 103, nickname: '商务合作', jiuLiaoId: 'cs_103', intro: '企业合作、品牌推广咨询', status: 'offline' },
        ]);
        setLoading(false);
      }
    }
  }, [show, api]);

  const handleChat = (cs) => {
    if (!requireLogin(() => handleChat(cs), 'login')) return;
    try {
      onClose && onClose();
      // 跳转到久聊IM的客服会话
      if (window.API && window.API.post) {
        window.API.post('/im/conversations', {
          friend_id: cs.id,
          friend_name: cs.nickname,
          friend_avatar: cs.avatar || '',
        }).then(() => {
          navigate('im');
        }).catch(() => {
          navigate('im');
        });
      } else {
        navigate('im');
      }
    } catch (e) {}
  };

  if (!show) return null;

  return (
    <div
      style={{
        position: 'fixed', inset: 0, zIndex: 2000,
        background: 'rgba(0,0,0,0.5)',
        display: 'flex', alignItems: 'flex-end', justifyContent: 'center',
      }}
      onClick={() => onClose && onClose()}
    >
      <div
        onClick={e => e.stopPropagation()}
        style={{
          width: '100%', maxWidth: 480,
          background: 'var(--bg-card)',
          borderRadius: '16px 16px 0 0',
          maxHeight: '70vh',
          display: 'flex', flexDirection: 'column',
        }}
      >
        <div style={{
          padding: '16px 20px',
          borderBottom: '1px solid var(--border)',
          display: 'flex', justifyContent: 'space-between', alignItems: 'center',
        }}>
          <div style={{ fontSize: 16, fontWeight: 600, color: 'var(--text-primary)' }}>联系客服</div>
          <div style={{ fontSize: 20, color: 'var(--text-tertiary)', cursor: 'pointer' }} onClick={() => onClose && onClose()}>×</div>
        </div>
        <div style={{ flex: 1, overflowY: 'auto', padding: 12 }}>
          {loading ? (
            <div style={{ textAlign: 'center', padding: 30, color: 'var(--text-tertiary)' }}>加载中...</div>
          ) : list.length === 0 ? (
            <div style={{ textAlign: 'center', padding: 30, color: 'var(--text-tertiary)' }}>暂无客服</div>
          ) : (
            list.map(cs => (
              <div
                key={cs.id}
                onClick={() => handleChat(cs)}
                style={{
                  display: 'flex', alignItems: 'center', gap: 12,
                  padding: 12, borderRadius: 10,
                  cursor: 'pointer',
                }}
                onMouseEnter={e => e.currentTarget.style.background = 'var(--bg-page)'}
                onMouseLeave={e => e.currentTarget.style.background = 'transparent'}
              >
                <div style={{
                  width: 44, height: 44, borderRadius: '50%',
                  background: 'linear-gradient(135deg, var(--primary), #4080FF)',
                  color: '#fff',
                  display: 'flex', alignItems: 'center', justifyContent: 'center',
                  fontSize: 18, fontWeight: 600,
                  position: 'relative',
                }}>
                  {(cs.nickname || '客').charAt(0)}
                  <span style={{
                    position: 'absolute', bottom: 0, right: 0,
                    width: 10, height: 10, borderRadius: '50%',
                    background: cs.status === 'online' ? '#00B578' : '#9CA3AF',
                    border: '2px solid var(--bg-card)',
                  }} />
                </div>
                <div style={{ flex: 1, minWidth: 0 }}>
                  <div style={{ fontSize: 14, fontWeight: 500, color: 'var(--text-primary)', marginBottom: 2 }}>
                    {cs.nickname}
                    <span style={{ fontSize: 11, marginLeft: 6, color: cs.status === 'online' ? '#00B578' : 'var(--text-tertiary)' }}>
                      {cs.status === 'online' ? '在线' : '离线'}
                    </span>
                  </div>
                  <div style={{ fontSize: 12, color: 'var(--text-tertiary)', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
                    {cs.intro || ''}
                  </div>
                </div>
                <div style={{ fontSize: 14, color: 'var(--text-tertiary)' }}>→</div>
              </div>
            ))
          )}
        </div>
      </div>
    </div>
  );
}

// ================ XSS 安全工具 ================
// HTML 转义（纯文本字段）
function escapeHtml(str) {
  if (str == null) return '';
  return String(str)
    .replace(/&/g, '&amp;')
    .replace(/</g, '&lt;')
    .replace(/>/g, '&gt;')
    .replace(/"/g, '&quot;')
    .replace(/'/g, '&#39;')
    .replace(/`/g, '&#96;');
}

// 富文本白名单过滤（只允许安全标签和属性）
function sanitizeHtml(html) {
  if (!html) return '';
  let str = String(html);
  // 移除 script 标签及内容
  str = str.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, '');
  str = str.replace(/<script[^>]*>/gi, '');
  // 移除 style 标签
  str = str.replace(/<style\b[^<]*(?:(?!<\/style>)<[^<]*)*<\/style>/gi, '');
  // 移除 iframe/frame/embed/object/link/meta/base
  str = str.replace(/<(iframe|frame|embed|object|link|meta)\b[^>]*>.*?<\/\1>/gi, '');
  str = str.replace(/<(iframe|frame|embed|object|link|meta|base)\b[^>]*\/?>/gi, '');
  // 移除所有 on* 事件属性
  str = str.replace(/\s+on[a-z]+\s*=\s*"[^"]*"/gi, '');
  str = str.replace(/\s+on[a-z]+\s*=\s*'[^']*'/gi, '');
  str = str.replace(/\s+on[a-z]+\s*=\s*[^\s>]+/gi, '');
  // 移除 javascript: / data: 协议的链接
  str = str.replace(/(href|src|action)\s*=\s*["']\s*javascript:/gi, (m) => m.replace(/javascript:/gi, '#'));
  str = str.replace(/(href|src|action)\s*=\s*["']\s*data:/gi, (m) => m.replace(/data:/gi, '#'));
  return str;
}

// Export to window
Object.assign(window, {
  useApp,
  useToast,
  BottomSheet,
  BottomNav,
  AppHeader,
  PublishSheet,
  SegmentedControl,
  PageWrapper,
  ErrorBoundary,
  CustomerServiceModal,
  AppContext,
  escapeHtml,
  sanitizeHtml,
});
