/* global React */
// Shared chrome — phone frame, status bar, tabbar, header, helpers
const { useState, useEffect, useRef, useCallback, useMemo, createContext, useContext, Fragment } = React;

// ===== API base + fetch helper =====
// 同源走 /api,本地用 h5proxy.py 反代到 apmchat.pages.dev。
// 跨源场景在 index.html 里 window.API_BASE = 'https://apmchat.pages.dev/api' 覆盖。
const API_BASE = (typeof window !== 'undefined' && window.API_BASE) || '/api';

async function apiFetch(path, { fallback = null, signal } = {}) {
  const url = path.startsWith('http') ? path : API_BASE + path;
  try {
    const res = await fetch(url, { signal, credentials: 'omit' });
    if (!res.ok) throw new Error('http ' + res.status);
    return await res.json();
  } catch (err) {
    // CORS / network / 4xx — silently fall back to mock so prototype keeps rendering
    if (typeof console !== 'undefined') console.warn('[apiFetch fallback]', path, err.message);
    return fallback;
  }
}

// useApi: tiny hook for GET endpoints — { data, loading, error, source }
function useApi(path, { fallback = null } = {}) {
  const [state, setState] = React.useState({ data: fallback, loading: true, error: null, source: 'pending' });
  React.useEffect(() => {
    let alive = true;
    const ctrl = new AbortController();
    apiFetch(path, { fallback: null, signal: ctrl.signal }).then((data) => {
      if (!alive) return;
      if (data) setState({ data, loading: false, error: null, source: 'live' });
      else setState({ data: fallback, loading: false, error: 'fallback', source: 'mock' });
    });
    return () => { alive = false; ctrl.abort(); };
  }, [path]);
  return state;
}

// pickI18n 在 locale-map.js 里定义并挂到 window

// ===== Language Context — 全局语言, 独立于货币 =====
const LangContext = createContext({ lang: 'zh', set: () => {} });

// ===== Currency helpers =====
const CURRENCIES = {
  CNY: { sym: '¥',  flag: '🇨🇳', code: 'CNY', name: '人民币', rate: 1 },
  KRW: { sym: '₩',  flag: '🇰🇷', code: 'KRW', name: '韩元',   rate: 188 },
  USD: { sym: '$',  flag: '🇺🇸', code: 'USD', name: '美元',   rate: 0.138 },
  JPY: { sym: '¥',  flag: '🇯🇵', code: 'JPY', name: '日元',   rate: 21.4 },
  VND: { sym: '₫',  flag: '🇻🇳', code: 'VND', name: '越南盾', rate: 3450 },
};

function formatPrice(cny, code = 'CNY') {
  const cur = CURRENCIES[code];
  const v = cny * cur.rate;
  if (code === 'KRW' || code === 'VND' || code === 'JPY') {
    return Math.round(v).toLocaleString();
  }
  return v.toFixed(2);
}

const CurContext = createContext({ code: 'CNY', set: () => {} });

