// Q&A + Guides + Voting + Announcements — tabbed, Supabase-backed.
const sb = window.supabaseClient;

const DISCUSS_I18N = {
  zh: {
    tabs: { qa: '问答', guides: '攻略', vote: '功能投票', news: '官方公告' },
    hints: { qa: '点箭头顶一下', guides: '视频 + 图文', vote: '点箭头即投票', news: '团队动态' },
    solved: '已解决',
    replies: (n) => `${n} 条回复`,
    replyBtn: '回答',
    replyPlaceholder: '写下你的回答，回车即发送…',
    send: '发送',
    addReply: '+ 加一条回答',
    askPlaceholder: '遇到问题？问一句，让会的人看见。',
    ask: '发问',
    asked: '已发布',
    voteHint: ['你希望下一个版本做什么？', ' 点箭头即投票。'],
    featurePlaceholder: '列表里没有？你还想要什么，直接写下来',
    submit: '提交',
    submitted: '已记录',
    video: '视频',
    readMore: '开始阅读',
    page: (cur, total) => `第 ${cur} / ${total} 页`,
  },
  en: {
    tabs: { qa: 'Q&A', guides: 'Guides', vote: 'Roadmap', news: 'News' },
    hints: { qa: 'Upvote to surface', guides: 'Videos + Articles', vote: 'Click arrow to vote', news: 'Team updates' },
    solved: 'Solved',
    replies: (n) => `${n} ${n === 1 ? 'reply' : 'replies'}`,
    replyBtn: 'Reply',
    replyPlaceholder: 'Write your answer, press enter to send…',
    send: 'Send',
    addReply: '+ Add a reply',
    askPlaceholder: 'Got a question? Ask the community.',
    ask: 'Ask',
    asked: 'Posted',
    voteHint: ['What should we build next?', ' Click the arrow to vote.'],
    featurePlaceholder: 'Not in the list? Tell us what you want',
    submit: 'Submit',
    submitted: 'Recorded',
    video: 'VIDEO',
    readMore: 'Read more',
    page: (cur, total) => `Page ${cur} of ${total}`,
  },
};

// ── Supabase 数据服务 ───────────────────────────────────────────

const DB = {
  // 问题列表 + 投票数 + 评论
  async fetchQuestions(userId) {
    const { data: questions, error } = await sb
      .from('questions')
      .select('*, comments(*)');
    if (error) throw error;

    // 获取所有相关用户的 profile（头像）
    const userIds = [...new Set((questions || []).map(q => q.user_id).filter(Boolean))];
    const profileMap = {};
    if (userIds.length > 0) {
      const { data: profiles } = await sb.from('profiles').select('id, avatar_url, nickname').in('id', userIds);
      (profiles || []).forEach(p => { profileMap[p.id] = p; });
    }

    // 获取投票数
    const { data: voteCounts } = await sb.from('question_vote_counts').select('*');
    const voteMap = {};
    (voteCounts || []).forEach(v => { voteMap[v.question_id] = v.votes; });

    // 当前用户的投票
    let myVotes = new Set();
    if (userId) {
      const { data: mv } = await sb.from('question_votes').select('question_id').eq('user_id', userId);
      (mv || []).forEach(v => myVotes.add(v.question_id));
    }

    return (questions || []).map(q => {
      const profile = profileMap[q.user_id];
      return {
      id: q.id,
      userId: q.user_id,
      author: (profile?.nickname) || q.author_name,
      initial: q.author_initial,
      hue: q.author_hue,
      avatarUrl: profile?.avatar_url || '',
      time: timeAgo(q.created_at),
      tag: q.tag,
      title: q.title,
      body: q.body,
      votes: voteMap[q.id] || 0,
      voted: myVotes.has(q.id),
      solved: q.solved,
      comments: (q.comments || [])
        .sort((a, b) => new Date(a.created_at) - new Date(b.created_at))
        .map(c => ({
          id: c.id,
          author: c.author_name,
          badge: c.badge,
          time: timeAgo(c.created_at),
          body: c.body,
        })),
    };}).sort((a, b) => b.votes - a.votes);
  },

  async createQuestion(userId, email, title, body, tag) {
    const name = email ? email.split('@')[0] : '匿名';
    const { data, error } = await sb.from('questions').insert({
      user_id: userId,
      author_name: name,
      author_initial: name.charAt(0),
      author_hue: (name.charCodeAt(0) % 60) + 140,
      tag: tag || '通用',
      title,
      body: body || '',
    }).select().single();
    if (error) throw error;
    // 自投一票
    await sb.from('question_votes').insert({ user_id: userId, question_id: data.id });
    return data;
  },

  async addComment(userId, email, questionId, body) {
    const name = email ? email.split('@')[0] : '匿名';
    const { error } = await sb.from('comments').insert({
      question_id: questionId,
      user_id: userId,
      author_name: name,
      body,
    });
    if (error) throw error;
  },

  async toggleQuestionVote(userId, questionId, currentlyVoted) {
    if (currentlyVoted) {
      await sb.from('question_votes').delete().eq('user_id', userId).eq('question_id', questionId);
    } else {
      await sb.from('question_votes').insert({ user_id: userId, question_id: questionId });
    }
  },

  // 功能请求
  async fetchFeatures(userId) {
    const { data: features, error } = await sb.from('feature_requests').select('*');
    if (error) throw error;

    // 获取创建者 profile
    const userIds = [...new Set((features || []).map(f => f.user_id).filter(Boolean))];
    const profileMap = {};
    if (userIds.length > 0) {
      const { data: profiles } = await sb.from('profiles').select('id, avatar_url, nickname').in('id', userIds);
      (profiles || []).forEach(p => { profileMap[p.id] = p; });
    }

    const { data: voteCounts } = await sb.from('feature_vote_counts').select('*');
    const voteMap = {};
    (voteCounts || []).forEach(v => { voteMap[v.feature_id] = v.votes; });

    let myVotes = new Set();
    if (userId) {
      const { data: mv } = await sb.from('feature_votes').select('feature_id').eq('user_id', userId);
      (mv || []).forEach(v => myVotes.add(v.feature_id));
    }

    return (features || []).map(f => {
      const profile = profileMap[f.user_id];
      const name = profile?.nickname || (f.user_id ? '匿名' : '');
      return {
        id: f.id,
        userId: f.user_id || null,
        title: f.title,
        desc: f.description,
        votes: voteMap[f.id] || 0,
        voted: myVotes.has(f.id),
        author: name,
        avatarUrl: profile?.avatar_url || '',
        initial: (name || f.title || '?').charAt(0),
        hue: (f.title || '').charCodeAt(0) % 60 + 140,
        time: timeAgo(f.created_at),
        createdAt: f.created_at,
      };
    }).sort((a, b) => b.votes - a.votes);
  },

  async toggleFeatureVote(userId, featureId, currentlyVoted) {
    if (currentlyVoted) {
      await sb.from('feature_votes').delete().eq('user_id', userId).eq('feature_id', featureId);
    } else {
      await sb.from('feature_votes').insert({ user_id: userId, feature_id: featureId });
    }
  },

  async submitFeatureRequest(userId, title) {
    const { data, error } = await sb.from('feature_requests').insert({
      title, description: '', user_id: userId,
    }).select().single();
    if (error) throw error;
    // 自投一票
    if (data) {
      await sb.from('feature_votes').insert({ user_id: userId, feature_id: data.id });
    }
    return data;
  },

  // 公告
  async fetchAnnouncements() {
    const { data, error } = await sb.from('announcements').select('*').order('created_at', { ascending: false });
    if (error) throw error;
    return (data || []).map(a => ({
      date: a.date_label,
      tag: a.tag,
      title: a.title,
      emerald: a.emerald,
    }));
  },
};

