// =========================================================
// FBIF 资讯订阅 · Timeline view (核心界面 · 真·时间线)
// Centered, readable feed on a vertical time axis.
// Date dividers + per-card timestamp dots + connecting line.
// Click a card → opens the reader preview (handled in App).
// =========================================================

// segmented control (shared)
const Seg = ({ value, onChange, options, size = 28 }) => (
  <div style={{ display: 'inline-flex', background: '#F2F3F5', padding: 2, borderRadius: 6, gap: 2 }}>
    {options.map(o => {
      const active = value === o.value;
      return (
        <button key={o.value} onClick={() => onChange(o.value)}
          style={{
            height: size - 4, padding: '0 12px', border: 'none', background: active ? '#fff' : 'transparent',
            fontFamily: 'inherit', fontSize: 13, color: active ? '#1F2329' : '#646A73',
            fontWeight: active ? 500 : 400, borderRadius: 4, cursor: 'pointer',
            boxShadow: active ? '0 1px 2px rgba(31,35,41,.06)' : 'none',
            display: 'inline-flex', alignItems: 'center', gap: 5, transition: 'background-color .15s',
          }}>
          {o.icon && <Icon name={o.icon} size={13} />}
          {o.label}
          {o.count != null && <span style={{ fontFamily: 'var(--font-mono)', fontSize: 11, opacity: .7 }}>{o.count}</span>}
        </button>
      );
    })}
  </div>
);

function clock(iso) {
  const d = new Date(iso);
  const p = n => String(n).padStart(2, '0');
  return `${p(d.getHours())}:${p(d.getMinutes())}`;
}
function dayLabel(iso) {
  const d = new Date(iso);
  const today = new Date();
  const yest = new Date(); yest.setDate(today.getDate() - 1);
  const same = (a, b) => a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();
  const wd = ['周日','周一','周二','周三','周四','周五','周六'][d.getDay()];
  const md = `${d.getMonth() + 1} 月 ${d.getDate()} 日`;
  if (same(d, today)) return `今天 · ${md} ${wd}`;
  if (same(d, yest)) return `昨天 · ${md} ${wd}`;
  return `${md} ${wd}`;
}

// ---- timeline card ----
const TLCard = ({ entry, active, onOpen, compact = false, narrow = false }) => {
  const [hover, setHover] = React.useState(false);
  const [focus, setFocus] = React.useState(false);
  const tags = entry.tags.map(id => window.FBIF_DATA.TAGS.find(t => t.id === id)).filter(Boolean);
  const indexMode = compact || narrow;
  const sourceMax = indexMode ? 120 : 180;
  const handleKey = (e) => {
    if (e.key === 'Enter' || e.key === ' ') {
      e.preventDefault();
      onOpen(entry);
    }
  };
  return (
    <article role="button" tabIndex={0} aria-label={`打开文章：${entry.title}`} onClick={() => onOpen(entry)} onKeyDown={handleKey}
      onMouseEnter={() => setHover(true)} onMouseLeave={() => setHover(false)}
      onFocus={() => setFocus(true)} onBlur={() => setFocus(false)}
      style={{
        position: 'relative', border: '1px solid', borderColor: active ? '#A8C3FB' : hover ? '#C9CDD4' : '#E5E6EB',
        borderRadius: 8, background: active ? '#F7FAFF' : '#fff', padding: indexMode ? '10px 12px' : '12px 14px', cursor: 'pointer',
        transition: 'border-color .15s, background-color .15s, box-shadow .15s',
        boxShadow: focus ? '0 0 0 3px rgba(20,86,240,.14)' : hover ? '0 2px 8px rgba(31,35,41,.05)' : 'none',
      }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 7, minWidth: 0, marginBottom: 6 }}>
        <SourceMark short={entry.source_short} color={entry.source_color} size={18} radius={5} />
        <span style={{ fontSize: 12, color: '#1F2329', fontWeight: 500, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis', maxWidth: sourceMax }}>
          {entry.source_name.replace(/\s*Newsroom/, '')}
        </span>
        {!narrow && <SourceTypeChip type={entry.source_type} />}
        {!narrow && <TierTag tier={entry.source_tier} compact />}
        <span style={{ flex: 1 }} />
        {!indexMode && entry.quality_score != null && <QualityScore score={entry.quality_score} />}
      </div>

      <h3 style={{ fontSize: indexMode ? 14 : 15, lineHeight: indexMode ? '21px' : '22px', fontWeight: 500, color: '#1F2329', margin: 0, textWrap: 'pretty',
                   display: '-webkit-box', WebkitLineClamp: indexMode ? 3 : 2, WebkitBoxOrient: 'vertical', overflow: 'hidden' }}>
        {entry.title}
      </h3>

      {!indexMode && (
        <p style={{ fontSize: 13, lineHeight: '20px', color: '#646A73', margin: '5px 0 0', textWrap: 'pretty',
                    display: '-webkit-box', WebkitLineClamp: 1, WebkitBoxOrient: 'vertical', overflow: 'hidden' }}>
          {entry.summary}
        </p>
      )}

      {!indexMode && <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginTop: 7, minWidth: 0 }}>
        {tags.slice(0, 3).map(t => (
          <span key={t.id} style={{ display: 'inline-flex', alignItems: 'center', gap: 4, fontSize: 12, color: '#646A73' }}>
            <span style={{ width: 6, height: 6, borderRadius: 9999, background: t.color }} />{t.name}
          </span>
        ))}
        {entry.related > 0 && (
          <span style={{ display: 'inline-flex', alignItems: 'center', gap: 4, fontSize: 12, color: '#8F959E' }}>
            <Icon name="git-merge" size={13} />关联讨论 {entry.related} 条
          </span>
        )}
        <span style={{ flex: 1 }} />
        {entry.is_featured && <span title="精选" style={{ color: '#1456F0', display: 'inline-flex' }}><Icon name="sparkles" size={13} /></span>}
      </div>}
    </article>
  );
};

