// components.jsx — shared UI primitives for 16x0 v2
const { useState, useEffect } = React;

const mobileViewStores = new Map();

function getMobileViewStore(maxWidth) {
  if (mobileViewStores.has(maxWidth)) return mobileViewStores.get(maxWidth);
  const query = `(max-width: ${maxWidth}px)`;
  const read = () => typeof window !== 'undefined' && window.innerWidth <= maxWidth;
  let value = read();
  let media = null;
  const listeners = new Set();
  const notify = () => {
    const next = read();
    if (next === value) return;
    value = next;
    listeners.forEach(listener => listener(value));
  };
  const store = {
    getSnapshot: () => value,
    subscribe(listener) {
      listeners.add(listener);
      if (listeners.size === 1 && typeof window !== 'undefined') {
        media = window.matchMedia?.(query) || null;
        if (media?.addEventListener) media.addEventListener('change', notify);
        else window.addEventListener('resize', notify);
      }
      return () => {
        listeners.delete(listener);
        if (listeners.size === 0 && typeof window !== 'undefined') {
          if (media?.removeEventListener) media.removeEventListener('change', notify);
          else window.removeEventListener('resize', notify);
          media = null;
        }
      };
    },
  };
  mobileViewStores.set(maxWidth, store);
  return store;
}

function useIsMobileView(maxWidth = 760) {
  const store = getMobileViewStore(maxWidth);
  const [isMobile, setIsMobile] = useState(store.getSnapshot);
  useEffect(() => {
    setIsMobile(store.getSnapshot());
    return store.subscribe(setIsMobile);
  }, [maxWidth]);
  return isMobile;
}

function scrollToTopOnMobile(maxWidth = 760) {
  if (typeof window === 'undefined' || window.innerWidth > maxWidth) return;
  const run = () => {
    const root = document.scrollingElement || document.documentElement || document.body;
    root.scrollTo({ top:0, left:0, behavior:'auto' });
    document.body.scrollTop = 0;
    document.documentElement.scrollTop = 0;
  };
  requestAnimationFrame(() => requestAnimationFrame(run));
}

// ── LiveDot ──────────────────────────────────────────────────────────────────
function LiveDot() {
  return (
    <span style={{ display:'inline-flex', alignItems:'center', gap:5, whiteSpace:'nowrap',
      color:'#e05555', fontSize:10, fontWeight:700, letterSpacing:'0.08em', fontFamily:'var(--font-cond)' }}>
      <span style={{ width:5, height:5, borderRadius:'50%', background:'#e05555',
        flexShrink:0, animation:'pulseDot 1.4s ease-in-out infinite' }} />
      AO VIVO
    </span>
  );
}

// ── MapBadge ─────────────────────────────────────────────────────────────────
function MapBadge({ mapId, size = 'sm' }) {
  const map = window.MAPS.find(m => m.id === mapId) || { name: mapId, color:'var(--text-3)' };
  const pad = size === 'lg' ? '3px 10px' : '1px 7px';
  const fs  = size === 'lg' ? 11 : 10;
  return (
    <span style={{ padding:pad, background:'var(--bg-4)', border:'1px solid var(--border-2)',
      borderRadius:'var(--r-sm)', fontSize:fs, fontWeight:700, color:map.color,
      letterSpacing:'0.06em', fontFamily:'var(--font-cond)', textTransform:'uppercase' }}>
      {map.name}
    </span>
  );
}

// ── CountUp ──────────────────────────────────────────────────────────────────
function CountUp({ to, duration = 900 }) {
  const [val, setVal] = useState(0);
  useEffect(() => {
    const start = performance.now();
    let raf;
    function tick(now) {
      const p = Math.min((now - start) / duration, 1);
      const e = 1 - Math.pow(1 - p, 3);
      setVal(Math.round(to * e));
      if (p < 1) raf = requestAnimationFrame(tick);
    }
    raf = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(raf);
  }, [to]);
  return <>{val.toLocaleString('pt-BR')}</>;
}

// ── SectionLabel ─────────────────────────────────────────────────────────────
function SectionLabel({ label, right }) {
  return (
    <div style={{ display:'flex', alignItems:'center', gap:10, marginBottom:8 }}>
      <span style={{ fontFamily:'var(--font-cond)', fontWeight:700, fontSize:10,
        color:'var(--text-3)', letterSpacing:'0.12em', textTransform:'uppercase', whiteSpace:'nowrap' }}>
        {label}
      </span>
      <div style={{ flex:1, height:1, background:'var(--border-1)' }} />
      {right && <span style={{ fontSize:10, color:'var(--text-3)', whiteSpace:'nowrap' }}>{right}</span>}
    </div>
  );
}