function timeAgo(dateStr) {
  const lang = window.__kiwvoLang || 'zh';
  const now = Date.now();
  const d = new Date(dateStr).getTime();
  const diff = now - d;
  const mins = Math.floor(diff / 60000);
  if (lang === 'en') {
    if (mins < 1) return 'just now';
    if (mins < 60) return `${mins}m ago`;
    const hours = Math.floor(mins / 60);
    if (hours < 24) return `${hours}h ago`;
    const days = Math.floor(hours / 24);
    if (days < 7) return `${days}d ago`;
    return new Date(dateStr).toLocaleDateString('en-US', { month: 'short', day: 'numeric' });
  }
  if (mins < 1) return '刚刚';
  if (mins < 60) return `${mins} 分钟前`;
  const hours = Math.floor(mins / 60);
  if (hours < 24) return `${hours} 小时前`;
  const days = Math.floor(hours / 24);
  if (days < 7) return `${days} 天前`;
  return new Date(dateStr).toLocaleDateString('zh-CN', { month: 'numeric', day: 'numeric' });
}

// ── 静态数据 (攻略不存数据库) ──────────────────────────────────

const OFFICIAL_GUIDE = {
  id: 'g0', type: 'official', emoji: '📖', min: 8, official: true,
  href: '/guides/official.html',
  title: 'kiwvo 官方使用手册',
  desc: '从下载安装到多平台推流开播的完整教程',
  chapters: [
    { label: '下载安装', anchor: '#install' },
    { label: '注册登录', anchor: '#login' },
    { label: '推流码配置', anchor: '#stream-key' },
    { label: '返佣码', anchor: '#referral' },
    { label: '一键开播', anchor: '#go-live' },
    { label: '常见问题', anchor: '#faq' },
  ],
};

const GUIDES = [
  OFFICIAL_GUIDE,
  { id: 'g1', type: 'video',   emoji: '\u26A1', duration: '3:42', hue: 160, title: '3 分钟开始你的第一场直播',         desc: '下载 → 登录 → 选游戏 → 开播。真的就这四步。', author: 'kiwvo 团队', views: '12.3K' },
  { id: 'g2', type: 'article', emoji: '\uD83C\uDF99', min: 5,           title: '把麦克风调到「听着舒服」的程度',        desc: '一键降噪、回声消除与音量监控的最简设置。' },
  { id: 'g3', type: 'video',   emoji: '\uD83C\uDFAE', duration: '6:15', hue: 175, title: '游戏 + 摄像头布局模板演示',         desc: '用内置模板替代手动拖画面，0 拖拽上直播。', author: '@pixel_mochi', views: '8.7K' },
  { id: 'g4', type: 'article', emoji: '\uD83D\uDCE1', min: 6,           title: 'Binance · OKX · Gate 推流密钥配置',   desc: '一次配置，多平台记忆，下次开播只需点一下。' },
  { id: 'g5', type: 'video',   emoji: '\uD83C\uDFAC', duration: '8:54', hue: 145, title: '场景切换与转场动效进阶',            desc: '让你的直播看起来像电视台。', author: '@深夜电台', views: '5.4K' },
  { id: 'g6', type: 'article', emoji: '\u2699\uFE0F', min: 4,           title: 'NVENC / x264 编码器选型指南',         desc: '不同显卡如何选最优编码器，参数推荐。' },
  { id: 'g7', type: 'video',   emoji: '\uD83D\uDCCA', duration: '4:08', hue: 190, title: 'OBS 老用户迁移到 kiwvo 全过程',    desc: '场景、热键、插件如何 1:1 复刻。', author: '@AkiraNoLight', views: '3.9K' },
  { id: 'g8', type: 'article', emoji: '\uD83C\uDF9A', min: 7,           title: '回声消除背后的算法与最佳实践',         desc: '深入讲一讲为什么 kiwvo 的人声更干净。' },
];

// ── 硬编码数据作为 fallback ─────────────────────────────────────

