/* SINAIS FIFA — Player stats modal (dados reais do banco) */ const { useState: useS_P, useEffect: useE_P, useRef: useR_P } = React; const PLAYER_LOADING_STEPS = [ 'Conectando ao motor estatístico…', 'Lendo padrões ELO + λ Poisson do jogador…', 'Compilando últimos confrontos…', 'Calculando médias e tendências…', ]; const PLAYER_SAMPLE_SIZES = [5, 10, 15, 20]; const FormChipP = ({ result }) => ( {result} ); const PlayerModal = ({ player, onClose }) => { const [phase, setPhase] = useS_P('idle'); // idle | loading | analysis | error const [step, setStep] = useS_P(0); const [sample, setSample] = useS_P(10); const [data, setData] = useS_P(null); const [errMsg, setErrMsg] = useS_P(''); const stepRef = useR_P(null); useE_P(() => () => { if (stepRef.current) clearInterval(stepRef.current); }, []); const generate = async () => { if (!player.id) { setErrMsg('player sem id no banco'); setPhase('error'); return; } setPhase('loading'); setStep(0); setErrMsg(''); setData(null); stepRef.current = setInterval(() => { setStep(s => Math.min(s + 1, PLAYER_LOADING_STEPS.length - 1)); }, 360); try { const res = await fetch(`/api/player/${encodeURIComponent(player.id)}?sample=${sample}`); if (!res.ok) { const detail = await res.json().catch(() => ({})); throw new Error(detail.detail || `HTTP ${res.status}`); } const body = await res.json(); const elapsed = (PLAYER_LOADING_STEPS.length - 1) * 360; const wait = Math.max(0, 1300 - elapsed); setTimeout(() => { clearInterval(stepRef.current); setStep(PLAYER_LOADING_STEPS.length - 1); setData(body); setPhase('analysis'); }, wait); } catch (e) { clearInterval(stepRef.current); setErrMsg(e.message || 'falha ao carregar estatísticas'); setPhase('error'); } }; return (
e.stopPropagation()}>

Estatísticas · {player.handle}

{player.team} · {player.games} jogos · ROI {player.roi >= 0 ? '+' : ''}{player.roi}%

{phase === 'idle' && (
{player.handle.slice(0,2).toUpperCase()}
{player.handle}
{player.team}
{player.wr}%win rate {player.roi >= 0 ? '+' : ''}{player.roi}%roi {player.games}jogos
Base de análise · últimos N jogos
{PLAYER_SAMPLE_SIZES.map(n => ( ))}
)} {phase === 'loading' && (
{PLAYER_LOADING_STEPS.map((s, i) => (
{s}
))}
)} {phase === 'error' && (
⚠️
Falha ao carregar estatísticas
{errMsg}
)} {phase === 'analysis' && data && ( <>
base · últimos {sample} jogos
Forma recente · últimos 10
{data.recent.length === 0 && sem histórico} {data.recent.map((r, i) => )}
ELO · momentum
{data.elo}
elo atual
= 0 ? 'up' : 'down'}`}> {data.momentum >= 0 ? '↑' : '↓'} {Math.abs(data.momentum)}
{data.streak.n > 0 ? `${data.streak.n}${data.streak.type}` : '—'}
streak
Gols feitos/jogo
{data.goalsFor}
Gols sofridos/jogo
{data.goalsAgainst}
Clean sheets
{data.cleanSheet}%
BTTS
{data.btts}%
Over 2.5 hits
{data.overHits}/{data.overTotal}
WR jogando em casa
{data.homeWR}%
WR jogando fora
{data.awayWR}%
Últimos confrontos resultado · placar
{data.matches.length === 0 && (
sem confrontos no período
)} {data.matches.map((m, i) => (
{m.res}
{m.home ? 'vs' : '@'} {m.opp}
{m.daysAgo}d atrás · {m.home ? 'casa' : 'fora'}
{m.gf} {m.ga}
))}
)}
); }; window.PlayerModal = PlayerModal;