// ── Country flag ─────────────────────────────────────────────────────────────
const FLAG_CODES = {
  '🇧🇷':'br', '🇺🇦':'ua', '🇸🇪':'se', '🇵🇱':'pl', '🇺🇸':'us', '🇫🇷':'fr',
  '🇩🇰':'dk', '🇧🇦':'ba', '🇸🇰':'sk', '🇷🇺':'ru', '🇨🇦':'ca', '🇪🇪':'ee',
  '🇱🇹':'lt', '🇳🇴':'no', '🇱🇻':'lv', '🇪🇺':'eu', '🇮🇱':'il', '🌍':'eu'
};
Object.assign(FLAG_CODES, {
  '🇧🇷':'br', '🇺🇦':'ua', '🇸🇪':'se', '🇵🇱':'pl', '🇺🇸':'us', '🇫🇷':'fr',
  '🇩🇰':'dk', '🇧🇦':'ba', '🇸🇰':'sk', '🇷🇺':'ru', '🇨🇦':'ca', '🇪🇪':'ee',
  '🇱🇹':'lt', '🇳🇴':'no', '🇱🇻':'lv', '🇪🇺':'eu', '🇮🇱':'il', '🌍':'eu',
  '🇦🇺':'eu', '🇭🇺':'eu', '🇫🇮':'eu', '🇰🇿':'eu'
});
const FLAG_ASSET_CODES = new Set(['ba','br','ca','dk','ee','eu','fr','il','lt','lv','no','pl','ru','se','sk','ua','us']);
function resolveFlagCode(value) {
  const raw = String(value || '').trim();
  const token = raw.split(/\s+/)[0] || raw;
  const mapped = FLAG_CODES[token] || FLAG_CODES[raw];
  if (mapped) return mapped;

  const chars = [...token];
  const first = chars[0]?.codePointAt(0);
  const second = chars[1]?.codePointAt(0);
  if (first === 0x1f30d) return 'eu';
  if (first >= 0x1f1e6 && first <= 0x1f1ff && second >= 0x1f1e6 && second <= 0x1f1ff) {
    const code = String.fromCharCode(first - 0x1f1e6 + 97) + String.fromCharCode(second - 0x1f1e6 + 97);
    return FLAG_ASSET_CODES.has(code) ? code : 'eu';
  }

  const lower = token.toLowerCase().slice(0, 2);
  return FLAG_ASSET_CODES.has(lower) ? lower : 'eu';
}
function Flag({ value, size = 15 }) {
  const code = resolveFlagCode(value);
  return (
    <img
      src={`/assets/flags/${code}.svg`}
      alt={value || code.toUpperCase()}
      title={value || code.toUpperCase()}
      style={{ width:size, height:size, objectFit:'contain', flexShrink:0, verticalAlign:'-2px' }}
      loading="lazy"
    />
  );
}

// ── TierBadge ────────────────────────────────────────────────────────────────
const TIER_SHORT = { GE:'GE', SM:'SM', LEM:'LEM', MG:'MG', GN:'GN' };
const TIER_RANK_IMG = {
  GE:'/assets/ranks/global.png',
  SM:'/assets/ranks/supreme.png',
  LEM:'/assets/ranks/eagle.png',
  MG:'/assets/ranks/guardian.png',
  GN:'/assets/ranks/nova.png'
};
function TierBadge({ tier, short = false }) {
  const meta = window.TIER_META[tier] || window.TIER_META.GN;
  return (
    <span style={{ display:'inline-flex', alignItems:'center', gap:4, padding:'1px 6px 1px 2px', borderRadius:'var(--r-sm)',
      background:meta.bg, color:meta.color,
      fontSize:9, fontWeight:800, letterSpacing:'0.1em',
      fontFamily:'var(--font-cond)', textTransform:'uppercase', whiteSpace:'nowrap',
      border:`1px solid ${meta.color}30` }}>
      <img src={TIER_RANK_IMG[tier] || TIER_RANK_IMG.GN} alt={meta.label}
        style={{ width:32, height:13, objectFit:'cover', borderRadius:'1px', border:'1px solid rgba(0,0,0,0.35)' }}
        loading="lazy" />
      {short ? TIER_SHORT[tier] : meta.label}
    </span>
  );
}

// ── RoleBadge ────────────────────────────────────────────────────────────────
function RoleBadge({ role, size = 'sm' }) {
  const meta = window.ROLE_META[role] || { color:'var(--text-3)', bg:'var(--bg-4)', label: role };
  const fs = size === 'lg' ? 11 : 9;
  return (
    <span style={{ padding:`1px ${size==='lg'?9:6}px`, borderRadius:'var(--r-sm)',
      background:meta.bg, color:meta.color,
      fontSize:fs, fontWeight:800, letterSpacing:'0.1em',
      fontFamily:'var(--font-cond)', textTransform:'uppercase',
      border:`1px solid ${meta.color}30` }}>
      {meta.label}
    </span>
  );
}