const FALLBACK_QUESTIONS = [
  {
    id: 'q1', author: '椰汁不加冰', initial: '椰', hue: 175, time: '2 小时前', tag: '音频',
    title: '推流时游戏声和麦克风声怎么分开录？',
    body: '想让回放里人声独立一轨方便后期剪辑，kiwvo 里有对应设置吗？',
    votes: 48, voted: false, solved: true,
    comments: [
      { id: 'c1', author: 'kiwvo 团队', badge: 'STAFF', time: '1 小时前', body: '设置 → 录制 → 打开「多音轨录制」即可。开播时两轨分别是 Track1（桌面）Track2（麦克风）。' },
      { id: 'c2', author: 'AkiraNoLight', time: '42 分钟前', body: '亲测有用，剪辑时在 DaVinci 里拆轨很方便。' },
    ],
  },
  {
    id: 'q2', author: 'pixel_mochi', initial: 'p', hue: 150, time: '昨天', tag: '画面',
    title: '4K 60 帧推流 B 站会掉码率吗？',
    body: '手头 3070，目前测试码率 12000 有时会卡。有人跑过稳定档位的参数分享一下？',
    votes: 31, voted: false, solved: false,
    comments: [
      { id: 'c3', author: 'NorthBound', time: '20 小时前', body: 'NVENC P5 + CQ19，B 站实测 10000~12000 稳定，再高就看上行带宽了。' },
    ],
  },
  {
    id: 'q3', author: '深夜电台', initial: '夜', hue: 145, time: '3 天前', tag: '场景',
    title: '切换场景时能加个平滑淡入淡出吗？',
    body: '现在切画面比较硬，希望有个 200ms 的过渡。',
    votes: 22, voted: false, solved: false, comments: [],
  },
];

const FALLBACK_FEATURES = [
  { id: 1, title: '原生支持 NDI 输入源',         desc: '局域网内接入 OBS 等其他软件画面',  votes: 2847, voted: false, author: '', initial: '原', hue: 160, time: '', userId: null, createdAt: null },
  { id: 2, title: '实时 AI 字幕 · 中英双语',     desc: '边播边生成，观众自选语言',         votes: 2143, voted: false, author: '', initial: '实', hue: 170, time: '', userId: null, createdAt: null },
  { id: 3, title: 'Twitch / YouTube 同时推流',   desc: '一次开播，多平台同步',             votes: 1902, voted: false, author: '', initial: 'T',  hue: 150, time: '', userId: null, createdAt: null },
  { id: 4, title: '场景切换热键手柄映射',         desc: '支持 Stream Deck 与 XBox 手柄',    votes: 1356, voted: false, author: '', initial: '场', hue: 145, time: '', userId: null, createdAt: null },
  { id: 5, title: '主播专用低延迟回声消除',       desc: '游戏声 + 人声更干净',              votes: 904,  voted: false, author: '', initial: '主', hue: 175, time: '', userId: null, createdAt: null },
  { id: 6, title: 'macOS 版本',                  desc: '我们听到了，正在路上',             votes: 712,  voted: false, author: '', initial: 'm',  hue: 155, time: '', userId: null, createdAt: null },
  { id: 7, title: '多机位画面同步切换',           desc: '主控 + 副机位场景联动',           votes: 588,  voted: false, author: '', initial: '多', hue: 165, time: '', userId: null, createdAt: null },
  { id: 8, title: 'AI 自动剪辑高光时刻',          desc: '直播结束自动产出 1 分钟集锦',     votes: 421,  voted: false, author: '', initial: 'A',  hue: 180, time: '', userId: null, createdAt: null },
];

const FALLBACK_ANNOUNCEMENTS = [
  { date: '04 · 22', tag: '版本', title: 'v2.4 发布 · 新增虚拟摄像头直出', emerald: true },
  { date: '04 · 18', tag: '社区', title: '创作者激励计划 S2 启动，报名截止 5/10' },
  { date: '04 · 12', tag: '修复', title: '修复部分 AMD 显卡下编码器掉帧' },
  { date: '04 · 05', tag: '版本', title: 'v2.3 · 引入场景镜像与多房间推流' },
  { date: '03 · 28', tag: '社区', title: '主播贡献值规则更新公告' },
];

// ── UI 组件 ─────────────────────────────────────────────────────

function Avatar({ initial, hue, size = 36, avatarUrl }) {
  if (avatarUrl) {
    return (
      <img
        src={avatarUrl}
        alt={initial}
        className="shrink-0 rounded-full object-cover"
        style={{ width: size, height: size }}
      />
    );
  }
  return (
    <div
      className="shrink-0 rounded-full flex items-center justify-center text-[13px] font-semibold text-emerald-100"
      style={{ width: size, height: size, background: `oklch(0.32 0.08 ${hue})` }}
    >
      {initial}
    </div>
  );
}

function LoadingSpinner() {
  return (
    <div className="flex items-center justify-center py-16">
      <svg className="animate-spin text-emerald-400/60" width="24" height="24" viewBox="0 0 24 24" fill="none">
        <circle cx="12" cy="12" r="9" stroke="currentColor" strokeWidth="2.5" opacity="0.25"/>
        <path d="M21 12a9 9 0 0 0-9-9" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round"/>
      </svg>
    </div>
  );
}