// ---- axis row (timestamp + dot + line) wrapping a card ----
const AxisRow = ({ entry, last, children, compact = false }) => (
  <div style={{ display: 'flex', gap: compact ? 10 : 12, position: 'relative' }}>
    <div style={{ width: compact ? 40 : 48, flexShrink: 0, display: 'flex', flexDirection: 'column', alignItems: 'center', paddingTop: compact ? 12 : 14 }}>
      <span style={{ fontFamily: 'var(--font-mono)', fontSize: compact ? 11 : 12, color: '#646A73', lineHeight: 1 }}>{clock(entry.published_at)}</span>
      <span style={{ width: compact ? 8 : 9, height: compact ? 8 : 9, borderRadius: 9999, marginTop: 8, flexShrink: 0,
        background: '#1456F0', border: '2px solid #1456F0' }} />
      {!last && <span style={{ flex: 1, width: 2, background: '#E5E6EB', marginTop: 4, minHeight: 20 }} />}
    </div>
    <div style={{ flex: 1, minWidth: 0, paddingBottom: last ? 0 : (compact ? 10 : 12) }}>{children}</div>
  </div>
);

// ---- states ----
const TLSkeleton = () => (
  <div style={{ display: 'flex', gap: 14 }}>
    <div style={{ width: 52, flexShrink: 0, display: 'flex', flexDirection: 'column', alignItems: 'center', paddingTop: 15 }}>
      <div className="sk" style={{ width: 30, height: 10 }} />
      <span style={{ width: 9, height: 9, borderRadius: 9999, marginTop: 8, background: '#E5E6EB' }} />
      <span style={{ flex: 1, width: 2, background: '#EDEFF2', marginTop: 4, minHeight: 40 }} />
    </div>
    <div style={{ flex: 1, border: '1px solid #EDEFF2', borderRadius: 8, padding: 16, marginBottom: 16 }}>
      <div className="sk" style={{ width: 140, height: 12, marginBottom: 12 }} />
      <div className="sk" style={{ width: '88%', height: 16, marginBottom: 8 }} />
      <div className="sk" style={{ width: '64%', height: 14 }} />
    </div>
  </div>
);

const Centered = ({ icon, title, hint, action }) => {
  useLucide();
  return (
    <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', padding: '80px 24px', textAlign: 'center', color: '#8F959E' }}>
      <Icon name={icon} size={56} color="#D4D7DC" />
      <div style={{ fontSize: 15, color: '#1F2329', marginTop: 14 }}>{title}</div>
      <div style={{ fontSize: 13, color: '#8F959E', marginTop: 6, maxWidth: 300, lineHeight: '20px' }}>{hint}</div>
      {action && <div style={{ marginTop: 18 }}>{action}</div>}
    </div>
  );
};

const DemoMenu = ({ value, onPick, onClose }) => {
  useLucide();
  const items = [
    { v: null, l: '正常', icon: 'circle-check' },
    { v: 'loading', l: '加载中', icon: 'loader' },
    { v: 'empty', l: '空状态', icon: 'inbox' },
    { v: 'error', l: '加载失败', icon: 'cloud-off' },
  ];
  return (
    <>
      <div onClick={onClose} style={{ position: 'fixed', inset: 0, zIndex: 50 }} />
      <div style={{ position: 'absolute', zIndex: 51, top: 'calc(100% + 4px)', right: 0, width: 168, background: '#fff', borderRadius: 8, border: '1px solid #EDEFF2', boxShadow: '0 4px 12px rgba(31,35,41,.08), 0 0 1px rgba(31,35,41,.12)', padding: 4 }}>
        <div style={{ padding: '6px 10px 4px', fontSize: 11, color: '#8F959E' }}>状态演示</div>
        {items.map(it => {
          const active = value === it.v || (it.v === null && !value);
          return (
            <div key={it.l} onClick={() => { onPick(it.v); onClose(); }}
              style={{ display: 'flex', alignItems: 'center', gap: 8, height: 32, padding: '0 10px', borderRadius: 6, cursor: 'pointer', fontSize: 13, color: active ? '#0F4DD1' : '#1F2329', background: active ? '#EBF1FE' : 'transparent' }}>
              <Icon name={it.icon} size={15} color={active ? '#1456F0' : '#646A73'} />
              <span style={{ flex: 1 }}>{it.l}</span>
              {active && <Icon name="check" size={14} color="#1456F0" />}
            </div>
          );
        })}
      </div>
    </>
  );
};

