/* ============================================================
FIFA EDGE — H2H Match Detail view
============================================================ */
const { useState: useSh, useMemo: useMh, useEffect: useEh } = React;
function pickPlayer(id) { return PLAYERS.find(p => p.id === id) || PLAYERS[0]; }
const H2H_EMPTY = {
h2h: { games: 0, aWins: 0, draws: 0, bWins: 0, avgGoals: 0, overRate: 0, bttsRate: 0 },
recent: [],
overLines: [
{ line: 0.5, a: 0, b: 0 }, { line: 1.5, a: 0, b: 0 }, { line: 2.5, a: 0, b: 0 },
{ line: 3.5, a: 0, b: 0 }, { line: 4.5, a: 0, b: 0 }, { line: 5.5, a: 0, b: 0 },
],
underLines: [
{ line: 1.5, a: 0, b: 0 }, { line: 2.5, a: 0, b: 0 },
{ line: 3.5, a: 0, b: 0 }, { line: 4.5, a: 0, b: 0 },
],
goalsByMin: [],
dailyDist: Array.from({length: 24}, (_, i) => ({ h: String(i).padStart(2,'0'), a: 0, b: 0 })),
mostFrequent: [],
bothScore: [
['Ambos marcaram 1T', 0], ['Ambos marcaram 2T', 0],
['Nenhum marcou 1T', 0], ['Nenhum marcou 2T', 0],
],
};
const H2HDetail = ({ matchId, onBack }) => {
const m = MATCHES.find(x => x.id === matchId) || MATCHES[0];
if (!m) return
Jogo não encontrado. Voltar
;
const A = m.home, B = m.away;
const [data, setData] = useSh(H2H_EMPTY);
useEh(() => {
if (!A?.handle || !B?.handle) return;
const url = `/api/h2h?home=${encodeURIComponent(A.handle)}&away=${encodeURIComponent(B.handle)}`;
fetch(url, { cache: 'no-store' })
.then(r => r.ok ? r.json() : null)
.then(d => { if (d) setData({ ...H2H_EMPTY, ...d }); })
.catch(err => console.warn('[h2h] fetch failed', err));
}, [A?.handle, B?.handle]);
const { h2h, recent, overLines, underLines, goalsByMin, dailyDist, mostFrequent, bothScore } = data;
const ap = A.wr, bp = B.wr, dp = 1 - ap - bp + 0.15;
const total = ap + bp + dp;
const pctA = Math.round((ap/total)*100), pctB = Math.round((bp/total)*100), pctD = 100 - pctA - pctB;
const overBar = (v) => (
{v.line}
{v.a.toFixed(1)}%
);
const underBar = (v) => (
{v.line}
{v.a.toFixed(1)}%
);
return (
<>
‹ Voltar
Confronto direto · {A.handle} vs {B.handle}
Kickoff {window.fmtHM(m.kickoff)} (SP) · {m.league} · T-{m.minuteToKO}m
Salvar
Enviar tip
{/* ===== Hero head-to-head ===== */}
{A.handle.slice(0,2).toUpperCase()}
{A.handle}
{A.team}
ÚLTIMOS 10 PARTIDAS
BTTS {(h2h.bttsRate*100).toFixed(0)}%
O2.5 {(h2h.overRate*100).toFixed(0)}%
AVG {h2h.avgGoals}
{B.handle.slice(0,2).toUpperCase()}
{B.handle}
{B.team}
{/* Pro notice */}
Visão parcial · dados de 6 partidas recentes
Para o histórico completo e mercados consolidados, ative PRO + LIVE + BOT no plano operador.
Ativar
{/* Top KPIs */}
{/* ===== Over/Under grids ===== */}
Over/Under (Partida) — {A.handle}
Over Under
{overLines.map(v => overBar(v))}
Handicap Asiático — LIVE
0.0 ±0.5 ±1.0
Linha
{A.handle}
{B.handle}
{[[-2, 12.4, 47.8], [-1.5, 21.3, 36.2], [-1, 32.4, 28.1], [-0.5, 42.8, 22.4], [0, 52.6, 18.7], [+0.5, 64.1, 13.2], [+1, 72.4, 9.8]].map((r,i) => (
{r[0] > 0 ? '+' : ''}{r[0]}
50?'var(--win)':'var(--loss)'}}>{r[1].toFixed(1)}%
50?'var(--win)':'var(--loss)'}}>{r[2].toFixed(1)}%
))}
Over (1º tempo) — {A.handle}
{[{line:0.5,a:72.4},{line:1.5,a:41.8},{line:2.5,a:18.9}].map(v => overBar(v))}
Over (1º tempo) — {B.handle}
{[{line:0.5,a:68.1},{line:1.5,a:37.4},{line:2.5,a:15.2}].map(v => overBar(v))}
{underLines.map(v => underBar(v))}
{underLines.map(v => underBar({...v, a: v.a*0.9}))}
{/* Média gols / Estatísticas da partida */}
{A.handle}
Tempo
{B.handle}
1.42
1º T
1.18
1.87
2º T
1.64
{[
['Posse média', 54.2, 45.8],
['Finalizações', 62.1, 37.9],
['Finalizações ao gol', 58.7, 41.3],
['xG médio', 55.4, 44.6],
['Escanteios', 51.8, 48.2],
].map((r,i)=>(
))}
{/* Ambos equipes marcam / Resultado mais frequente */}
{bothScore.map((r,i) => (
))}
Resultados mais frequentes
{mostFrequent.map((r,i) => (
))}
{/* Análise de time por equipe */}
{[A,B].map((P, ix) => (
Análise de time · {P.handle}
Time P V E D GP GC
{['Man City','Bayern','Liverpool','Real Madrid','PSG'].map((t,i)=>{
const pj = 3+i, v = pj-i, e = (i%2), d = pj-v-e;
return (
{t}
{pj}
{v}
{e}
{d}
{pj*2}
{pj}
);
})}
))}
{/* Média de pontos linha tempo */}
Média de pontos (média móvel · 12 jogos)
{[1,2,3,4,5].map(y => )}
{[0,1,2,3,4,5,6].map(y => {y} )}
● {A.handle}
● {B.handle}
{/* Distribuição diária */}
Distribuição diária de partidas (por hora UTC)
{dailyDist.map((d,i) => (
))}
{/* Histórico de partidas */}
Histórico de partidas
ÚLTIMAS 6
{recent.map((r,i) => (
r.scB?'var(--text-0)':'var(--text-2)', fontWeight:r.scA>r.scB?600:400}}>{A.handle} {A.team}
{r.scA} : {r.scB}
r.scA?'var(--text-0)':'var(--text-2)', fontWeight:r.scB>r.scA?600:400}}>{B.team} {B.handle}
{r.date}
))}
{/* Últimas partidas por player */}
{[A,B].map(P => (
Últimas partidas · {P.handle}
{P.form.slice(0,5).map((r,i) => (
{P.handle}
{r==='w'?'2 : 1':r==='d'?'1 : 1':'0 : 2'}
Opponent_{i+1}
))}
))}
{/* Insights text */}
Histórico de confrontos · análise
ÚLT. ATUALIZAÇÃO: 19/04 18:00 UTC
● Visão Geral
Em {h2h.games} confrontos entre {A.handle} e {B.handle}, {A.handle} venceu {h2h.aWins} vezes, {B.handle} venceu {h2h.bWins}, com {h2h.draws} empates. ELO atual {A.elo} vs {B.elo} favorece {A.elo>B.elo?A.handle:B.handle} por {Math.abs(A.elo-B.elo)} pontos.
● Performance
Nos últimos confrontos diretos, {A.handle} acumulou {(A.wr*100).toFixed(0)}% de vitórias, enquanto {B.handle} manteve {(B.wr*100).toFixed(0)}% aproveitamento. Over 2.5 bateu em {(h2h.overRate*100).toFixed(0)}% das partidas.
>
);
};
Object.assign(window, { H2HDetail });