// ── MiniStatBar ──────────────────────────────────────────────────────────────
function MiniStatBar({ label, value }) {
  const pct = Math.round((value / 99) * 100);
  const color = pct >= 90 ? 'var(--accent)' : pct >= 75 ? '#8a9cb4' : 'var(--text-3)';
  return (
    <div style={{ display:'flex', alignItems:'center', gap:5 }}>
      <span style={{ fontFamily:'var(--font-cond)', fontSize:8, fontWeight:700, color:'var(--text-3)',
        letterSpacing:'0.08em', width:24, textTransform:'uppercase' }}>{label}</span>
      <div style={{ flex:1, height:2, background:'var(--bg-5)', borderRadius:1 }}>
        <div style={{ height:'100%', width:`${pct}%`, background:color,
          borderRadius:1, transition:'width 400ms ease' }} />
      </div>
      <span style={{ fontFamily:'var(--font-mono)', fontSize:9, color, width:18, textAlign:'right' }}>
        {value}
      </span>
    </div>
  );
}

// ── PlayerCard ───────────────────────────────────────────────────────────────
function PlayerCard({ player, state = 'available', onRecruit, compact = false }) {
  // state: 'available' | 'blocked' | 'recruited' | 'display'
  const [hov, setHov] = useState(false);
  const isBlocked   = state === 'blocked';
  const isRecruited = state === 'recruited';
  const canClick    = state === 'available';

  const tier = window.TIER_META[player.tier] || window.TIER_META.GN;

  const border = isRecruited ? 'rgba(244,165,35,0.45)'
               : hov && canClick ? 'var(--border-3)'
               : 'var(--border-2)';
  const bg = isRecruited ? 'rgba(244,165,35,0.07)'
           : hov && canClick ? 'var(--bg-4)'
           : 'var(--bg-3)';

  return (
    <div
      data-sound={canClick ? 'pick' : undefined}
      onClick={() => canClick && onRecruit && onRecruit(player)}
      onMouseEnter={() => setHov(true)}
      onMouseLeave={() => setHov(false)}
      style={{
        background:bg, border:`1px solid ${border}`,
        borderRadius:'var(--r-lg)', padding: compact ? '8px 10px' : '12px',
        cursor: canClick ? 'pointer' : 'default',
        opacity: isBlocked ? 0.32 : 1,
        transition:'all 140ms ease',
        position:'relative', userSelect:'none',
      }}
    >
      {isBlocked && (
        <div style={{ position:'absolute', inset:0, display:'flex', alignItems:'center',
          justifyContent:'center', zIndex:2, borderRadius:'var(--r-lg)',
          background:'rgba(11,12,13,0.55)' }}>
          <span style={{ fontFamily:'var(--font-cond)', fontSize:9, fontWeight:800,
            color:'var(--text-3)', letterSpacing:'0.12em' }}>BLOQUEADO</span>
        </div>
      )}

      {/* Top row: overall + badges */}
      <div style={{ display:'flex', alignItems:'flex-start', justifyContent:'space-between', marginBottom: compact ? 5 : 8, gap:6 }}>
        <span style={{ fontFamily:'var(--font-mono)', fontSize: compact ? 20 : 26, fontWeight:700,
          color: isRecruited ? 'var(--accent)' : tier.color, lineHeight:1 }}>
          {player.overall}
        </span>
        <div style={{ display:'flex', flexDirection:'column', alignItems:'flex-end', gap:4 }}>
          <RoleBadge role={player.role} />
          <TierBadge tier={player.tier} short />
        </div>
      </div>

      {/* Name + meta */}
      <div style={{ marginBottom: compact ? 0 : 8 }}>
        <div style={{ fontFamily:'var(--font-cond)', fontWeight:800, fontSize: compact ? 13 : 15,
          color: isRecruited ? 'var(--accent)' : 'var(--text-1)', letterSpacing:'0.02em',
          transition:'color 120ms ease' }}>
          <span style={{ display:'inline-flex', alignItems:'center', gap:5, minWidth:0 }}>
            <Flag value={player.country} />
            <span style={{ overflow:'hidden', textOverflow:'ellipsis', whiteSpace:'nowrap' }}>{player.name}</span>
          </span>
          {isRecruited && <span style={{ marginLeft:6, color:'var(--accent)', fontSize:11 }}>✓</span>}
        </div>
        <div style={{ fontFamily:'var(--font-cond)', fontSize:9, color:'var(--text-3)',
          letterSpacing:'0.08em', textTransform:'uppercase', marginTop:1 }}>
          {player.era}
        </div>
      </div>

      {/* Stat bars (hidden in compact) */}
      {!compact && (
        <div style={{ display:'flex', flexDirection:'column', gap:3 }}>
          {[['AIM',player.s.aim],['ENT',player.s.entry],['CLU',player.s.clutch],
            ['UTL',player.s.util],['MOV',player.s.move]].map(([l,v]) => (
            <MiniStatBar key={l} label={l} value={v} />
          ))}
        </div>
      )}

      {canClick && hov && !compact && (
        <div style={{ marginTop:8, padding:'5px 0', textAlign:'center',
          fontFamily:'var(--font-cond)', fontSize:10, fontWeight:800,
          color:'var(--accent)', letterSpacing:'0.1em' }}>
          RECRUTAR
        </div>
      )}
    </div>
  );
}