const TimelineView = ({
  entries, status, view, scope, scopeLabel, tab, onTab,
  density, onDensity, activeId, onOpen,
  onRetry, onManage, onGoTimeline, counts, railOpen, onOpenRail, appRailWidth = 76, onDemo, demo, readerOpen = false,
}) => {
  useLucide();
  const [narrow, setNarrow] = React.useState(typeof window !== 'undefined' ? window.innerWidth < 760 : false);
  const showQualitySwitch = counts.featured > 0 || tab === 'featured';
  const contentMaxWidth = readerOpen ? 680 : 880;
  const compactList = readerOpen || narrow;

  React.useEffect(() => {
    const onResize = () => setNarrow(window.innerWidth < 760);
    window.addEventListener('resize', onResize);
    return () => window.removeEventListener('resize', onResize);
  }, []);

  // group by day
  const groups = [];
  entries.forEach(e => {
    const label = dayLabel(e.published_at);
    let g = groups.find(x => x.label === label);
    if (!g) { g = { label, items: [] }; groups.push(g); }
    g.items.push(e);
  });

  return (
    <div style={{ flex: 1, minWidth: 0, display: 'flex', flexDirection: 'column', height: '100%', background: '#F5F6F7' }}>
      {/* feed */}
      <div style={{ flex: 1, overflowY: 'auto', minHeight: 0 }}>
        <div style={{ maxWidth: contentMaxWidth, margin: '0 auto', padding: compactList ? '14px 12px 52px' : '18px 24px 60px', width: '100%', transition: 'max-width .22s ease, padding .22s ease' }}>
          {showQualitySwitch && (
            <div style={{ display: 'flex', justifyContent: 'flex-end', margin: '-2px 0 12px' }}>
              <Seg value={tab} onChange={onTab} options={[
                { value: 'featured', label: '精选', icon: 'sparkles', count: counts.featured },
                { value: 'all', label: '全部', count: counts.all },
              ]} size={26} />
            </div>
          )}
          {status === 'loading' && Array.from({ length: 5 }).map((_, i) => <TLSkeleton key={i} />)}
          {status === 'error' && <Centered icon="cloud-off" title="内容加载失败" hint="请稍后重试，资讯将自动恢复加载。" action={<Button variant="primary" icon="refresh-cw" onClick={onRetry}>重试</Button>} />}
          {status === 'empty' && <Centered icon="inbox" title="暂无资讯" hint="换个筛选或调整订阅范围以看到更多内容。" action={<Button variant="secondary" icon="settings-2" onClick={onManage}>去订阅管理</Button>} />}
          {status === 'ready' && entries.length === 0 && (
            <Centered icon="inbox"
              title={`${scopeLabel}暂无资讯`}
              hint="换个筛选或调整订阅范围以看到更多内容。"
              action={<Button variant="secondary" icon="settings-2" onClick={onManage}>去订阅管理</Button>} />
          )}
          {status === 'ready' && groups.map((g, gi) => (
            <div key={g.label} style={{ marginBottom: compactList ? 4 : 6 }}>
              {/* date divider */}
              <div style={{ position: 'sticky', top: 0, zIndex: 20, display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 12, margin: gi === 0 ? '-2px 0 10px' : '8px 0 10px', padding: '7px 0 8px', background: 'rgba(245,246,247,.96)', backdropFilter: 'blur(8px)' }}>
                <span style={{ fontSize: 13, fontWeight: 500, color: '#646A73', whiteSpace: 'nowrap' }}>{g.label}</span>
                <span style={{ fontSize: 12, color: '#BBBFC4', whiteSpace: 'nowrap' }}>{g.items.length} 条</span>
              </div>
              {g.items.map((e, i) => (
                <AxisRow key={e.id} entry={e} last={gi === groups.length - 1 && i === g.items.length - 1} compact={compactList}>
                  <TLCard entry={e} active={e.id === activeId} onOpen={onOpen} compact={readerOpen} narrow={narrow} />
                </AxisRow>
              ))}
            </div>
          ))}
          {status === 'ready' && entries.length > 0 && (
            <div style={{ textAlign: 'center', fontSize: 12, color: '#BBBFC4', paddingTop: 8 }}>没有更多了</div>
          )}
        </div>
      </div>
    </div>
  );
};

Object.assign(window, { TimelineView, Seg });