function QuestionCard({ q, onVote, onReply, t }) {
  const [expanded, setExpanded] = React.useState(false);
  const [replying, setReplying] = React.useState(false);
  const [draft, setDraft] = React.useState('');
  const [pulse, setPulse] = React.useState(false);
  const [submitting, setSubmitting] = React.useState(false);

  const handleVote = (e) => {
    e.stopPropagation();
    if (!q.voted) { setPulse(true); setTimeout(() => setPulse(false), 400); }
    onVote(q.id, q.voted);
  };

  const postReply = async (e) => {
    e.preventDefault();
    if (!draft.trim() || submitting) return;
    setSubmitting(true);
    await onReply(q.id, draft.trim());
    setDraft('');
    setReplying(false);
    setExpanded(true);
    setSubmitting(false);
  };

  return (
    <div className="rounded-xl bg-[#0F1E1A] border border-white/[0.04] hover:border-emerald-400/20 transition-colors overflow-hidden">
      <div className="flex gap-4 p-4">
        <div className="min-w-0 flex-1">
          <div className="flex items-center gap-2 mb-2">
            <button onClick={() => window.dispatchEvent(new CustomEvent('kiwvo:open-user-profile', { detail: {
              name: q.author, hue: q.hue, topic: '', tier: 0, viewers: '', platforms: [],
              avatarUrl: q.avatarUrl,
              social: { telegram: '', links: [] },
              userId: q.userId,
            } }))} className="flex items-center gap-2 hover:opacity-80 transition-opacity cursor-pointer">
              <Avatar initial={q.initial} hue={q.hue} size={28} avatarUrl={q.avatarUrl} />
              <span className="text-[14px] text-white/80 font-medium">{q.author}</span>
            </button>
            <span className="text-[11px] text-white/30 font-mono">{q.time}</span>
            <span className="text-[10px] font-mono tracking-[0.1em] px-1.5 py-0.5 rounded bg-white/[0.05] text-white/50 uppercase">{q.tag}</span>
            {q.solved && (
              <span className="inline-flex items-center gap-1 text-[10.5px] font-mono tracking-[0.1em] px-1.5 py-0.5 rounded bg-emerald-400/10 text-emerald-300/90 uppercase">
                <svg width="10" height="10" viewBox="0 0 24 24" fill="none">
                  <path d="M5 12.5l4.5 4.5L19 7.5" stroke="currentColor" strokeWidth="3" strokeLinecap="round" strokeLinejoin="round" />
                </svg>
                {t.solved}
              </span>
            )}
          </div>
          <h4 className="text-[15px] text-white font-medium leading-snug mb-1">{q.title}</h4>
          {q.body && <p className="text-[13px] text-white/55 leading-relaxed mb-3">{q.body}</p>}

          <div className="flex items-center gap-4 text-[12px]">
            <button
              onClick={() => setExpanded((v) => !v)}
              className="inline-flex items-center gap-1.5 text-white/50 hover:text-emerald-300 transition-colors"
            >
              <svg width="13" height="13" viewBox="0 0 24 24" fill="none">
                <path d="M21 12c0 4-4 7-9 7-1.5 0-2.9-.3-4.2-.8L3 20l1-4.2A7.2 7.2 0 0 1 3 12c0-4 4-7 9-7s9 3 9 7z" stroke="currentColor" strokeWidth="1.6" strokeLinejoin="round" />
              </svg>
              <span>{t.replies(q.comments.length)}</span>
              <svg width="11" height="11" viewBox="0 0 24 24" fill="none" className={`transition-transform ${expanded ? 'rotate-180' : ''}`}>
                <path d="M6 9l6 6 6-6" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
              </svg>
            </button>
            <button
              onClick={() => { setReplying(true); setExpanded(true); }}
              className="inline-flex items-center gap-1.5 text-white/50 hover:text-emerald-300 transition-colors"
            >
              <svg width="13" height="13" viewBox="0 0 24 24" fill="none">
                <path d="M4 7h12a4 4 0 0 1 4 4v0a4 4 0 0 1-4 4H8l-4 3V7z" stroke="currentColor" strokeWidth="1.6" strokeLinejoin="round" />
              </svg>
              <span>{t.replyBtn}</span>
            </button>
          </div>
        </div>

        <button
          onClick={handleVote}
          className={`shrink-0 w-12 h-[60px] rounded-lg flex flex-col items-center justify-center border transition-all duration-200 ${
            q.voted
              ? 'bg-emerald-500/12 border-emerald-400/40 text-emerald-300'
              : 'bg-white/[0.02] border-white/[0.07] text-white/50 hover:text-emerald-300 hover:border-emerald-400/30 hover:bg-emerald-400/[0.05]'
          } ${pulse ? 'scale-[1.08]' : ''}`}
        >
          <svg width="14" height="14" viewBox="0 0 24 24" fill="none">
            <path d="M12 5l7 8h-4v6h-6v-6H5l7-8z" fill={q.voted ? 'currentColor' : 'none'} stroke="currentColor" strokeWidth="1.8" strokeLinejoin="round" />
          </svg>
          <span className={`text-[11.5px] font-semibold font-mono tabular-nums mt-0.5 ${q.voted ? 'text-emerald-300' : 'text-white/70'}`}>
            {q.votes}
          </span>
        </button>
      </div>

      {expanded && (
        <div className="border-t border-white/[0.05] bg-[#0A1512]/50 px-4 pt-4 pb-4 pl-4 animate-[fadeIn_0.15s_ease]">
          {q.comments.length > 0 && (
            <div className="space-y-3 mb-3">
              {q.comments.map((c) => (
                <div key={c.id} className="flex gap-3">
                  <Avatar initial={c.author.slice(0, 1)} hue={c.badge === 'STAFF' ? 160 : 170} size={28} />
                  <div className="min-w-0 flex-1">
                    <div className="flex items-center gap-2 mb-0.5">
                      <span className="text-[12.5px] text-white/80 font-medium">{c.author}</span>
                      {c.badge && (
                        <span className="text-[9.5px] font-mono tracking-[0.14em] px-1.5 py-0.5 rounded bg-emerald-400/12 text-emerald-300">{c.badge}</span>
                      )}
                      <span className="text-[11px] text-white/30 font-mono">{c.time}</span>
                    </div>
                    <p className="text-[13px] text-white/70 leading-relaxed">{c.body}</p>
                  </div>
                </div>
              ))}
            </div>
          )}

          {replying ? (
            <form onSubmit={postReply} className="flex items-center gap-2 p-1.5 rounded-lg bg-[#0F1E1A] border border-white/[0.08] focus-within:border-emerald-400/40 focus-within:shadow-[0_0_0_3px_rgba(16,185,129,0.08)] transition-all">
              <input
                autoFocus
                value={draft}
                onChange={(e) => setDraft(e.target.value)}
                placeholder={t.replyPlaceholder}
                className="flex-1 bg-transparent outline-none text-[13px] text-white placeholder:text-white/30 px-2 py-1.5"
              />
              <button
                type="submit"
                disabled={!draft.trim() || submitting}
                className={`px-3 h-8 rounded-md text-[12px] font-semibold transition-all inline-flex items-center gap-1.5 ${
                  draft.trim() && !submitting ? 'bg-emerald-500 hover:bg-emerald-400 text-[#052E21]' : 'bg-white/[0.04] text-white/30 cursor-not-allowed'
                }`}
              >
                {submitting ? (
                  <svg className="animate-spin" width="12" height="12" viewBox="0 0 24 24" fill="none">
                    <circle cx="12" cy="12" r="9" stroke="currentColor" strokeWidth="2.5" opacity="0.25"/>
                    <path d="M21 12a9 9 0 0 0-9-9" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round"/>
                  </svg>
                ) : t.send}
              </button>
            </form>
          ) : (
            <button onClick={() => setReplying(true)} className="text-[12px] text-white/40 hover:text-emerald-300 transition-colors">
              {t.addReply}
            </button>
          )}
        </div>
      )}
    </div>
  );
}

