(function(){
// 資金流向頁 - 台股 + 美股共用
// 接線：market="tw" 用 live.flow_tw；market="us" 用 live.flow_us
const T = window.STOCK_TOKENS;

// ── DataMode 標示 ────────────────────────────────────────────────────────────
function DataModeBadge({ market }) {
  const live = window.STOCK_DATA_LIVE;
  const flowData = market === 'tw' ? live.flow_tw : live.flow_us;
  const isLive = live.loaded && flowData && flowData.institutions &&
    (flowData._status === 'live' || !flowData.not_implemented);
  const dateStr = flowData && flowData.date ? flowData.date : '';
  return (
    <div style={{ display: 'flex', alignItems: 'center', gap: 4,
      fontSize: 10, color: T.text3, fontFamily: T.fontMono }}>
      <span style={{
        display: 'inline-block', width: 6, height: 6, borderRadius: 3,
        background: isLive ? 'oklch(0.7 0.15 155)' : 'oklch(0.7 0 0)',
      }} />
      {isLive ? ('LIVE ' + dateStr) : 'DEMO'}
    </div>
  );
}

function FlowPage({ market }) {
  const vp = window.useViewport();
  const isTW = market === 'tw';
  const live = window.STOCK_DATA_LIVE;

  // 取對應的 live flow data
  const liveFlowRaw = isTW
    ? (live.loaded ? live.flow_tw : null)
    : (live.loaded ? live.flow_us : null);

  // 判斷是否有實際資料：_status==='live' 或有 institutions 且未標示 not_implemented
  const hasLiveFlow = liveFlowRaw && liveFlowRaw.institutions &&
    (liveFlowRaw._status === 'live' || !liveFlowRaw.not_implemented);

  // 無資料顯示空狀態
  if (!hasLiveFlow) {
    const emptyTitle = isTW ? '台股資金流向功能開發中' : '美股資金流功能開發中';
    return (
      <div style={{ padding: 24 }}>
        <window.EmptyState
          title={emptyTitle}
          hint="pipeline 尚未實作此資料源，預計後續加入"
        />
      </div>
    );
  }

  // 真實 fetcher schema 是 buy_b / sell_b / net_b（億），mock 是 buy / sell / net
  // 統一 normalize 為 buy / sell / net
  const institutions = (liveFlowRaw.institutions || []).map(f => ({
    name: f.name,
    buy: (typeof f.buy_b === 'number') ? f.buy_b : (typeof f.buy === 'number' ? f.buy : 0),
    sell: (typeof f.sell_b === 'number') ? f.sell_b : (typeof f.sell === 'number' ? f.sell : 0),
    net: (typeof f.net_b === 'number') ? f.net_b : (typeof f.net === 'number' ? f.net : 0),
  }));
  const topBuys = liveFlowRaw.top_buys || null;
  const topSells = liveFlowRaw.top_sells || null;

  const pad = vp.isMobile ? 12 : 24;

  return (
    <div style={{ padding: pad, display: 'flex', flexDirection: 'column', gap: vp.isMobile ? 12 : 16 }}>
      {/* AI 解讀條 */}
      <div style={{
        background: 'linear-gradient(135deg, ' + T.aiSoft + ', oklch(0.97 0.018 290))',
        border: '1px solid ' + T.aiBorder, borderRadius: T.radiusLg, padding: vp.isMobile ? 14 : 18,
      }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 10 }}>
          <window.AIBadge size="md" />
          <div style={{ fontSize: 13, fontWeight: 600, color: T.ai }}>AI 資金流向解讀</div>
          <span style={{ fontSize: 10, color: T.text3, fontFamily: T.fontMono }}>
            {liveFlowRaw.date ? liveFlowRaw.date : '—'} 更新
          </span>
          <div style={{ marginLeft: 'auto' }}><DataModeBadge market={market} /></div>
        </div>
        <div style={{ fontSize: 13, color: T.text2, lineHeight: 1.6 }}>
          {isTW ? '今日三大法人' : '今日美股資金'}：
          {institutions.map(f => (
            <span key={f.name}>
              {f.name} <b style={{ color: window.dirColor(f.net), fontFamily: T.fontMono }}>
                {window.sign(f.net)}{f.net.toFixed(1)} 億
              </b>{'  '}
            </span>
          ))}
        </div>
      </div>

      {/* KPI bar */}
      <div style={{
        display: 'grid',
        gridTemplateColumns: vp.isMobile ? '1fr 1fr' : 'repeat(4, 1fr)',
        gap: vp.isMobile ? 8 : 12,
      }}>
        {institutions.map((f) => (
          <FlowKpi key={f.name} label={f.name + '買賣超'} v={(window.sign(f.net) + f.net.toFixed(1) + ' 億')}
            up={f.net > 0} down={f.net < 0} vp={vp} />
        ))}
      </div>

      {/* 主視覺：桑基圖（mobile 橫向滑動）*/}
      {!vp.isMobile && (
        <window.Card title={isTW ? '今日資金流動 · 桑基圖' : 'Money Flow · Sankey'}
          subtitle="法人 → 題材 → 個股"
          action={<div style={{ display: 'flex', gap: 6 }}>
            <window.Btn variant="ghost" active>今日</window.Btn>
            <window.Btn variant="ghost">3 日</window.Btn>
            <window.Btn variant="ghost">1 週</window.Btn>
          </div>}
          padding={20}>
          <SankeyChart isTW={isTW} institutions={institutions} />
        </window.Card>
      )}

      {/* 雙欄：類股強弱 + 個股排行 */}
      <div style={{
        display: 'grid',
        gridTemplateColumns: vp.isMobile ? '1fr' : '1fr 1fr',
        gap: 16,
      }}>
        <window.Card title={isTW ? '類股資金強弱' : 'Sector Rotation'} padding={0}>
          <SectorBars isTW={isTW} />
        </window.Card>

        <window.Card title={isTW ? '個股買賣超 Top' : 'Top Net Inflow'} padding={0}>
          <TopFlowList isTW={isTW} liveData={{ top_buys: topBuys, top_sells: topSells }} />
        </window.Card>
      </div>
    </div>
  );
}
window.FlowPage = FlowPage;

function FlowKpi({ label, v, up, down, sub, vp }) {
  const c = up ? T.up : down ? T.down : T.text;
  const isMob = vp && vp.isMobile;
  return (
    <div style={{ background: T.surface, border: '1px solid ' + T.border, borderRadius: T.radius, padding: isMob ? 12 : 14 }}>
      <div style={{ fontSize: 10, color: T.text3, marginBottom: 4 }}>{label}</div>
      <div style={{ fontSize: isMob ? 17 : 22, fontWeight: 700, color: c, fontFamily: T.fontMono, letterSpacing: -0.4,
        fontVariantNumeric: 'tabular-nums' }}>{v}</div>
      {sub && <div style={{ fontSize: 10, color: T.text3, marginTop: 2 }}>{sub}</div>}
    </div>
  );
}

function SankeyChart({ isTW, institutions }) {
  const W = 720, H = 320;
  const sources = institutions
    ? institutions.map((f) => ({
        n: f.name,
        v: Math.abs(f.net),
        c: f.net > 0 ? T.up : f.net < 0 ? T.down : T.text3,
      }))
    : [];

  const themes = isTW
    ? [{ n: 'AI 伺服器', v: 52 }, { n: 'ASIC', v: 28 }, { n: '矽光子', v: 15 }, { n: 'IC 設計', v: 22 }, { n: '電源', v: 18 }, { n: '其他', v: 35 }]
    : [{ n: 'Mag7', v: 28 }, { n: 'Semi', v: 18 }, { n: 'AI Software', v: 12 }, { n: 'Energy', v: 8 }, { n: 'Bio', v: 5 }, { n: 'Other', v: 4 }];
  const stocks = isTW
    ? [{ n: '台積電', v: 35 }, { n: '鴻海', v: 22 }, { n: '世芯', v: 18 }, { n: '廣達', v: 15 }, { n: '緯穎', v: 12 }, { n: '聯發科', v: 10 }, { n: '其他', v: 60 }]
    : [{ n: 'NVDA', v: 38 }, { n: 'MSFT', v: 12 }, { n: 'GOOGL', v: 10 }, { n: 'AMZN', v: 8 }, { n: 'META', v: 6 }, { n: 'AVGO', v: 5 }, { n: 'Others', v: 20 }];

  const cols = [
    { x: 20, items: sources, w: 90 },
    { x: 280, items: themes, w: 110 },
    { x: 580, items: stocks, w: 110 },
  ];

  cols.forEach(col => {
    const total = col.items.reduce((s, i) => s + i.v, 0) || 1;
    let y = 20;
    const gap = 6;
    const avail = H - 40 - gap * (col.items.length - 1);
    col.items.forEach(it => {
      it.h = (it.v / total) * avail;
      it.y = y;
      y += it.h + gap;
    });
  });

  const links = [];
  cols[0].items.forEach((s) => {
    cols[1].items.forEach((t) => {
      const v = (s.v * t.v) / cols[1].items.reduce((sum, i) => sum + i.v, 0) / 3;
      if (v > 0.5) links.push({ from: s, to: t, v, color: s.c || T.primary });
    });
  });
  cols[1].items.forEach((t) => {
    cols[2].items.forEach((st) => {
      const v = (t.v * st.v) / cols[2].items.reduce((sum, i) => sum + i.v, 0) / 3;
      if (v > 0.5) links.push({ from: t, to: st, v, color: T.primary });
    });
  });

  return (
    <svg width={W} height={H} style={{ display: 'block', margin: '0 auto' }}>
      {links.map((l, i) => {
        const fromCol = cols.find(c => c.items.includes(l.from));
        const toCol = cols.find(c => c.items.includes(l.to));
        const fx = fromCol.x + fromCol.w;
        const tx = toCol.x;
        const fy = l.from.y + l.from.h / 2;
        const ty = l.to.y + l.to.h / 2;
        const cx = (fx + tx) / 2;
        const w = Math.max(1, l.v * 1.5);
        return (
          <path key={i}
            d={'M' + fx + ' ' + fy + ' C' + cx + ' ' + fy + ', ' + cx + ' ' + ty + ', ' + tx + ' ' + ty}
            stroke={l.color} strokeWidth={w} strokeOpacity="0.18" fill="none" />
        );
      })}
      {cols.map((col, ci) => col.items.map(it => (
        <g key={ci + it.n}>
          <rect x={col.x} y={it.y} width={col.w} height={it.h}
            fill={ci === 0 ? (it.c || T.primary) : ci === 1 ? T.primary : T.text2}
            rx="2" />
          <text x={col.x + col.w / 2} y={it.y + it.h / 2 + 4}
            fontSize={Math.min(12, Math.max(9, it.h / 4))}
            fontFamily={T.fontSans} fill="white" fontWeight="600" textAnchor="middle">
            {it.n}
          </text>
          <text x={col.x + col.w / 2} y={it.y + it.h + 12}
            fontSize="10" fontFamily={T.fontMono} fill={T.text3} textAnchor="middle">
            {isTW ? (it.v + ' 億') : ('$' + it.v + 'B')}
          </text>
        </g>
      )))}
    </svg>
  );
}

function SectorBars({ isTW }) {
  const data = isTW
    ? [
      { n: 'AI 伺服器', v: 52, max: 60 },
      { n: 'IC 設計', v: 22, max: 60 },
      { n: 'ASIC', v: 28, max: 60 },
      { n: '電源', v: 18, max: 60 },
      { n: '矽光子', v: 15, max: 60 },
      { n: '航運', v: 8, max: 60 },
      { n: '面板', v: -12, max: 60 },
      { n: '記憶體', v: -18, max: 60 },
      { n: '生技', v: -8, max: 60 },
    ]
    : [
      { n: 'Semis', v: 38, max: 50 },
      { n: 'Software', v: 28, max: 50 },
      { n: 'Cloud', v: 22, max: 50 },
      { n: 'Energy', v: 8, max: 50 },
      { n: 'Financials', v: 5, max: 50 },
      { n: 'Healthcare', v: -12, max: 50 },
      { n: 'Real Estate', v: -18, max: 50 },
    ];
  return (
    <div style={{ padding: 16 }}>
      {data.map((d, i) => (
        <div key={d.n} style={{ display: 'flex', alignItems: 'center', gap: 10, padding: '6px 0',
          borderBottom: i < data.length - 1 ? '1px dashed ' + T.border : 'none' }}>
          <span style={{ width: 90, fontSize: 12, color: T.text2, fontWeight: 500 }}>{d.n}</span>
          <div style={{ flex: 1, position: 'relative', height: 18 }}>
            <div style={{ position: 'absolute', left: '50%', top: 0, bottom: 0, width: 1, background: T.border }} />
            <div style={{
              position: 'absolute',
              [d.v > 0 ? 'left' : 'right']: '50%',
              top: 2, bottom: 2,
              width: (Math.abs(d.v) / d.max * 50) + '%',
              background: d.v > 0 ? T.up : T.down,
              borderRadius: 2,
            }} />
          </div>
          <span style={{ width: 60, textAlign: 'right', fontFamily: T.fontMono, fontSize: 12,
            color: window.dirColor(d.v), fontWeight: 600 }}>
            {window.sign(d.v)}{Math.abs(d.v)}{isTW ? ' 億' : 'B'}
          </span>
        </div>
      ))}
    </div>
  );
}

function TopFlowList({ isTW, liveData }) {
  // net_b（億，後端直接給）優先；否則用 net_lots/1000 換算
  const toNet = (item, sign) => {
    if (item.net_b != null) return item.net_b * sign;
    if (item.net_lots != null) return (item.net_lots / 1000) * sign;
    return 0;
  };

  // 有 live 的 top_buys / top_sells 時合并顯示
  const liveItems = liveData && liveData.top_buys
    ? [
        ...(liveData.top_buys || []).slice(0, 5).map(b => ({
          c: b.code, n: b.name, v: toNet(b, 1), p: b.price || 0, chg: b.change_pct || 0,
        })),
        ...(liveData.top_sells || []).slice(0, 2).map(s => ({
          c: s.code, n: s.name, v: toNet(s, -1), p: s.price || 0, chg: s.change_pct || 0,
        })),
      ]
    : null;

  if (!liveItems || liveItems.length === 0) {
    return (
      <div style={{ padding: 24, textAlign: 'center', color: T.text3, fontSize: 12 }}>
        暫無個股排行資料
      </div>
    );
  }

  return (
    <div>
      {liveItems.map((it, i) => (
        <div key={it.c + i} style={{
          padding: '10px 16px', borderBottom: i < liveItems.length - 1 ? '1px solid ' + T.border : 'none',
          display: 'grid', gridTemplateColumns: '1fr 80px 80px 70px', gap: 10, alignItems: 'center',
        }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
            <span style={{ width: 16, fontSize: 10, color: T.text3, fontFamily: T.fontMono }}>{i + 1}</span>
            <div>
              <div style={{ fontSize: 10, color: T.text3, fontFamily: T.fontMono }}>{it.c}</div>
              <div style={{ fontSize: 12, fontWeight: 600, color: T.text }}>{it.n}</div>
            </div>
          </div>
          <div style={{ fontFamily: T.fontMono, fontSize: 12, color: window.dirColor(it.v), fontWeight: 600, textAlign: 'right' }}>
            {window.sign(it.v)}{Math.abs(it.v).toFixed(isTW ? 1 : 2)}{isTW ? '億' : 'B'}
          </div>
          <div style={{ fontFamily: T.fontMono, fontSize: 12, color: T.text2, textAlign: 'right' }}>
            {it.p > 0 ? window.fmt(it.p, it.p < 100 ? 2 : 1) : '—'}
          </div>
          <div style={{ textAlign: 'right' }}>
            {it.chg !== 0 ? <window.ChangeChip value={it.chg} /> : <span style={{ color: T.text3, fontSize: 10 }}>—</span>}
          </div>
        </div>
      ))}
    </div>
  );
}

})();