// ── Header ───────────────────────────────────────────────────────────────────
function LanguageToggle({ locale = 'pt-BR', onLocaleChange }) {
  const activeLocale = ['pt-BR', 'en', 'ru'].includes(locale) ? locale : 'pt-BR';
  const options = [
    { id:'pt-BR', label:window.I18N?.text('language.pt') || 'PT-BR', flag:'br' },
    { id:'en', label:window.I18N?.text('language.en') || 'EN', flag:'us' },
    { id:'ru', label:window.I18N?.text('language.ru') || 'RU', flag:'ru' },
  ];
  return (
    <div aria-label={window.I18N?.text('language.label') || 'Idioma'}
      style={{ display:'inline-flex', alignItems:'center', gap:3,
        padding:3, background:'var(--bg-2)', border:'1px solid var(--border-2)',
        borderRadius:'var(--r-md)', flexShrink:0 }}>
      {options.map(option => {
        const active = activeLocale === option.id;
        return (
          <button key={option.id} type="button" data-sound="option"
            onClick={() => onLocaleChange?.(option.id)}
            aria-label={`${window.I18N?.text('language.label') || 'Idioma'}: ${option.label}`}
            style={{ minWidth:58, height:26, border:'1px solid',
              borderColor:active ? 'rgba(244,165,35,0.36)' : 'transparent',
              borderRadius:'var(--r-sm)', background:active ? 'rgba(244,165,35,0.14)' : 'transparent',
              color:active ? 'var(--accent)' : 'var(--text-3)', cursor:'pointer',
              display:'inline-flex', alignItems:'center', justifyContent:'center', gap:5,
              fontFamily:'var(--font-cond)', fontSize:10, fontWeight:800,
              letterSpacing:'0.08em', textTransform:'uppercase',
              transition:'background 120ms ease, border-color 120ms ease, color 120ms ease' }}>
            <window.Flag value={option.flag} size={14} />
            <span>{option.label}</span>
          </button>
        );
      })}
    </div>
  );
}

function GameHeader({ phase, subLabel, locale = 'pt-BR', onLocaleChange }) {
  return (
    <header style={{ background:'var(--bg-0)', borderBottom:'1px solid var(--border-2)',
      position:'sticky', top:0, zIndex:100 }}>
      <div style={{ maxWidth:1360, margin:'0 auto', padding:'0 30px',
        height:46, display:'flex', alignItems:'center',
        justifyContent:'space-between', gap:16 }}>

        <div style={{ flexShrink:0 }}>
          <span style={{ fontFamily:'var(--font-cond)', fontWeight:800, fontSize:22,
            letterSpacing:'-0.01em', lineHeight:1 }}>
            <span style={{ color:'var(--text-1)' }}>16</span>
            <span style={{ color:'var(--text-3)', fontWeight:600 }}>x</span>
            <span style={{ color:'var(--accent)' }}>0</span>
          </span>
        </div>

        {subLabel && (
          <div style={{ display:'flex', alignItems:'center', gap:8 }}>
            <span style={{ color:'var(--border-3)', fontSize:10 }}>·</span>
            <span style={{ fontFamily:'var(--font-cond)', fontSize:11, fontWeight:700,
              color:'var(--text-2)', letterSpacing:'0.1em', textTransform:'uppercase',
              whiteSpace:'nowrap' }}>
              {subLabel}
            </span>
          </div>
        )}
        <div style={{ flex:1 }} />
        <LanguageToggle locale={locale} onLocaleChange={onLocaleChange} />
      </div>
    </header>
  );
}

Object.assign(window, {
  LiveDot, MapBadge, CountUp, SectionLabel,
  Flag, TierBadge, RoleBadge, MiniStatBar, PlayerCard, GameHeader, LanguageToggle,
  useIsMobileView, scrollToTopOnMobile,
});