function QATab({ items, onVote, onReply, onAsk, onCheckAuth, t }) {
  const [ask, setAsk] = React.useState('');
  const [asked, setAsked] = React.useState(false);
  const [posting, setPosting] = React.useState(false);
  const inputRef = React.useRef(null);

  const handleInputFocus = () => {
    if (onCheckAuth && !onCheckAuth()) {
      inputRef.current?.blur();
    }
  };

  const postQuestion = async (e) => {
    e.preventDefault();
    if (!ask.trim() || posting) return;
    setPosting(true);
    await onAsk(ask.trim());
    setAsk('');
    setAsked(true);
    setPosting(false);
    setTimeout(() => setAsked(false), 1800);
  };

  return (
    <div>
      <form
        onSubmit={postQuestion}
        className="relative flex items-center gap-2 p-1.5 rounded-xl bg-[#0F1E1A] border border-white/[0.06] focus-within:border-emerald-400/40 focus-within:shadow-[0_0_0_4px_rgba(16,185,129,0.08)] transition-all mb-5"
      >
        <div className="pl-3 text-white/35">
          <svg width="16" height="16" viewBox="0 0 24 24" fill="none">
            <path d="M9.1 9a3 3 0 1 1 4.8 2.4c-.8.6-1.9 1-1.9 2v.6M12 17.5h.01" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" />
            <circle cx="12" cy="12" r="9" stroke="currentColor" strokeWidth="1.4" />
          </svg>
        </div>
        <input
          ref={inputRef}
          value={ask}
          onChange={(e) => setAsk(e.target.value)}
          onFocus={handleInputFocus}
          placeholder={t.askPlaceholder}
          className="flex-1 bg-transparent outline-none text-[14px] text-white placeholder:text-white/30 py-2"
        />
        <button
          type="submit"
          disabled={!ask.trim() || posting}
          className={`px-4 h-10 rounded-lg text-[13px] font-semibold transition-all inline-flex items-center gap-2 ${
            ask.trim() && !posting
              ? 'bg-emerald-500 hover:bg-emerald-400 text-[#052E21] shadow-[0_4px_20px_-4px_rgba(16,185,129,0.5)]'
              : 'bg-white/[0.04] text-white/30 cursor-not-allowed'
          }`}
        >
          {posting ? (
            <svg className="animate-spin" width="14" height="14" viewBox="0 0 24 24" fill="none">
              <circle cx="12" cy="12" r="9" stroke="currentColor" strokeWidth="2.5" opacity="0.25"/>
              <path d="M21 12a9 9 0 0 0-9-9" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round"/>
            </svg>
          ) : t.ask}
        </button>
        {asked && (
          <div className="absolute -bottom-7 right-0 flex items-center gap-1.5 text-[12px] text-emerald-300 font-mono tracking-wide animate-[fadeIn_0.2s_ease]">
            <svg width="12" height="12" viewBox="0 0 24 24" fill="none">
              <path d="M5 12.5l4.5 4.5L19 7.5" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round" />
            </svg>
            {t.asked}
          </div>
        )}
      </form>
      <div className="space-y-2.5">
        {items.map((q) => <QuestionCard key={q.id} q={q} onVote={onVote} onReply={onReply} t={t} />)}
      </div>
    </div>
  );
}

function FeatureCard({ f, onVote }) {
  const [pulse, setPulse] = React.useState(false);
  const handleVote = (e) => {
    e.stopPropagation();
    if (!f.voted) { setPulse(true); setTimeout(() => setPulse(false), 400); }
    onVote(f.id, f.voted);
  };

  return (
    <div className="rounded-xl bg-[#0F1E1A] border border-white/[0.04] hover:border-emerald-400/20 transition-colors overflow-hidden">
      <div className="flex gap-4 p-4">
        <div className="min-w-0 flex-1">
          {f.author ? (
            <div className="flex items-center gap-2 mb-2">
              <Avatar initial={f.initial} hue={f.hue} size={28} avatarUrl={f.avatarUrl} />
              <span className="text-[14px] text-white/80 font-medium">{f.author}</span>
              <span className="text-[11px] text-white/30 font-mono">{f.time}</span>
            </div>
          ) : f.time ? (
            <div className="flex items-center gap-2 mb-2">
              <span className="text-[11px] text-white/30 font-mono">{f.time}</span>
            </div>
          ) : null}
          <h4 className="text-[15px] text-white font-medium leading-snug mb-1">{f.title}</h4>
          {f.desc && <p className="text-[13px] text-white/55 leading-relaxed">{f.desc}</p>}
        </div>

        <button
          onClick={handleVote}
          className={`shrink-0 w-12 h-[60px] rounded-lg flex flex-col items-center justify-center border transition-all duration-200 ${
            f.voted
              ? 'bg-emerald-500/12 border-emerald-400/40 text-emerald-300'
              : 'bg-white/[0.02] border-white/[0.07] text-white/50 hover:text-emerald-300 hover:border-emerald-400/30 hover:bg-emerald-400/[0.05]'
          } ${pulse ? 'scale-[1.08]' : ''}`}
        >
          <svg width="14" height="14" viewBox="0 0 24 24" fill="none">
            <path d="M12 5l7 8h-4v6h-6v-6H5l7-8z" fill={f.voted ? 'currentColor' : 'none'} stroke="currentColor" strokeWidth="1.8" strokeLinejoin="round" />
          </svg>
          <span className={`text-[11.5px] font-semibold font-mono tabular-nums mt-0.5 ${f.voted ? 'text-emerald-300' : 'text-white/70'}`}>
            {f.votes}
          </span>
        </button>
      </div>
    </div>
  );
}

