// ═══════════════════════════════════════════════════════════════════════════
//  useApi hook + helpers — utilisés par toutes les pages live
//  Charge APRÈS React (script type="text/babel")
// ═══════════════════════════════════════════════════════════════════════════

// Fetch live data from worker.
// Returns { data, loading, error }
// - In LIVE mode (CZF.USE_LIVE_DATA=true): fetches from worker
// - In MOCK mode: returns mockFallback immediately
const useApi = (path, mockFallback = null) => {
  const [state, setState] = React.useState(() => ({
    data: (window.CZF && window.CZF.USE_LIVE_DATA) ? null : mockFallback,
    loading: !!(window.CZF && window.CZF.USE_LIVE_DATA),
    error: null,
  }));
  React.useEffect(() => {
    if (!window.CZF || !CZF.USE_LIVE_DATA || !path) return;
    let cancelled = false;
    const url = `${CZF.API_BASE}${path}`;
    fetch(url)
      .then(r => r.ok ? r.json() : Promise.reject(new Error(`${r.status}`)))
      .then(data => { if (!cancelled) setState({ data, loading: false, error: null }); })
      .catch(error => { if (!cancelled) setState({ data: null, loading: false, error }); });
    return () => { cancelled = true; };
  }, [path]);
  return state;
};

// Loading state — discrete, no flash
const Loading = ({ label = 'Chargement…' }) => (
  <div style={{
    padding: '3rem 2rem', textAlign: 'center',
    fontFamily: 'var(--fc)', fontSize: '.85rem',
    color: 'var(--muted)', letterSpacing: '.1em', textTransform: 'uppercase',
  }}>
    {label}
  </div>
);

// Empty state — used everywhere instead of mock fallback when API returns []
const Empty = ({ icon, title, sub }) => (
  <div style={{
    padding: '3.5rem 2rem', textAlign: 'center',
    background: 'var(--char)', border: '1px dashed var(--border-2)', borderRadius: 4,
  }}>
    {icon && <div style={{ marginBottom: '.85rem', color: 'var(--muted)', display: 'flex', justifyContent: 'center' }}>{icon}</div>}
    <div style={{
      fontFamily: 'var(--fd)', fontSize: '1.4rem', letterSpacing: '.05em',
      color: 'var(--cream-2)', marginBottom: '.4rem',
    }}>{title}</div>
    {sub && <div style={{
      fontFamily: 'var(--fc)', fontSize: '.78rem', color: 'var(--muted)',
      letterSpacing: '.04em', maxWidth: 440, margin: '0 auto', lineHeight: 1.5,
    }}>{sub}</div>}
  </div>
);

// Post helper to admin/public endpoints
const postApi = async (path, body, token) => {
  const base = (window.CZF && CZF.API_BASE) || '';
  const headers = { 'Content-Type': 'application/json' };
  if (token) headers['Authorization'] = `Bearer ${token}`;
  const r = await fetch(`${base}${path}`, { method: 'POST', headers, body: JSON.stringify(body) });
  if (!r.ok) throw new Error(`${r.status}`);
  return r.json().catch(() => ({}));
};

// Util: divide players into bubble layout based on tier
const positionBubbles = (players) => {
  const tierY = {
    CHALLENGER: 75, GRANDMASTER: 80, MASTER: 95,
    DIAMOND: 220, EMERALD: 350, PLATINUM: 360,
    GOLD: 470, SILVER: 470, BRONZE: 480, IRON: 480, UNRANKED: 480,
  };
  // Group by tier
  const byTier = {};
  players.forEach(p => {
    const t = (p.tier || 'UNRANKED').toUpperCase();
    if (!byTier[t]) byTier[t] = [];
    byTier[t].push(p);
  });
  const result = [];
  for (const [tier, group] of Object.entries(byTier)) {
    const y = tierY[tier] ?? 480;
    const count = group.length;
    const xStart = 80, xEnd = 1120;
    group.forEach((p, i) => {
      const x = count === 1
        ? (xStart + xEnd) / 2
        : xStart + ((xEnd - xStart) / (count + 1)) * (i + 1);
      // Small vertical jitter (deterministic from name)
      const seed = (p.discord_tag || p.name || 'x').charCodeAt(0);
      const jitterY = (seed % 7) * 6 - 18;
      result.push({
        ...p,
        name: p.discord_nick || p.discord_tag?.split('#')[0] || p.name || '?',
        tier,
        div: p.division || p.div || 'Yordle',
        role: ({ TOP: 'TOP', JUNGLE: 'JGL', MIDDLE: 'MID', BOTTOM: 'ADC', UTILITY: 'SUP' }[p.role_principal] || p.role || '?'),
        team: p.team_name || p.team || null,
        x, y: y + jitterY,
      });
    });
  }
  return result;
};

// Util: time ago formatter
const timeAgoFr = (iso) => {
  if (!iso) return '—';
  const d = new Date(iso);
  if (isNaN(d.getTime())) return iso;
  const diff = (Date.now() - d.getTime()) / 1000;
  if (diff < 60) return 'il y a un instant';
  if (diff < 3600) return `il y a ${Math.round(diff/60)} min`;
  if (diff < 86400) return `il y a ${Math.round(diff/3600)}h`;
  if (diff < 7*86400) return `il y a ${Math.round(diff/86400)}j`;
  return d.toLocaleDateString('fr-FR');
};

// Util: discord avatar URL
const discordAvatarUrl = (discordId, avatarHash, size = 64) => {
  if (!discordId || !avatarHash) return null;
  return `https://cdn.discordapp.com/avatars/${discordId}/${avatarHash}.png?size=${size}`;
};

Object.assign(window, { useApi, Loading, Empty, postApi, positionBubbles, timeAgoFr, discordAvatarUrl });
