import React from "react"; import { Zap, ExternalLink } from "lucide-react"; import { CHIP_CONFIG } from "../utils/fplLogic"; export const SolverOutputPanel = ({ pendingSolutions, setPendingSolutions, isSolving, globalPlayers, applySolution, appliedPlanSummary, setAppliedPlanSummary, baselineEv = 0,comprehensiveSettings }) => { // BULLETPROOF RELATIVE EV const getRelativeEv = (sol) => { if (baselineEv === undefined || !sol) return "+0.00"; const base = sol.lockedBaselineEv !== undefined ? sol.lockedBaselineEv : baselineEv; if (typeof sol === "number") { const diff = sol - base; return diff >= 0 ? `+${diff.toFixed(2)}` : diff.toFixed(2); } if (!sol.plan || !Array.isArray(sol.plan) || sol.plan.length === 0) { const fallbackEv = sol.ev !== undefined ? sol.ev : 0; const diff = fallbackEv - base; return diff >= 0 ? `+${diff.toFixed(2)}` : diff.toFixed(2); } let pathEV = 0; let hasValidGw = false; sol.plan.forEach(gwPlan => { const gw = gwPlan.gw; if (gw === undefined) return; hasValidGw = true; const gwChip = gwPlan.chip; const gwCapMult = gwChip === "tc" ? 3 : 2; let gwPts = 0; const getPlayer = (id) => globalPlayers.find(p => String(p.ID) === String(id)); (gwPlan.lineup || []).forEach(id => { const p = getPlayer(id); if (p && !p.isBlank) { const pts = Number(p[`${gw}_Pts`]) || 0; gwPts += pts * (String(p.ID) === String(gwPlan.captain) ? gwCapMult : 1); } }); let ofIdx = 0; (gwPlan.bench || []).forEach(id => { const p = getPlayer(id); if (p && !p.isBlank) { const pts = Number(p[`${gw}_Pts`]) || 0; if (gwChip === "bb") { gwPts += pts; } else { // THE FIX: Output Panel now perfectly matches Python and the main UI! const rawBw = comprehensiveSettings?.bench_weights || { 0: 0.03, 1: 0.21, 2: 0.06, 3: 0.002 }; const gkWeight = Number(rawBw[0] || 0.03); const outWeights = [Number(rawBw[1] || 0.21), Number(rawBw[2] || 0.06), Number(rawBw[3] || 0.002)]; if (p.Pos === "G") { gwPts += pts * gkWeight; } else { gwPts += pts * (outWeights[ofIdx] || 0.02); ofIdx++; } } } }); pathEV += gwPts - (gwPlan.hits || 0) * 4; }); if (!hasValidGw || Number.isNaN(pathEV)) { const fallbackEv = sol.ev !== undefined ? sol.ev : 0; const diff = fallbackEv - base; return diff >= 0 ? `+${diff.toFixed(2)}` : diff.toFixed(2); } const diff = pathEV - base; return diff >= 0 ? `+${diff.toFixed(2)}` : diff.toFixed(2); }; return (
{/* Left Side: Original Title & Description */}

Solver output

Nothing changes your squad until you apply a path.

{/* Right Side: Sleek, Minimalist Credit */} {/* Right Side: Sleek, Minimalist Credit */} Credit Sertalp-Moose Solver
{pendingSolutions.length > 0 && !isSolving && (

Optimal Paths Found

{pendingSolutions.map((sol, index) => (
ITERATION {sol.id || index + 1} {sol.chips_used && Object.entries(sol.chips_used).map(([gw, chip]) => { const cfg = CHIP_CONFIG[chip]; return cfg ? {cfg.short}{gw} : null; })}
{getRelativeEv(sol)} pts {sol.objective_score != null && eval: {sol.objective_score.toFixed(2)}}
{sol.plan.map((gwPlan) => ( (gwPlan.transfers_in.length > 0 || gwPlan.transfers_out.length > 0) && (
GW {gwPlan.gw} {gwPlan.chip && CHIP_CONFIG[gwPlan.chip] && {CHIP_CONFIG[gwPlan.chip].short}{gwPlan.gw}}
ITB: £{Math.abs(gwPlan.itb) < 0.05 ? "0.0" : Number(gwPlan.itb).toFixed(1)} FT Spend: {gwPlan.chip === "wc" || gwPlan.chip === "fh" ? `${gwPlan.transfers_out?.length || 0}/∞` : `${gwPlan.transfers_out?.length || 0}/${gwPlan.ft_at_start ?? 1}${gwPlan.hits > 0 ? ` (-${gwPlan.hits * 4})` : ""}`}
{gwPlan.chip === "wc" || gwPlan.chip === "fh" ?

{gwPlan.chip === "wc" ? "Wildcard active — unlimited free transfers" : "Free Hit active — squad reverts after the FH"}

: null} {gwPlan.transfers_out.map((id, i) => (
{globalPlayers.find((p) => String(p.ID) === String(id))?.Name || id} » {globalPlayers.find((p) => String(p.ID) === String(gwPlan.transfers_in[i]))?.Name || gwPlan.transfers_in[i]}
))}
) ))}
))}
)} {!isSolving && pendingSolutions.length === 0 && ( appliedPlanSummary ? (

Last Applied · {appliedPlanSummary.horizon}

{getRelativeEv(appliedPlanSummary)} pts {appliedPlanSummary.objectiveScore != null && ` · eval ${appliedPlanSummary.objectiveScore.toFixed(2)}`}
{appliedPlanSummary.transfers.map((t, i) => (
GW {t.gw} {t.chip && CHIP_CONFIG[t.chip] && {CHIP_CONFIG[t.chip].short}{t.gw}}
FT Spend: {t.chip === "wc" || t.chip === "fh" ? `${t.outs?.length || 0}/∞` : `${t.outs?.length || 0}/${t.ft_at_start ?? 1}${t.hits > 0 ? ` (-${t.hits * 4})` : ""}`} £{Math.abs(t.itb) < 0.05 ? "0.0" : Number(t.itb).toFixed(1)}m
{t.outs.length === 0 && t.ins.length === 0 ? ( {t.chip ? `${CHIP_CONFIG[t.chip]?.label || t.chip} active` : 'Hold — no transfers'} ) : ( t.outs.map((name, j) => (
{name} » {t.ins[j] || "?"}
)) )}
))}
) : (
Configure settings and hit Solve in the left panel.
) )}
); };