function VoteTab({ items, onVote, voteCount, totalCount, onSubmitFeature, onCheckAuth, t }) {
  const [feedback, setFeedback] = React.useState('');
  const [submitted, setSubmitted] = React.useState(false);
  const [posting, setPosting] = React.useState(false);
  const inputRef = React.useRef(null);

  const handleInputFocus = () => {
    if (onCheckAuth && !onCheckAuth()) {
      inputRef.current?.blur();
    }
  };

  const submit = async (e) => {
    e.preventDefault();
    if (!feedback.trim() || posting) return;
    setPosting(true);
    await onSubmitFeature(feedback.trim());
    setPosting(false);
    setSubmitted(true);
    setFeedback('');
    setTimeout(() => setSubmitted(false), 2200);
  };

  return (
    <div>
      <div className="flex items-baseline justify-between mb-3">
        <p className="text-[13px] text-white/55">{t.voteHint[0]}<span className="text-white/35">{t.voteHint[1]}</span></p>
        <span className="text-[11.5px] text-white/35 font-mono tracking-wide">{voteCount} / {totalCount} VOTED</span>
      </div>
      <form
        onSubmit={submit}
        className="relative flex items-center gap-2 p-1.5 rounded-xl bg-[#0F1E1A] border border-white/[0.06] focus-within:border-emerald-400/40 focus-within:shadow-[0_0_0_4px_rgba(16,185,129,0.08)] transition-all mb-5"
      >
        <div className="pl-3 text-white/35">
          <svg width="16" height="16" viewBox="0 0 24 24" fill="none">
            <path d="M12 3a9 9 0 1 0 9 9h-9V3z" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" />
            <path d="M13 3a9 9 0 0 1 8 8h-8V3z" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" />
          </svg>
        </div>
        <input
          ref={inputRef}
          value={feedback}
          onChange={(e) => setFeedback(e.target.value)}
          onFocus={handleInputFocus}
          placeholder={t.featurePlaceholder}
          className="flex-1 bg-transparent outline-none text-[14px] text-white placeholder:text-white/30 py-2"
        />
        <button
          type="submit"
          disabled={!feedback.trim() || posting}
          className={`px-4 h-10 rounded-lg text-[13px] font-semibold transition-all inline-flex items-center gap-2 ${
            feedback.trim() && !posting
              ? 'bg-emerald-500 hover:bg-emerald-400 text-[#052E21] shadow-[0_4px_20px_-4px_rgba(16,185,129,0.5)]'
              : 'bg-white/[0.04] text-white/30 cursor-not-allowed'
          }`}
        >
          {posting ? (
            <svg className="animate-spin" width="14" height="14" viewBox="0 0 24 24" fill="none">
              <circle cx="12" cy="12" r="9" stroke="currentColor" strokeWidth="2.5" opacity="0.25"/>
              <path d="M21 12a9 9 0 0 0-9-9" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round"/>
            </svg>
          ) : t.submit}
        </button>
        {submitted && (
          <div className="absolute -bottom-7 right-0 flex items-center gap-1.5 text-[12px] text-emerald-300 font-mono tracking-wide animate-[fadeIn_0.2s_ease]">
            <svg width="12" height="12" viewBox="0 0 24 24" fill="none">
              <path d="M5 12.5l4.5 4.5L19 7.5" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round" />
            </svg>
            {t.submitted}
          </div>
        )}
      </form>
      <div className="space-y-2.5">
        {items.map((f) => <FeatureCard key={f.id} f={f} onVote={onVote} />)}
      </div>
    </div>
  );
}

function AnnouncementsTab({ items }) {
  return (
    <ol className="relative border-l border-white/[0.07] pl-6 space-y-5 pt-1">
      {items.map((a, i) => (
        <li key={i} className="relative group">
          <span className={`absolute -left-[29px] top-1.5 w-2.5 h-2.5 rounded-full ring-4 ring-[#0A1512] ${
            a.emerald ? 'bg-emerald-400' : 'bg-white/25 group-hover:bg-emerald-400/70 transition-colors'
          }`} />
          <div className="flex items-center gap-2.5 mb-1.5">
            <span className="text-[11px] text-white/35 font-mono tracking-[0.1em]">{a.date}</span>
            <span className={`text-[10px] font-mono tracking-[0.12em] px-1.5 py-0.5 rounded ${
              a.tag === '版本' ? 'bg-emerald-400/10 text-emerald-300/90' : 'bg-white/[0.05] text-white/50'
            }`}>{a.tag.toUpperCase()}</span>
          </div>
          <a href="#" onClick={(e) => e.preventDefault()} className="block text-[14.5px] text-white/85 hover:text-emerald-300 transition-colors leading-snug">{a.title}</a>
        </li>
      ))}
    </ol>
  );
}

function GuideRow({ g }) {
  const isVideo = g.type === 'video';
  const isOfficial = g.official;
  const href = g.href || '#';

  return (
    <a
      href={href}
      target={g.href ? '_blank' : undefined}
      rel={g.href ? 'noopener' : undefined}
      onClick={g.href ? undefined : (e) => e.preventDefault()}
      className={`group flex items-center gap-4 px-4 py-3.5 rounded-xl border transition-colors ${
        isOfficial
          ? 'bg-emerald-500/[0.04] border-emerald-400/15 hover:border-emerald-400/35 hover:bg-emerald-500/[0.07]'
          : 'bg-[#0F1E1A] border-white/[0.04] hover:border-emerald-400/20 hover:bg-emerald-400/[0.02]'
      }`}
    >
      {/* Icon */}
      <div className={`shrink-0 w-9 h-9 rounded-lg flex items-center justify-center text-[16px] ${
        isOfficial ? 'bg-emerald-400/10 border border-emerald-400/20' : 'bg-white/[0.03] border border-white/[0.06]'
      }`}>
        {g.emoji}
      </div>

      {/* Title + desc */}
      <div className="min-w-0 flex-1">
        <div className="flex items-center gap-2">
          <span className={`text-[14px] font-medium truncate group-hover:text-emerald-300 transition-colors ${isOfficial ? 'text-white' : 'text-white/90'}`}>{g.title}</span>
          {isOfficial && <span className="shrink-0 text-[8px] font-mono tracking-[0.15em] px-1.5 py-0.5 rounded bg-emerald-400/15 text-emerald-300 uppercase border border-emerald-400/20">Official</span>}
        </div>
        <div className="text-[12px] text-white/40 truncate mt-0.5">{g.desc}</div>
      </div>

      {/* Meta: type + duration/min */}
      <div className="shrink-0 flex items-center gap-3">
        {isVideo ? (
          <span className="inline-flex items-center gap-1.5 text-[11px] text-emerald-300/60 font-mono">
            <svg width="10" height="10" viewBox="0 0 24 24" fill="currentColor" className="text-emerald-400/50"><path d="M8 5v14l11-7z" /></svg>
            {g.duration}
          </span>
        ) : (
          <span className="text-[11px] text-white/30 font-mono">{g.min} min</span>
        )}
        {g.views && <span className="text-[11px] text-white/25 font-mono">{g.views}</span>}
        <svg width="14" height="14" viewBox="0 0 24 24" fill="none" className="text-white/20 group-hover:text-emerald-400/60 transition-colors">
          <path d="M9 6l6 6-6 6" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
        </svg>
      </div>
    </a>
  );
}