// ===== ICONS (Lucide-style strokes) =====
function Icon({ name, size = 20, stroke = 'currentColor', sw = 1.6 }) {
  const paths = {
    home: <><path d="M3 11l9-8 9 8" /><path d="M5 10v10h14V10" /></>,
    grid: <><rect x="3" y="3" width="7" height="7" /><rect x="14" y="3" width="7" height="7" /><rect x="3" y="14" width="7" height="7" /><rect x="14" y="14" width="7" height="7" /></>,
    cart: <><circle cx="9" cy="20" r="1.4" /><circle cx="18" cy="20" r="1.4" /><path d="M3 4h2l2.4 11.4a2 2 0 002 1.6h7.6a2 2 0 002-1.5L21 8H6" /></>,
    user: <><circle cx="12" cy="8" r="4" /><path d="M4 21c0-4.5 3.6-8 8-8s8 3.5 8 8" /></>,
    live: <><rect x="2" y="6" width="14" height="12" rx="2" /><path d="M16 10l6-3v10l-6-3" /></>,
    search: <><circle cx="11" cy="11" r="7" /><path d="M21 21l-4.5-4.5" /></>,
    arrow: <><path d="M5 12h14M13 5l7 7-7 7" /></>,
    chev: <><path d="M9 6l6 6-6 6" /></>,
    chevd: <><path d="M6 9l6 6 6-6" /></>,
    back: <><path d="M19 12H5M12 19l-7-7 7-7" /></>,
    plus: <><path d="M12 5v14M5 12h14" /></>,
    minus: <><path d="M5 12h14" /></>,
    heart: <><path d="M12 21s-7-4.5-9.3-9C1.2 9.4 2.6 6 6 6c2 0 3.3 1 4 2.5C10.6 7 12 6 14 6c3.4 0 4.8 3.4 3.3 6-2.3 4.5-9.3 9-9.3 9z" /></>,
    share: <><circle cx="6" cy="12" r="2" /><circle cx="18" cy="6" r="2" /><circle cx="18" cy="18" r="2" /><path d="M8 11l8-4M8 13l8 4" /></>,
    star: <><path d="M12 3l2.7 5.5 6 .9-4.4 4.2 1 6L12 16.8 6.7 19.6l1-6L3.4 9.4l6-.9z" /></>,
    bell: <><path d="M6 8a6 6 0 1112 0c0 7 3 7 3 9H3c0-2 3-2 3-9zM10 21a2 2 0 004 0" /></>,
    map: <><path d="M9 20l-6 2V6l6-2 6 2 6-2v16l-6 2-6-2zM9 4v16M15 6v16" /></>,
    truck: <><rect x="1" y="6" width="13" height="11" /><path d="M14 9h4l3 4v4h-7" /><circle cx="6" cy="19" r="2" /><circle cx="18" cy="19" r="2" /></>,
    chat: <><path d="M21 12a8 8 0 11-3-6.3L21 5l-1 4a8 8 0 011 3z" /></>,
    coin: <><circle cx="12" cy="12" r="9" /><path d="M9 9h4a2 2 0 010 4h-4M9 13h5l1 4" /></>,
    qr: <><rect x="3" y="3" width="7" height="7" /><rect x="14" y="3" width="7" height="7" /><rect x="3" y="14" width="7" height="7" /><path d="M14 14h2v2h-2zM18 14h3M14 18h2M18 18v3M21 14v7" strokeWidth="1.4" /></>,
    check: <><path d="M5 12l5 5L20 7" /></>,
    close: <><path d="M5 5l14 14M19 5L5 19" /></>,
    pin: <><path d="M12 21s-7-7-7-12a7 7 0 0114 0c0 5-7 12-7 12z" /><circle cx="12" cy="9" r="2.5" /></>,
    moon: <><path d="M21 12.8A9 9 0 1111.2 3 7 7 0 0021 12.8z" /></>,
    globe: <><circle cx="12" cy="12" r="9" /><path d="M3 12h18M12 3a14 14 0 010 18M12 3a14 14 0 000 18" /></>,
    filter: <><path d="M3 5h18M6 12h12M10 19h4" /></>,
    sort: <><path d="M3 6h18M6 12h12M9 18h6" /></>,
    fire: <><path d="M12 22c4 0 7-3 7-7 0-4-3-5-3-9-3 2-7 5-7 9 0 1 .5 2 1 2.5C9 16 8 14 8 12c-2 1-3 3-3 5 0 4 3 5 7 5z" /></>,
    cam: <><rect x="3" y="7" width="18" height="12" rx="2" /><circle cx="12" cy="13" r="3.5" /><path d="M9 7l1.5-3h3L15 7" /></>,
    edit: <><path d="M12 20h9M16.5 3.5a2 2 0 113 3L7 19l-4 1 1-4z" /></>,
    settings: <><circle cx="12" cy="12" r="3" /><path d="M19 12a7 7 0 00-.1-1.2l2-1.5-2-3.4-2.3.9a7 7 0 00-2-1.2L14 3h-4l-.6 2.6a7 7 0 00-2 1.2l-2.3-.9-2 3.4 2 1.5A7 7 0 005 12c0 .4 0 .8.1 1.2l-2 1.5 2 3.4 2.3-.9a7 7 0 002 1.2L10 21h4l.6-2.6a7 7 0 002-1.2l2.3.9 2-3.4-2-1.5c0-.4.1-.8.1-1.2z" /></>,
  };
  return (
    <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke={stroke} strokeWidth={sw} strokeLinecap="round" strokeLinejoin="round">
      {paths[name]}
    </svg>
  );
}