function GuidesTab({ items }) {
  return (
    <div className="space-y-1.5">
      {items.map((g) => <GuideRow key={g.id} g={g} />)}
    </div>
  );
}

// ── 主组件 ──────────────────────────────────────────────────────

function DiscussBlock() {
  const [lang] = useLang();
  const t = DISCUSS_I18N[lang] || DISCUSS_I18N.zh;
  const [tab, setTab] = React.useState('qa');
  const [page, setPage] = React.useState({ qa: 0, guides: 0, news: 0, vote: 0 });
  const [questions, setQuestions] = React.useState(FALLBACK_QUESTIONS);
  const [features, setFeatures] = React.useState(FALLBACK_FEATURES);
  const [announcements, setAnnouncements] = React.useState(FALLBACK_ANNOUNCEMENTS);
  const [loadingData, setLoadingData] = React.useState(true);
  const [dbReady, setDbReady] = React.useState(false);
  const { user, requireAuth, prompt } = useRequireAuth();

  // Returns true if user is logged in; if not, triggers login prompt and returns false
  const checkAuth = React.useCallback(() => {
    if (user) return true;
    // Trigger the auth trigger button to open login modal
    document.querySelector('[data-auth-trigger]')?.click();
    return false;
  }, [user]);

  // 从数据库加载数据
  const loadData = React.useCallback(async () => {
    try {
      const userId = user?.id;
      const [q, f, a] = await Promise.all([
        DB.fetchQuestions(userId),
        DB.fetchFeatures(userId),
        DB.fetchAnnouncements(),
      ]);
      if (q.length > 0) setQuestions(q);
      if (f.length > 0) setFeatures(f);
      if (a.length > 0) setAnnouncements(a);
      setDbReady(true);
    } catch (err) {
      console.warn('Supabase 加载失败，使用本地数据:', err.message);
    } finally {
      setLoadingData(false);
    }
  }, [user?.id]);

  React.useEffect(() => { loadData(); }, [loadData]);

  // ── 操作 handlers ──────────────────────────────────────────

  const toggleVote = requireAuth(async (qId, currentlyVoted) => {
    // 乐观更新
    setQuestions(prev => prev.map(q =>
      q.id === qId ? { ...q, voted: !q.voted, votes: q.voted ? q.votes - 1 : q.votes + 1 } : q
    ));
    try {
      await DB.toggleQuestionVote(user.id, qId, currentlyVoted);
    } catch (err) {
      // 回滚
      setQuestions(prev => prev.map(q =>
        q.id === qId ? { ...q, voted: currentlyVoted, votes: currentlyVoted ? q.votes + 1 : q.votes - 1 } : q
      ));
      console.error('投票失败:', err);
    }
  });

  const addReply = requireAuth(async (qId, body) => {
    const tempComment = {
      id: `temp-${Date.now()}`,
      author: user.email?.split('@')[0] || '你',
      badge: null,
      time: '刚刚',
      body,
    };
    // 乐观更新
    setQuestions(prev => prev.map(q =>
      q.id === qId ? { ...q, comments: [...q.comments, tempComment] } : q
    ));
    try {
      await DB.addComment(user.id, user.email, qId, body);
      // 重新加载以获取真实 ID
      if (dbReady) {
        const fresh = await DB.fetchQuestions(user.id);
        if (fresh.length > 0) setQuestions(fresh);
      }
    } catch (err) {
      console.error('评论失败:', err);
    }
  });

  const askQuestion = requireAuth(async (title) => {
    const tempQ = {
      id: `temp-${Date.now()}`,
      author: user.email?.split('@')[0] || '你',
      initial: (user.email?.charAt(0) || '?').toUpperCase(),
      hue: 165,
      time: '刚刚',
      tag: '新',
      title,
      body: '',
      votes: 1,
      voted: true,
      solved: false,
      comments: [],
    };
    setQuestions(prev => [tempQ, ...prev]);
    setPage(p => ({ ...p, qa: 0 }));
    try {
      await DB.createQuestion(user.id, user.email, title, '', '新');
      if (dbReady) {
        const fresh = await DB.fetchQuestions(user.id);
        if (fresh.length > 0) setQuestions(fresh);
      }
    } catch (err) {
      console.error('提问失败:', err);
    }
  });

  const toggleFeatureVote = requireAuth(async (fId, currentlyVoted) => {
    setFeatures(prev => prev.map(f =>
      f.id === fId ? { ...f, voted: !f.voted, votes: f.voted ? f.votes - 1 : f.votes + 1 } : f
    ));
    try {
      await DB.toggleFeatureVote(user.id, fId, currentlyVoted);
    } catch (err) {
      setFeatures(prev => prev.map(f =>
        f.id === fId ? { ...f, voted: currentlyVoted, votes: currentlyVoted ? f.votes + 1 : f.votes - 1 } : f
      ));
      console.error('功能投票失败:', err);
    }
  });

  const submitFeature = requireAuth(async (title) => {
    // 乐观更新：自己的新条目置顶
    const tempF = {
      id: `temp-${Date.now()}`,
      userId: user.id,
      title,
      desc: '',
      votes: 1,
      voted: true,
      author: user.email?.split('@')[0] || '你',
      initial: (user.email?.charAt(0) || '?').toUpperCase(),
      hue: 165,
      avatarUrl: '',
      time: '刚刚',
      createdAt: new Date().toISOString(),
    };
    setFeatures(prev => [tempF, ...prev]);
    setPage(p => ({ ...p, vote: 0 }));
    try {
      await DB.submitFeatureRequest(user.id, title);
      if (dbReady) {
        const fresh = await DB.fetchFeatures(user.id);
        if (fresh.length > 0) setFeatures(fresh);
      }
    } catch (err) {
      console.error('提交功能请求失败:', err);
    }
  });

  // ── 分页 ──────────────────────────────────────────────────

  const sortedFeatures = React.useMemo(() => {
    const uid = user?.id;
    return [...features].sort((a, b) => {
      const aMe = uid && a.userId === uid;
      const bMe = uid && b.userId === uid;
      if (aMe && !bMe) return -1;
      if (!aMe && bMe) return 1;
      if (aMe && bMe) return new Date(b.createdAt || 0) - new Date(a.createdAt || 0);
      return b.votes - a.votes;
    });
  }, [features, user?.id]);

  const PAGE_SIZE = { qa: 3, guides: 6, news: 5, vote: 4 };
  const sources = { qa: questions, guides: GUIDES, news: announcements, vote: sortedFeatures };
  const total = sources[tab].length;
  const size = PAGE_SIZE[tab];
  const totalPages = Math.max(1, Math.ceil(total / size));
  const currentPage = Math.min(page[tab], totalPages - 1);
  const start = currentPage * size;
  const visibleItems = sources[tab].slice(start, start + size);

  const setTabPage = (id) => setPage((p) => ({ ...p, [tab]: Math.max(0, Math.min(totalPages - 1, id)) }));

  const tabs = [
    { id: 'qa',     label: t.tabs.qa,    count: questions.length },
    { id: 'guides', label: t.tabs.guides, count: GUIDES.length },
    { id: 'vote',   label: t.tabs.vote,  count: features.length },
    { id: 'news',   label: t.tabs.news,  count: announcements.length },
  ];

  return (
    <div>
      {prompt}
      <div className="flex items-baseline justify-between mb-5">
        <div className="inline-flex items-center gap-0.5 p-1 rounded-lg bg-white/[0.03] border border-white/[0.05]">
          {tabs.map((t) => (
            <button
              key={t.id}
              onClick={() => setTab(t.id)}
              className={`relative h-8 px-4 rounded-md text-[13px] font-medium transition-colors ${
                tab === t.id ? 'bg-[#0A1512] text-white shadow-[inset_0_0_0_1px_rgba(16,185,129,0.2)]' : 'text-white/45 hover:text-white/80'
              }`}
            >
              {t.label}
              <span className={`ml-1.5 text-[11px] font-mono ${tab === t.id ? 'text-emerald-300/80' : 'text-white/30'}`}>{t.count}</span>
            </button>
          ))}
        </div>
        <div className="flex items-center gap-3">
          {dbReady && (
            <span className="inline-flex items-center gap-1 text-[10px] text-emerald-400/50 font-mono">
              <span className="w-1.5 h-1.5 rounded-full bg-emerald-400/60" />
              LIVE
            </span>
          )}
          <span className="text-[11.5px] text-white/35 font-mono tracking-wide">
            {t.hints[tab]}
          </span>
        </div>
      </div>

      {loadingData && tab !== 'guides' ? (
        <LoadingSpinner />
      ) : (
        <>
          {tab === 'qa' && <QATab items={visibleItems} onVote={toggleVote} onReply={addReply} onAsk={askQuestion} onCheckAuth={checkAuth} t={t} />}
          {tab === 'guides' && <GuidesTab items={visibleItems} />}
          {tab === 'vote' && <VoteTab items={visibleItems} onVote={toggleFeatureVote} voteCount={features.filter(f => f.voted).length} totalCount={features.length} onSubmitFeature={submitFeature} onCheckAuth={checkAuth} t={t} />}
          {tab === 'news' && <AnnouncementsTab items={visibleItems} />}
        </>
      )}

      {totalPages > 1 && (
        <div className="mt-6 flex items-center justify-between flex-wrap gap-3">
          <div className="flex items-center gap-1 text-[12px] font-mono">
            <button onClick={() => setTabPage(currentPage - 1)} disabled={currentPage === 0} className="w-8 h-8 rounded-md border border-white/[0.06] text-white/55 hover:text-white hover:border-emerald-400/30 hover:bg-emerald-400/[0.06] disabled:opacity-30 disabled:cursor-not-allowed transition-all flex items-center justify-center">
              <svg width="13" height="13" viewBox="0 0 24 24" fill="none"><path d="M15 6l-6 6 6 6" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" /></svg>
            </button>
            {Array.from({ length: totalPages }).map((_, i) => (
              <button key={i} onClick={() => setTabPage(i)} className={`w-8 h-8 rounded-md text-[12px] tabular-nums transition-all ${i === currentPage ? 'bg-emerald-400/12 text-emerald-300 border border-emerald-400/30' : 'text-white/45 hover:text-white border border-transparent hover:border-white/10'}`}>
                {i + 1}
              </button>
            ))}
            <button onClick={() => setTabPage(currentPage + 1)} disabled={currentPage >= totalPages - 1} className="w-8 h-8 rounded-md border border-white/[0.06] text-white/55 hover:text-white hover:border-emerald-400/30 hover:bg-emerald-400/[0.06] disabled:opacity-30 disabled:cursor-not-allowed transition-all flex items-center justify-center">
              <svg width="13" height="13" viewBox="0 0 24 24" fill="none"><path d="M9 6l6 6-6 6" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" /></svg>
            </button>
            <span className="text-white/35 ml-2">{t.page(currentPage + 1, totalPages)}</span>
          </div>
        </div>
      )}
    </div>
  );
}

window.DiscussBlock = DiscussBlock;