// ===== Phone shell =====
function Phone({ children, label, num, dark = false, theme }) {
  return (
    <div className="phone" data-theme={theme}>
      {label && (
        <div className="phone-label">
          <b>{num}</b> &nbsp;{label}
        </div>
      )}
      <div className="screen">
        <div className={'statusbar ' + (dark ? 'light' : '')}>
          <span>9:41</span>
          <span className="right">
            <svg width="14" height="10" viewBox="0 0 14 10" fill="none"><path d="M1 9h2V7H1zM5 9h2V5H5zM9 9h2V3H9zM13 9V1" stroke="currentColor" strokeWidth="1.4" strokeLinecap="round" /></svg>
            <svg width="14" height="10" viewBox="0 0 14 10" fill="none"><path d="M7 7l1 1 1-1M3 4a6 6 0 018 0M5 6a3 3 0 014 0" stroke="currentColor" strokeWidth="1.2" strokeLinecap="round" fill="none" /></svg>
            <span className="battery"><i style={{ width: '78%' }}></i></span>
          </span>
        </div>
        <div className={'wx-capsule ' + (dark ? 'dark' : '')}>
          <div className="dots"><span /><span /><span /></div>
          <div className="div" />
          <div className="x" />
        </div>
        {children}
      </div>
    </div>
  );
}

// ===== Bottom tab bar =====
function TabBar({ active = 'home', onNav }) {
  const tabs = [
    { id: 'home', label: '首页', icon: 'home' },
    { id: 'cat',  label: '分类', icon: 'grid' },
    { id: 'live', label: 'AI 直播', icon: 'live', special: true },
    { id: 'cart', label: '购物车', icon: 'cart', badge: 3 },
    { id: 'me',   label: '我的', icon: 'user' },
  ];
  return (
    <div className="tabbar">
      {tabs.map(t => (
        <button key={t.id} className={'tab ' + (active === t.id ? 'active' : '')} onClick={() => onNav?.(t.id)}>
          {t.special ? (
            <div style={{ position: 'relative', width: 38, height: 38, marginTop: -16, borderRadius: '50%', background: 'var(--brand)', display: 'grid', placeItems: 'center', boxShadow: '0 6px 16px var(--brand-soft)' }}>
              <Icon name="live" size={18} stroke="#fff" sw={1.8} />
              <span style={{ position: 'absolute', top: -2, right: -2, fontSize: 7, fontWeight: 700, background: '#FFD53D', color: '#000', padding: '1px 4px', borderRadius: 999, fontFamily: 'var(--font-display)' }}>LIVE</span>
            </div>
          ) : (
            <div className="blob" style={{ position: 'relative' }}>
              <Icon name={t.icon} size={21} sw={active === t.id ? 1.8 : 1.5} />
              {t.badge && (
                <span style={{ position: 'absolute', top: -3, right: -6, fontSize: 8, fontWeight: 700, background: 'var(--brand)', color: '#fff', padding: '0 4px', minWidth: 14, height: 14, borderRadius: 999, display: 'grid', placeItems: 'center', lineHeight: 1, border: '1.5px solid #fff' }}>{t.badge}</span>
              )}
            </div>
          )}
          <span style={{ marginTop: t.special ? 0 : 0 }}>{t.label}</span>
        </button>
      ))}
    </div>
  );
}

// ===== Currency drawer =====
function CurrencyDrawer({ open, onClose }) {
  const { code, set } = useContext(CurContext);
  return (
    <Fragment>
      <div className={'drawer-mask ' + (open ? 'open' : '')} onClick={onClose} />
      <div className={'drawer ' + (open ? 'open' : '')}>
        <div style={{ width: 36, height: 4, borderRadius: 2, background: '#E5E5E5', margin: '0 auto 12px' }} />
        <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between', marginBottom: 4 }}>
          <h3 style={{ fontSize: 16, fontWeight: 700 }}>选择币种</h3>
          <span style={{ fontSize: 11, color: 'var(--fg-3)' }}>汇率每日 00:00 更新</span>
        </div>
        <p style={{ fontSize: 11, color: 'var(--fg-3)', marginBottom: 14 }}>下单瞬间锁定汇率,订单详情永久保留</p>
        <div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
          {Object.values(CURRENCIES).map(c => (
            <button key={c.code} onClick={() => { set(c.code); onClose(); }}
              style={{ display: 'flex', alignItems: 'center', gap: 12, padding: '11px 12px', borderRadius: 10, border: '1px solid ' + (code === c.code ? 'var(--brand)' : 'var(--border-1)'), background: code === c.code ? 'var(--brand-soft)' : '#fff', cursor: 'pointer', textAlign: 'left' }}>
              <span style={{ fontSize: 22 }}>{c.flag}</span>
              <div style={{ flex: 1 }}>
                <div style={{ fontSize: 13, fontWeight: 600 }}>{c.name} <span style={{ fontFamily: 'var(--font-mono)', fontSize: 10, color: 'var(--fg-3)', marginLeft: 4 }}>{c.code}</span></div>
                <div style={{ fontSize: 10, color: 'var(--fg-3)', fontFamily: 'var(--font-mono)', marginTop: 2 }}>1 CNY = {c.rate.toLocaleString()} {c.sym}</div>
              </div>
              {code === c.code && <Icon name="check" size={18} stroke="var(--brand)" sw={2} />}
            </button>
          ))}
        </div>
      </div>
    </Fragment>
  );
}

// ===== Currency pill button =====
function CurPill({ onClick, dark = false }) {
  const { code } = useContext(CurContext);
  const c = CURRENCIES[code];
  return (
    <button className="curpill" onClick={onClick} style={dark ? { background: 'rgba(255,255,255,0.18)', color: '#fff' } : {}}>
      <span className="flag">{c.flag}</span>
      <span style={{ fontFamily: 'var(--font-mono)' }}>{code}</span>
      <Icon name="chevd" size={10} sw={2} />
    </button>
  );
}

// ===== Sinsagom mini avatar =====
// 数据源: /api/public/brand/mascot — 全局只拉一次, 失败回落到本地 assets/sinsagom-1.jpg
let _mascotPromise = null;
function getMascotUrl() {
  if (!_mascotPromise) {
    _mascotPromise = apiFetch('/public/brand/mascot', { fallback: { url: 'assets/sinsagom-1.jpg' } })
      .then(d => d?.url || 'assets/sinsagom-1.jpg');
  }
  return _mascotPromise;
}
function Sinsagom({ size = 28 }) {
  const [url, setUrl] = useState('assets/sinsagom-1.jpg');
  useEffect(() => { getMascotUrl().then(setUrl); }, []);
  return (
    <span style={{ width: size, height: size, borderRadius: '50%', background: `#FFE9D6 url(${url}) center/120% no-repeat`, display: 'inline-block', flexShrink: 0, border: '1.5px solid #fff', boxShadow: '0 2px 6px rgba(0,0,0,0.08)' }} />
  );
}

// ===== Korean-style price block =====
function PriceBlock({ cny, originCny, size = 18 }) {
  const { code } = useContext(CurContext);
  const c = CURRENCIES[code];
  return (
    <span className="price" style={{ fontSize: size }}>
      <span className="cur">{c.sym}</span>
      <span className="num">{formatPrice(cny, code)}</span>
      {originCny && <span className="strike">{c.sym}{formatPrice(originCny, code)}</span>}
    </span>
  );
}

// ===== Product image placeholder — uses profile imgs =====
function ProductImg({ idx = 1, ratio = 1, label }) {
  const src = `assets/p${((idx - 1) % 12) + 1}.jpg`;
  return (
    <div className="ph" style={{ aspectRatio: ratio, background: `url(${src}) center/cover, #EDEAE5`, position: 'relative' }}>
      {label && <div style={{ position: 'absolute', left: 6, top: 6, background: 'rgba(0,0,0,0.65)', color: '#fff', fontSize: 9, fontWeight: 600, padding: '2px 5px', borderRadius: 2, fontFamily: 'var(--font-mono)' }}>{label}</div>}
    </div>
  );
}

Object.assign(window, { CurContext, LangContext, CURRENCIES, formatPrice, Icon, Phone, TabBar, CurrencyDrawer, CurPill, Sinsagom, PriceBlock, ProductImg, apiFetch, useApi, API_BASE });
