import React, { useState, useEffect, useMemo, useContext, useRef } from "react";
import { createPortal } from "react-dom";
import { Search, Loader2, RotateCcw, Shield, Settings, Zap, Plus, Copy, Trash2 } from "lucide-react";
import { DndContext, DragOverlay, closestCenter, PointerSensor, useSensor, useSensors } from "@dnd-kit/core";
import { PlayerContext } from "../PlayerContext";
import { CHIP_CONFIG, getPlayerPrice, normalizeBenchGkFirst,getOptimalLayout } from "../utils/fplLogic";
import { useFplSolverApi } from "../hooks/useFplSolverApi";
import { SolverOutputPanel } from "./SolverOutputPanel";
import { PitchView } from "./PitchView";
import { PlayerEditModal, PlayerSearchModal } from "./PlayerModals";
import { PlayerCardVisual } from "./PlayerCardVisual";
import { TabsPanel } from "./TabsPanel";
import { AdvancedSettingsModal, DEFAULT_SETTINGS } from "./AdvancedSettingsModal";
import { ActiveMovesPanel } from "./ActiveMovesPanel";
import { DraftsComparisonTable } from "./DraftsComparisonTable";

export default function Solver() {
  const {
    globalPlayers, updatePlayerStat, isLoadingDB, teamId, setTeamId, teamData, setTeamData, availableGWs, setAvailableGWs, horizon, setHorizon, activeGW, setActiveGW, captainId, setCaptainId, viceId, setViceId, initialSquadIds, setInitialSquadIds, isLoggedIn, userProfile, setUserProfile, manualOverrides, setManualOverrides, highlightTransferIds, setHighlightTransferIds, transfersByGw, setTransfersByGw, chipsByGw, setChipsByGw, baselineItb, setBaselineItb, baselineFt, setBaselineFt, availableFts, setAvailableFts, itb, setItb, HIT_COST, ftAtStartOfGw, quickSettings, setQuickSettings, advancedSettings, setAdvancedSettings, numSims, setNumSims, comprehensiveSettings, setComprehensiveSettings, appliedPlanSummary, setAppliedPlanSummary, solverApplySnapshot, setSolverApplySnapshot, solverTransferPairs, setSolverTransferPairs, solveElapsedSec, setSolveElapsedSec, drafts, setDrafts, activeDraftId, setActiveDraftId, fixtureOverrides, sessionEdits
  } = useContext(PlayerContext);

  // --- THE PRISTINE VAULT ---
  const pristineSquadRef = useRef({});

  useEffect(() => {
    if (teamData.length > 0 && globalPlayers.length > 0 && availableGWs?.length > 0) {
      setTeamData(prevTeam => {
        let hasChanges = false;
        const newTeam = prevTeam.map(p => {
          if (p.isBlank) return p;
          const fresh = globalPlayers.find(g => String(g.ID) === String(p.ID));
          if (!fresh) return p;
          
          let needsUpdate = false;
          for (const gw of availableGWs) {
            if (p[`${gw}_Pts`] !== fresh[`${gw}_Pts`] || p[`${gw}_xMins`] !== fresh[`${gw}_xMins`]) {
              needsUpdate = true;
              break;
            }
          }
          
          if (needsUpdate) {
            hasChanges = true;
            // Inherits the fresh stats while fiercely protecting the locked financial data
            return { ...p, ...fresh, purchase_price: p.purchase_price, selling_price: p.selling_price, Price: p.Price, now_cost: p.now_cost };
          }
          return p;
        });
        return hasChanges ? newTeam : prevTeam;
      });
    }
  }, [globalPlayers, availableGWs]);

  const [pendingAutoReset, setPendingAutoReset] = useState(false);
  const lastOverridesRef = useRef(fixtureOverrides);

  // Watches for fixture changes and queues an auto-reset for when the math finishes
  useEffect(() => {
    // THE FIX: Stringify the objects so React compares the actual data, not the memory address!
    const currentStr = JSON.stringify(fixtureOverrides || {});
    const lastStr = JSON.stringify(lastOverridesRef.current || {});
    
    if (lastStr !== currentStr) {
      lastOverridesRef.current = fixtureOverrides;
      setPendingAutoReset(true);
    }
  }, [fixtureOverrides]);

  // --- STRICT VAULT-BASED PLAYER FACTORY ---
  const hydratePlayer = (id, knownPristineData = null) => {
    const globalMatch = globalPlayers.find((p) => String(p.ID) === String(id));
    if (!globalMatch) return null;

    // 1. Trust explicit overrides (like when clicking 'undo transfer')
    if (knownPristineData && typeof knownPristineData === "object" && knownPristineData.purchase_price !== undefined) {
      const hydrated = { 
        ...globalMatch, // Absolute source of truth for stats
        purchase_price: knownPristineData.purchase_price,
        selling_price: knownPristineData.selling_price,
        multiplier: knownPristineData.multiplier,
        is_captain: knownPristineData.is_captain,
        is_vice_captain: knownPristineData.is_vice_captain
      };
      hydrated.now_cost = globalMatch.now_cost !== undefined ? globalMatch.now_cost : globalMatch.Price;
      hydrated.Price = hydrated.selling_price !== undefined ? hydrated.selling_price : getPlayerPrice(hydrated);
      return hydrated;
    }

    const marketCost = globalMatch.now_cost !== undefined ? globalMatch.now_cost : globalMatch.Price;
    const lockedBaselinePlayer = pristineSquadRef.current[id];

    // 2. CHECK THE CHAIN: Was this player sold in any previous gameweek?
    let isChainBroken = false;

    if (lockedBaselinePlayer && availableGWs && availableGWs.length > 0) {
      const pastGWs = availableGWs.filter(g => g < activeGW).sort((a, b) => a - b);
      for (const gw of pastGWs) {
        if (chipsByGw[gw] === "fh") continue;
        const mLock = manualOverrides[gw];
        if (mLock?.manualTransfers && Object.values(mLock.manualTransfers).some(p => String(p?.ID) === String(id))) {
          isChainBroken = true; break;
        }
        const sPairs = solverTransferPairs[gw];
        if (sPairs && Object.values(sPairs).some(pair => String(pair.outPlayer?.ID) === String(id))) {
          isChainBroken = true; break;
        }
      }
    } else {
      isChainBroken = true;
    }

    // 3. APPLY THE LOGIC
    let finalPurchasePrice, finalSellingPrice;

    if (lockedBaselinePlayer && !isChainBroken) {
      finalPurchasePrice = lockedBaselinePlayer.purchase_price;
      finalSellingPrice = lockedBaselinePlayer.selling_price !== undefined ? lockedBaselinePlayer.selling_price : getPlayerPrice(lockedBaselinePlayer);
    } else {
      finalPurchasePrice = marketCost;
      finalSellingPrice = marketCost;
    }

    const hydrated = {
      ...globalMatch, // Fresh stats unconditionally overlay everything!
      ...(lockedBaselinePlayer && !isChainBroken ? {
        purchase_price: lockedBaselinePlayer.purchase_price,
        selling_price: lockedBaselinePlayer.selling_price,
        multiplier: lockedBaselinePlayer.multiplier,
        is_captain: lockedBaselinePlayer.is_captain,
        is_vice_captain: lockedBaselinePlayer.is_vice_captain
      } : {}),
      purchase_price: finalPurchasePrice,
      selling_price: finalSellingPrice,
      Price: finalSellingPrice, 
      now_cost: marketCost
    };

    return hydrated;
  };

  const [isLoading, setIsLoading] = useState(false);
  const [error, setError] = useState(null);
  const [fixtures, setFixtures] = useState([]);
  const [isFixturesLoaded, setIsFixturesLoaded] = useState(false);
  const [activeDragPlayer, setActiveDragPlayer] = useState(null);
  const [selectedPlayer, setSelectedPlayer] = useState(null);
  const [searchQuery, setSearchQuery] = useState("");
  const [sortConfig, setSortConfig] = useState({ key: "ev", direction: "desc" });
  const [showIdPrompt, setShowIdPrompt] = useState(false);
  // --- DEFAULT ID ONBOARDING STATE ---
  const [showInitialIdPrompt, setShowInitialIdPrompt] = useState(false);
  const [initialIdInput, setInitialIdInput] = useState("");

  // Trigger popup if logged in but no default ID is set
  useEffect(() => {
    // THE FIX: Wait until the profile is fully hydrated (checking for .email) 
    // and the site has finished its initial load (!isLoadingDB) before prompting.
    if (isLoggedIn && userProfile && userProfile.email && !userProfile.defaultTeamId && !isLoadingDB) {
      setShowInitialIdPrompt(true);
    } else {
      setShowInitialIdPrompt(false);
    }
  }, [isLoggedIn, userProfile, isLoadingDB]);

  const handleSaveInitialId = () => {
    const parsedId = parseInt(initialIdInput);
    if (!parsedId) return;

    const token = localStorage.getItem('fpl_token');
    if (token) {
      fetch('https://anayshukla-fpl-solver.hf.space/api/auth/save_session', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` },
        body: JSON.stringify({ default_team_id: parsedId })
      });
      setUserProfile(prev => ({ ...prev, defaultTeamId: parsedId }));
      setTeamId(String(parsedId)); // Auto-load the ID for them
      setShowInitialIdPrompt(false);
    }
  };
  const [pendingTeamId, setPendingTeamId] = useState(null);
  const [lastLoadedId, setLastLoadedId] = useState(teamData.length > 0 ? teamId : null);

  const [solverTab, setSolverTab] = useState("solver");
  const [showAdvancedSettings, setShowAdvancedSettings] = useState(false);
  const [banSearch, setBanSearch] = useState("");
  const [lockSearch, setLockSearch] = useState("");
  const [chipSolveOptions, setChipSolveOptions] = useState({ wc: [], fh: [], bb: [], tc: [] });
  const [showDraftMenu, setShowDraftMenu] = useState(false);

  const [sensTimer, setSensTimer] = useState(0);
  const [chipSolveTimer, setChipSolveTimer] = useState(0);

  const abortControllerRef = useRef(null);
  const sensors = useSensors(useSensor(PointerSensor, { activationConstraint: { distance: 5 } }));

  const {
    isSolving, isChipSolving, isRunningSens, pendingSolutions, setPendingSolutions, chipSolveSolutions, setChipSolveSolutions, sensResults, setSensResults, sensViewGw, setSensViewGw, handleSolve: apiHandleSolve, handleChipSolve: apiHandleChipSolve, handleSensAnalysis: apiHandleSensAnalysis, loadSettingsFromCloud, saveSettingsToCloud
  } = useFplSolverApi(abortControllerRef);

  useEffect(() => {
    let interval;
    if (isRunningSens) { interval = setInterval(() => setSensTimer((t) => t + 1), 1000); } else { setSensTimer(0); }
    return () => clearInterval(interval);
  }, [isRunningSens]);

  useEffect(() => {
    let interval;
    if (isChipSolving) { interval = setInterval(() => setChipSolveTimer((t) => t + 1), 1000); } else { setChipSolveTimer(0); }
    return () => clearInterval(interval);
  }, [isChipSolving]);

  const maxAvailableHorizon = useMemo(() => (availableGWs.length ? Math.min(10, availableGWs.length) : 10), [availableGWs]);
  const horizonGWs = useMemo(() => (availableGWs.length ? availableGWs.slice(0, horizon) : []), [availableGWs, horizon]);
  const playerCardGWs = useMemo(() => {
    if (!horizonGWs.length || !activeGW) return [];
    const idx = horizonGWs.indexOf(activeGW);
    return idx === -1 ? [] : horizonGWs.slice(idx).slice(0, 3);
  }, [horizonGWs, activeGW]);
  const solveGWs = useMemo(() => {
    if (!horizonGWs.length || !activeGW) return horizonGWs;
    const idx = horizonGWs.indexOf(activeGW);
    return idx === -1 ? horizonGWs : horizonGWs.slice(idx);
  }, [horizonGWs, activeGW]);

  const solveGWLabel = useMemo(() => {
    if (!solveGWs.length) return "";
    return solveGWs.length === 1 ? `GW${solveGWs[0]}` : `GW${solveGWs[0]}–${solveGWs[solveGWs.length - 1]}`;
  }, [solveGWs]);

  const ownedPlayerIds = useMemo(() => new Set(teamData.filter((p) => !p.isBlank).map((p) => p.ID)), [teamData]);

  const hitsThisGw = useMemo(() => {
    const T = transfersByGw[activeGW]?.count || 0;
    const chip = chipsByGw[activeGW];
    if (chip === "wc" || chip === "fh") return 0;
    const startFt = ftAtStartOfGw(activeGW, availableGWs, baselineFt, transfersByGw, chipsByGw);
    return Math.max(0, T - startFt);
  }, [activeGW, availableGWs, baselineFt, transfersByGw, chipsByGw]);

  // 1. Standard state (can default to your hardcoded defaults initially)
  const [isCloudLoaded, setIsCloudLoaded] = useState(false);

  // 1. Fetch from Cloud on Mount / Login
  useEffect(() => {
    if (teamId && !isCloudLoaded) {
      loadSettingsFromCloud(teamId).then((cloudData) => {
        if (cloudData) {
          if (cloudData.quick) {
            setQuickSettings(prev => ({ ...prev, ...cloudData.quick }));
          }
          // THE FIX: Use setComprehensiveSettings!
          if (cloudData.advanced) {
            setComprehensiveSettings(prev => ({ ...prev, ...cloudData.advanced }));
          }
        }
        setIsCloudLoaded(true);
      });
    }
  }, [teamId]);

  // 2. Save to Cloud (DEBOUNCED)
  useEffect(() => {
    if (teamId && isCloudLoaded) {
      const timerId = setTimeout(() => {
        // THE FIX: Pass comprehensiveSettings instead of advancedSettings!
        saveSettingsToCloud(teamId, quickSettings, comprehensiveSettings);
      }, 500);
      return () => clearTimeout(timerId);
    }
    // THE FIX: Watch comprehensiveSettings in the dependency array!
  }, [quickSettings, comprehensiveSettings, teamId, isCloudLoaded]);

  const getValidLayout = (players, gw) => {
    if (!players || players.length !== 15) return null;
    const getEV = (p) => p.isBlank ? -1000 : (Number(p[`${gw}_Pts`]) || 0);

    let gks = players.filter((p) => p.Pos === "G").sort((a, b) => getEV(b) - getEV(a));
    let defs = players.filter((p) => p.Pos === "D").sort((a, b) => getEV(b) - getEV(a));
    let mids = players.filter((p) => p.Pos === "M").sort((a, b) => getEV(b) - getEV(a));
    let fwds = players.filter((p) => p.Pos === "F").sort((a, b) => getEV(b) - getEV(a));

    const starters = [];
    if (gks.length) starters.push(gks.shift());
    starters.push(...defs.splice(0, 3), ...mids.splice(0, 2), ...fwds.splice(0, 1));

    const remaining = [...defs, ...mids, ...fwds].sort((a, b) => getEV(b) - getEV(a));
    starters.push(...remaining.splice(0, 11 - starters.length));

    const finalStarters = [
      ...starters.filter((p) => p.Pos === "G"),
      ...starters.filter((p) => p.Pos === "D"),
      ...starters.filter((p) => p.Pos === "M"),
      ...starters.filter((p) => p.Pos === "F"),
    ];

    const benchGk = gks.length ? gks[0] : null;
    const benchRest = remaining.sort((a, b) => getEV(b) - getEV(a));
    const bench = benchGk ? [benchGk, ...benchRest] : benchRest;
    const topStarters = [...finalStarters].sort((a, b) => getEV(b) - getEV(a));

    return { optimalArray: [...finalStarters, ...bench], cap: topStarters[0]?.ID, vice: topStarters[1]?.ID };
  };

  // Like getValidLayout but penalises players whose EV should be discounted due to
  // opposing-play clashes (two squad members facing each other in a fixture).
  // Falls back to getValidLayout when fixtures/settings are unavailable.
  const getValidLayoutWithPenalty = (players, gw, fixturesArr = fixtures, settings = comprehensiveSettings) => {
    if (!players || players.length !== 15) return null;

    const penalty = Number(settings?.opposing_play_penalty ?? DEFAULT_SETTINGS.opposing_play_penalty);

    // Build a map: teamId -> list of player IDs from this squad playing that GW
    const gwFixtures = (fixturesArr || []).filter(f => Number(f.event || f.gw) === Number(gw));

    // For each player collect their team identifier (numeric or string)
    const getTeamId = (p) => p.team || p.Team || p.team_id;

    // Build a set of opposing-team pairs from GW fixtures that involve squad players
    // Returns adjusted EV for a player = raw EV - (penalty * number of opponents in squad)
    const getAdjustedEV = (p) => {
      if (p.isBlank) return -1000;
      const rawEV = Number(p[`${gw}_Pts`]) || 0;
      if (!penalty || !gwFixtures.length) return rawEV;

      const pTeam = getTeamId(p);
      if (!pTeam) return rawEV;

      // Find fixtures this player's team is in, then count squad opponents
      let opponentCount = 0;
      gwFixtures.forEach(fix => {
        const h = fix.team_h || fix.home_team;
        const a = fix.team_a || fix.away_team;
        // Is this player's team in this fixture?
        if (String(pTeam) === String(h) || String(pTeam) === String(a)) {
          const opponentTeam = String(pTeam) === String(h) ? String(a) : String(h);
          // Count squad players on the opposing team
          players.forEach(other => {
            if (other.ID !== p.ID && !other.isBlank) {
              const otherTeam = String(getTeamId(other));
              if (otherTeam === opponentTeam) opponentCount++;
            }
          });
        }
      });

      return rawEV - penalty * opponentCount;
    };

    let gks = players.filter((p) => p.Pos === "G").sort((a, b) => getAdjustedEV(b) - getAdjustedEV(a));
    let defs = players.filter((p) => p.Pos === "D").sort((a, b) => getAdjustedEV(b) - getAdjustedEV(a));
    let mids = players.filter((p) => p.Pos === "M").sort((a, b) => getAdjustedEV(b) - getAdjustedEV(a));
    let fwds = players.filter((p) => p.Pos === "F").sort((a, b) => getAdjustedEV(b) - getAdjustedEV(a));

    const starters = [];
    if (gks.length) starters.push(gks.shift());
    starters.push(...defs.splice(0, 3), ...mids.splice(0, 2), ...fwds.splice(0, 1));

    const remaining = [...defs, ...mids, ...fwds].sort((a, b) => getAdjustedEV(b) - getAdjustedEV(a));
    starters.push(...remaining.splice(0, 11 - starters.length));

    const finalStarters = [
      ...starters.filter((p) => p.Pos === "G"),
      ...starters.filter((p) => p.Pos === "D"),
      ...starters.filter((p) => p.Pos === "M"),
      ...starters.filter((p) => p.Pos === "F"),
    ];

    const benchGk = gks.length ? gks[0] : null;
    const benchRest = remaining.sort((a, b) => getAdjustedEV(b) - getAdjustedEV(a));
    const bench = benchGk ? [benchGk, ...benchRest] : benchRest;
    const topStarters = [...finalStarters].sort((a, b) => getAdjustedEV(b) - getAdjustedEV(a));

    return { optimalArray: [...finalStarters, ...bench], cap: topStarters[0]?.ID, vice: topStarters[1]?.ID };
  };

  const derivedItb = useMemo(() => {
    let currentBank = baselineItb;
    if (!availableGWs || availableGWs.length === 0) return currentBank;
    for (let gw = availableGWs[0]; gw <= activeGW; gw++) {
      if (gw < activeGW && chipsByGw[gw] === "fh") continue;
      if (transfersByGw[gw]) currentBank += transfersByGw[gw].netDelta || 0;
    }
    return currentBank;
  }, [activeGW, availableGWs, baselineItb, transfersByGw, chipsByGw]);

  const currentRemainingFts = useMemo(() => {
    if (!availableGWs || availableGWs.length === 0) return baselineFt;
    const startingFts = ftAtStartOfGw(activeGW, availableGWs, baselineFt, transfersByGw, chipsByGw);
    const usedThisWeek = transfersByGw[activeGW]?.count || 0;
    return Math.max(0, startingFts - usedThisWeek);
  }, [activeGW, availableGWs, baselineFt, transfersByGw, chipsByGw, ftAtStartOfGw]);

  useEffect(() => {
    fetch("https://anayshukla-fpl-solver.hf.space/api/fixtures")
      .then((res) => res.json())
      .then(data => { setFixtures(data); setIsFixturesLoaded(true); })
      .catch(() => { setIsFixturesLoaded(true); });
    fetch("https://anayshukla-fpl-solver.hf.space/api/solver/default-settings").then((r) => (r.ok ? r.json() : {})).then((d) => {
      if (d && typeof d === "object") {
        setComprehensiveSettings(prev => ({ ...d, ...prev }));
      }
    }).catch(() => { });
  }, []);

  useEffect(() => { setItb(derivedItb); setAvailableFts(currentRemainingFts); }, [derivedItb, currentRemainingFts, setItb, setAvailableFts]);
  useEffect(() => { if (horizon > maxAvailableHorizon && maxAvailableHorizon > 0) setHorizon(maxAvailableHorizon); }, [maxAvailableHorizon, horizon]);

  useEffect(() => {
    if (!isSolving) { setSolveElapsedSec(0); return; }
    const t0 = Date.now();
    const id = setInterval(() => setSolveElapsedSec(Math.floor((Date.now() - t0) / 1000)), 250);
    const prev = document.body.style.overflow;
    document.body.style.overflow = "hidden";
    return () => { clearInterval(id); document.body.style.overflow = prev; };
  }, [isSolving]);

  const hasAutoLoadedAfterLogin = useRef(false);

  useEffect(() => {
    if (isLoggedIn && userProfile.defaultTeamId && String(userProfile.defaultTeamId) === String(teamId) && !isLoading) {
      if (!hasAutoLoadedAfterLogin.current) {
        hasAutoLoadedAfterLogin.current = true;
        fetchTeam(null, teamData.length > 0);
      }
    }
    if (!isLoggedIn) {
      hasAutoLoadedAfterLogin.current = false; // reset on logout
    }
  }, [isLoggedIn, userProfile.defaultTeamId, teamId]);

  const fetchTeam = async (e, preserveState = false) => {
    // If manually clicked by user, always wipe the slate clean
    if (e) { e.preventDefault(); setManualOverrides({}); preserveState = false; }

    if (!teamId) return;
    setIsLoading(true); setError(null);
    try {
      const token = localStorage.getItem('fpl_token');
      const res = await fetch(`https://anayshukla-fpl-solver.hf.space/api/manager/${teamId}`, {
        headers: token ? { 'Authorization': `Bearer ${token}` } : {}
      });
      if (!res.ok) throw new Error("Could not fetch team.");
      const data = await res.json();

      if (data.picks && data.picks.length > 0) {
        // 1. ALWAYS populate the strict baseline vault and logic
        pristineSquadRef.current = {};
        data.picks.forEach(p => {
          pristineSquadRef.current[p.ID] = { ...p };
        });
        setBaselineItb(data.in_the_bank || 0);
        setBaselineFt(typeof data.free_transfers === "number" ? data.free_transfers : 1);
        setInitialSquadIds(data.picks.map((p) => p.ID));

        const gws = Object.keys(data.picks[0]).filter((k) => k.includes("_Pts")).map((k) => parseInt(k.split("_")[0])).sort((a, b) => a - b);
        setAvailableGWs(gws);

        // 2. ONLY overwrite the squad arrays if we are NOT loading from a saved DB Draft
        if (!preserveState) {
          setTransfersByGw({}); setHighlightTransferIds({}); setSolverTransferPairs({}); setSolverApplySnapshot(null); setChipsByGw({}); setChipSolveSolutions([]);
          setActiveGW(gws[0]);

          // THE HYDRATION FIX: Merge the raw FPL picks with the rich Python math BEFORE rendering the pitch!
          const hydratedPicks = data.picks.map(p => {
            const gMatch = globalPlayers.find(g => String(g.ID) === String(p.ID));
            if (gMatch) {
              // Attach all EV, Fixture, and Price data instantly
              return { ...gMatch, ...p, Price: p.selling_price !== undefined ? p.selling_price : gMatch.Price };
            }
            return p;
          });

          // Now getValidLayoutWithPenalty has the EV data + opposing-play penalty to sort properly!
          const opt = getValidLayoutWithPenalty(hydratedPicks, gws[0], fixtures, comprehensiveSettings);
          if (opt) { setTeamData(opt.optimalArray); setCaptainId(opt.cap); setViceId(opt.vice); }
          else { setTeamData(hydratedPicks); }
        } else {
          // If preserving state, just ensure activeGW doesn't break if the draft lacked it
          if (!activeGW) setActiveGW(gws[0]);
        }

        setLastLoadedId(teamId);
        if (isLoggedIn && userProfile.defaultTeamId !== parseInt(teamId)) { setPendingTeamId(parseInt(teamId)); setShowIdPrompt(true); }
      }
    } catch (err) { setError(err.message); } finally { setIsLoading(false); }
  };

  useEffect(() => {
    if (!teamData.length || !activeGW || teamData.some((p) => p.isBlank && !String(p.ID).startsWith("blank_"))) return;

    const gwLock = manualOverrides[activeGW];

    if (gwLock && gwLock.ids) {
      let reconstructed = gwLock.ids.map((id) => {
        if (String(id).startsWith("blank_")) {
          const replaced = gwLock.manualTransfers?.[id];
          return { ID: id, isBlank: true, Pos: replaced?.Pos || "M", Name: "", Team: "", Price: 0, replacedPlayer: replaced };
        }

        let found = hydratePlayer(id);
        if (found && gwLock.manualTransfers && gwLock.manualTransfers[id]) {
          found.replacedPlayer = gwLock.manualTransfers[id];
        }
        return found;
      }).filter(Boolean);

      if (reconstructed.length !== 15) {
        if (globalPlayers.length > 0) {
          setManualOverrides((prev) => { const n = { ...prev }; delete n[activeGW]; return n; });
        }
        return;
      }

      // THE FIX: Auto-optimize lineup safely AFTER global EVs finish recalculating!
      if (pendingAutoReset) {
        const opt = getValidLayoutWithPenalty(reconstructed, activeGW);
        if (opt) {
          setManualOverrides((prev) => ({ ...prev, [activeGW]: { ...gwLock, ids: opt.optimalArray.map((p) => p.ID), cap: opt.cap, vice: opt.vice } }));
          setTeamData(opt.optimalArray);
          setCaptainId(opt.cap);
          setViceId(opt.vice);
        }
        setPendingAutoReset(false);
        return;
      }

      let needsSub = false;
      const getEV = (p) => Number(p[`${activeGW}_Pts`]) || 0;

      for (let i = 0; i < 11; i++) {
        const starter = reconstructed[i];
        if (starter.isBlank || (getEV(starter) === 0 && (!gwLock.forcedZeros || !gwLock.forcedZeros.includes(starter.ID)))) {
          const bestBenchIdx = [11, 12, 13, 14].find((bIdx) => {
            const bPlayer = reconstructed[bIdx];
            if (bPlayer.isBlank || getEV(bPlayer) <= 0) return false;

            const tempStarters = [...reconstructed.slice(0, 11)];
            tempStarters[i] = bPlayer;
            const counts = { G: 0, D: 0, M: 0, F: 0 };
            tempStarters.forEach(p => { if (p.Pos) counts[p.Pos]++; });

            if (counts.G !== 1 || counts.D < 3 || counts.M < 2 || counts.F < 1) return false;
            return true;
          });

          if (bestBenchIdx) {
            const temp = reconstructed[i];
            reconstructed[i] = reconstructed[bestBenchIdx];
            reconstructed[bestBenchIdx] = temp;
            needsSub = true;
          }
        }
      }

      if (needsSub) {
        setManualOverrides((prev) => ({ ...prev, [activeGW]: { ...gwLock, ids: reconstructed.map((p) => p.ID) } }));
      }

      setTeamData(reconstructed);
      setCaptainId(gwLock.cap);
      setViceId(gwLock.vice);

    } else {
      let deterministicIds = [...initialSquadIds];
      if (availableGWs && availableGWs.length > 0) {
        for (let gw = availableGWs[0]; gw < activeGW; gw++) {
          if (manualOverrides[gw] && chipsByGw[gw] !== "fh") deterministicIds = manualOverrides[gw].ids;
        }
      }

      const deterministicSquad = deterministicIds.map(id => hydratePlayer(id)).filter(Boolean);

      const opt = getValidLayoutWithPenalty(deterministicSquad, activeGW);
      if (opt) {
        setTeamData(opt.optimalArray);
        setCaptainId(opt.cap);
        setViceId(opt.vice);
      }
    }
  }, [globalPlayers, activeGW, teamData.length, manualOverrides, pendingAutoReset]);

  const activeGwEV = useMemo(() => {
    if (!teamData.length || !activeGW) return 0;
    const chip = chipsByGw[activeGW];
    const capMult = chip === "tc" ? 3 : 2;
    let total = 0;
    teamData.slice(0, 11).forEach((p) => { if (!p.isBlank) total += (Number(p[`${activeGW}_Pts`]) || 0) * (p.ID === captainId ? capMult : 1); });

    let ofIdx = 0;
    teamData.slice(11, 15).forEach((p) => {
      if (!p.isBlank) {
        if (chip === "bb") {
          total += (Number(p[`${activeGW}_Pts`]) || 0);
        } else {
          // THE FIX: Read dynamically from the UI settings!
          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") {
            total += (Number(p[`${activeGW}_Pts`]) || 0) * gkWeight;
          } else {
            const bw = outWeights[ofIdx] || 0.02;
            total += (Number(p[`${activeGW}_Pts`]) || 0) * bw;
            ofIdx++;
          }
        }
      }
    });
    return total - hitsThisGw * HIT_COST;
  }, [teamData, activeGW, captainId, hitsThisGw, chipsByGw]);

  const horizonEvData = useMemo(() => {
    if (!teamData.length || !horizonGWs.length) return { total: 0, breakdown: {} };
    let total = 0;
    const breakdown = {};

    // Helper to get the actual squad that existed at the start of a specific GW
    const getSquadForGw = (targetGw) => {
      // If it's the active GW or in the future, the current teamData is our baseline
      if (targetGw >= activeGW) return teamData;

      // If it's in the past, rebuild it from the permanent chain
      let deterministicIds = [...initialSquadIds];
      if (availableGWs && availableGWs.length > 0) {
        for (let gw = availableGWs[0]; gw <= targetGw; gw++) {
          if (manualOverrides[gw] && chipsByGw[gw] !== "fh") {
            deterministicIds = manualOverrides[gw].ids;
          }
        }
      }
      return deterministicIds.map(id => hydratePlayer(id)).filter(Boolean);
    };

    horizonGWs.forEach((gw) => {
      let gwPts = 0;
      const gwChip = chipsByGw[gw];
      const gwCapMult = gwChip === "tc" ? 3 : 2;

      const applyBenchMath = (benchSlice) => {
        let ofIdx = 0;
        benchSlice.forEach((p) => {
          if (!p.isBlank) {
            if (gwChip === "bb") {
              gwPts += (Number(p[`${gw}_Pts`]) || 0);
            } else {
              // THE FIX: Dynamic settings for horizon EV too!
              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 += (Number(p[`${gw}_Pts`]) || 0) * gkWeight;
              } else {
                const bw = outWeights[ofIdx] || 0.02;
                gwPts += (Number(p[`${gw}_Pts`]) || 0) * bw;
                ofIdx++;
              }
            }
          }
        });
      };

      // THE FIX: Use the time-accurate squad for this specific GW
      const gwSpecificSquad = getSquadForGw(gw);

      if (gw === activeGW) {
        gwSpecificSquad.slice(0, 11).forEach((p) => { if (!p.isBlank) gwPts += (Number(p[`${gw}_Pts`]) || 0) * (p.ID === captainId ? gwCapMult : 1); });
        applyBenchMath(gwSpecificSquad.slice(11, 15));
      } else {
        const gwLock = manualOverrides[gw];
        if (gwLock && gwLock.ids) {
          const reconstructed = gwLock.ids.map((id) => gwSpecificSquad.find((p) => String(p.ID) === String(id)) || globalPlayers.find((p) => String(p.ID) === String(id))).filter(Boolean);
          if (reconstructed.length === 15) {
            reconstructed.slice(0, 11).forEach((p) => { if (!p.isBlank) gwPts += (Number(p[`${gw}_Pts`]) || 0) * (p.ID === gwLock.cap ? gwCapMult : 1); });
            applyBenchMath(reconstructed.slice(11, 15));
          } else {
            const opt = getValidLayout(gwSpecificSquad, gw);
            if (opt) {
              opt.optimalArray.slice(0, 11).forEach((p) => { gwPts += (Number(p[`${gw}_Pts`]) || 0) * (p.ID === opt.cap ? gwCapMult : 1); });
              applyBenchMath(opt.optimalArray.slice(11, 15));
            }
          }
        } else {
          const opt = getValidLayout(gwSpecificSquad, gw);
          if (opt) {
            opt.optimalArray.slice(0, 11).forEach((p) => { gwPts += (Number(p[`${gw}_Pts`]) || 0) * (p.ID === opt.cap ? gwCapMult : 1); });
            applyBenchMath(opt.optimalArray.slice(11, 15));
          }
        }
      }
      const ftStart = ftAtStartOfGw(gw, availableGWs, baselineFt, transfersByGw, chipsByGw);
      const T = transfersByGw[gw]?.count ?? 0;
      const isChipFree = gwChip === "wc" || gwChip === "fh";
      const hits = isChipFree ? 0 : Math.max(0, T - ftStart);
      const ev = gwPts - hits * HIT_COST;

      total += ev;
      breakdown[gw] = { ev, chip: gwChip, hits, ftStart, moves: T, isChipFree };
    });
    return { total, breakdown };
  }, [teamData, horizonGWs, activeGW, captainId, manualOverrides, baselineFt, transfersByGw, chipsByGw, globalPlayers, initialSquadIds, availableGWs]);

  const horizonEV = horizonEvData.total;

  // Sync the breakdown to the active draft automatically
  useEffect(() => {
    if (Object.keys(horizonEvData.breakdown).length === 0) return;
    setDrafts(prev => {
      const activeIdx = prev.findIndex(d => d.id === activeDraftId);
      if (activeIdx === -1) return prev;
      const currentCached = prev[activeIdx].cachedEvs;
      if (JSON.stringify(currentCached) === JSON.stringify(horizonEvData.breakdown)) return prev;

      const next = [...prev];
      next[activeIdx] = { ...next[activeIdx], cachedEvs: horizonEvData.breakdown };
      return next;
    });
  }, [horizonEvData.breakdown, activeDraftId, setDrafts]);

  // --- SOLVER API TRIGGERS & BASELINE ENGINE ---
  const getSolverStartingState = () => {
    const startGW = solveGWs[0];
    const startIndex = availableGWs.indexOf(startGW);

    // 1. Get Starting Squad (The exact squad going INTO the solve horizon, before current manual moves)
    let startingIds = initialSquadIds;
    if (startIndex > 0) {
      const prevGw = availableGWs[startIndex - 1];
      startingIds = manualOverrides[prevGw]?.ids || initialSquadIds;
    }

    const startingSquad = startingIds.map(id => {
      // Try to keep exact FPL prices from current teamData
      const existing = teamData.find(t => String(t.ID) === String(id));
      if (existing) return existing;
      const g = globalPlayers.find(x => String(x.ID) === String(id));
      return g ? { ...g, Price: getPlayerPrice(g) } : null;
    }).filter(Boolean);

    // 2. Get Starting ITB (Bank BEFORE the current gameweek's moves)
    let startingItb = baselineItb;
    for (let i = 0; i < startIndex; i++) {
      const gw = availableGWs[i];
      if (chipsByGw[gw] === "fh") continue;
      if (transfersByGw[gw]) startingItb += transfersByGw[gw].netDelta || 0;
    }

    // 3. Get Starting FTs (FTs going INTO the horizon)
    const startingFts = ftAtStartOfGw(startGW, availableGWs, baselineFt, transfersByGw, chipsByGw);

    // 4. Extract Manual Moves as Booked Transfers
    const bookedTransfers = [];
    solveGWs.forEach(gw => {
      const lock = manualOverrides[gw];
      if (lock && lock.manualTransfers) {
        Object.entries(lock.manualTransfers).forEach(([inId, outPlayer]) => {
          if (!String(inId).startsWith("blank_") && outPlayer) {
            bookedTransfers.push({
              gw: Number(gw),
              transfer_in: Number(inId),
              transfer_out: Number(outPlayer.ID)
            });
          }
        });
      }
    });

    return { startingSquad, startingItb, startingFts, bookedTransfers };
  };


  const getActiveCompSettings = (bookedTransfers) => {
    let payload;

    // If OFF: Send the absolute baseline defaults from our frontend UI + the manual moves
    if (!comprehensiveSettings.enabled) {
      payload = { ...DEFAULT_SETTINGS, booked_transfers: bookedTransfers };
    }
    // If ON: Send the user's custom edited settings + the manual moves
    else {
      payload = { ...comprehensiveSettings, booked_transfers: bookedTransfers };
    }

    // Safety check: If they aren't using the advanced FT list, strip it so backend uses the flat value
    if (!payload.use_ft_value_list) {
      delete payload.ft_value_list;
    }

    return payload;
  };

  // --- THE XMINS FILTER ENGINE ---
  // Replicates open-fpl-solver logic BEFORE sending the payload to Python
  const getFilteredGlobalPlayers = (startingSquad, bookedTransfers) => {
    const activeSettings = getActiveCompSettings(bookedTransfers);
    const xminLbPerGw = activeSettings.xmin_lb || 0;

    // If the setting is 0 or disabled, skip filtering
    if (xminLbPerGw <= 0) return globalPlayers;

    // Multiply the input by the horizon length to get the total threshold
    const totalXminThreshold = xminLbPerGw * horizonGWs.length;

    // Build the "safe_players" array (Current squad + anyone you manually locked in)
    const safePlayers = new Set(startingSquad.map(p => String(p.ID)));
    bookedTransfers.forEach(bt => {
      safePlayers.add(String(bt.transfer_in));
      safePlayers.add(String(bt.transfer_out));
    });

    // Execute the filter: (total_min >= xmin_lb) | (ID in safe_players)
    return globalPlayers.filter(p => {
      if (safePlayers.has(String(p.ID))) return true;

      let totalMins = 0;
      horizonGWs.forEach(gw => {
        totalMins += (Number(p[`${gw}_xMins`]) || 0);
      });

      return totalMins >= totalXminThreshold;
    });
  };

  const runMainSolver = () => {
    const { startingSquad, startingItb, startingFts, bookedTransfers } = getSolverStartingState();

    // THE FIX: Calculate apples-to-apples baseline EV for the active window, and the past locked EV
    const lockedBaselineEv = solveGWs.reduce((sum, gw) => sum + (horizonEvData.breakdown[gw]?.ev || 0), 0);
    const pastBaselineEv = horizonGWs.filter(gw => !solveGWs.includes(gw)).reduce((sum, gw) => sum + (horizonEvData.breakdown[gw]?.ev || 0), 0);

    apiHandleSolve({
      teamId, solveGWs, horizonGWs, teamData: startingSquad,
      globalPlayers: getFilteredGlobalPlayers(startingSquad, bookedTransfers),
      itb: startingItb, availableFts: startingFts, advancedSettings, quickSettings, chipsByGw,
      comprehensiveSettings: getActiveCompSettings(bookedTransfers),
      lockedBaselineEv, pastBaselineEv // <-- INJECTED HERE
    });
  };

  const runSensAnalysis = () => {
    const { startingSquad, startingItb, startingFts, bookedTransfers } = getSolverStartingState();

    const lockedBaselineEv = solveGWs.reduce((sum, gw) => sum + (horizonEvData.breakdown[gw]?.ev || 0), 0);
    const pastBaselineEv = horizonGWs.filter(gw => !solveGWs.includes(gw)).reduce((sum, gw) => sum + (horizonEvData.breakdown[gw]?.ev || 0), 0);

    apiHandleSensAnalysis({
      teamId, solveGWs, horizonGWs, teamData: startingSquad,
      globalPlayers: getFilteredGlobalPlayers(startingSquad, bookedTransfers),
      itb: startingItb, availableFts: startingFts, advancedSettings, quickSettings, chipsByGw,
      comprehensiveSettings: getActiveCompSettings(bookedTransfers), numSims,
      lockedBaselineEv, pastBaselineEv // <-- INJECTED HERE
    });
  };

  const runChipSolve = () => {
    const { startingSquad, startingItb, startingFts, bookedTransfers } = getSolverStartingState();

    const lockedBaselineEv = solveGWs.reduce((sum, gw) => sum + (horizonEvData.breakdown[gw]?.ev || 0), 0);
    const pastBaselineEv = horizonGWs.filter(gw => !solveGWs.includes(gw)).reduce((sum, gw) => sum + (horizonEvData.breakdown[gw]?.ev || 0), 0);

    apiHandleChipSolve({
      teamId, horizonGWs, teamData: startingSquad,
      globalPlayers: getFilteredGlobalPlayers(startingSquad, bookedTransfers),
      itb: startingItb, availableFts: startingFts, advancedSettings,
      comprehensiveSettings: getActiveCompSettings(bookedTransfers), chipSolveOptions,
      lockedBaselineEv, pastBaselineEv // <-- INJECTED HERE
    });
  };

  // --- MULTIVERSE DRAFT HANDLERS ---
  const handleCloneDraft = () => {
    if (drafts.length >= 5) { alert("Maximum of 5 realities allowed."); return; }
    const currentDraft = drafts.find(d => d.id === activeDraftId);
    const newId = `draft_${Date.now()}`;

    // THE FIX: Deep clone ALL objects to stop timelines from sharing memory
    const newDraft = {
      ...currentDraft,
      id: newId,
      name: `${currentDraft.name} (Copy)`,
      fixtureOverrides: JSON.parse(JSON.stringify(currentDraft.fixtureOverrides || {})),
      sessionEdits: JSON.parse(JSON.stringify(currentDraft.sessionEdits || {})),
      manualOverrides: JSON.parse(JSON.stringify(currentDraft.manualOverrides || {})),
      transfersByGw: JSON.parse(JSON.stringify(currentDraft.transfersByGw || {})),
      highlightTransferIds: JSON.parse(JSON.stringify(currentDraft.highlightTransferIds || {})),
      solverTransferPairs: JSON.parse(JSON.stringify(currentDraft.solverTransferPairs || {})),
      chipsByGw: JSON.parse(JSON.stringify(currentDraft.chipsByGw || {})),
      cachedEvs: JSON.parse(JSON.stringify(currentDraft.cachedEvs || {}))
    };

    setDrafts(prev => [...prev, newDraft]);
    setActiveDraftId(newId);
  };

  const handleNewDraft = () => {
    if (drafts.length >= 5) { alert("Maximum of 5 realities allowed."); return; }
    const newId = `draft_${Date.now()}`;
    const startGW = availableGWs[0] || activeGW;
    const pristineSquad = initialSquadIds.map(id => hydratePlayer(id)).filter(Boolean);
    const opt = getValidLayoutWithPenalty(pristineSquad, startGW);
    const finalSquad = opt ? opt.optimalArray : pristineSquad;

    const newDraft = {
      id: newId, name: `Draft ${drafts.length + 1}`, teamData: finalSquad, horizon: horizon, activeGW: startGW, captainId: opt ? opt.cap : null, viceId: opt ? opt.vice : null, solverTransferPairs: {}, solverApplySnapshot: null, appliedPlanSummary: null, hitsThisGw: 0, highlightTransferIds: {}, transfersByGw: {}, chipsByGw: {}, manualOverrides: {}, fixtureOverrides: {}, sessionEdits: {}, cachedEvs: {}
    };
    setDrafts(prev => [...prev, newDraft]);
    setActiveDraftId(newId);
  };
  // --- TIMELINE WIPING HELPER ---
  // If you manually edit the pitch, any "future" moves planned by the solver MUST be 
  // wiped out so that the timeline correctly cascades forward!
  const clearFuture = (prev) => {
    return prev; // 👈 FIXED: We no longer wipe out future gameweek plans!
  };

  const applySolution = (sol) => {
    setSolverApplySnapshot({
      teamData: [...teamData], availableFts, transfersByGw: { ...transfersByGw }, manualOverrides: { ...manualOverrides }, baselineItb, baselineFt
    });

    const newOverrides = { ...manualOverrides };
    const newTransfersByGw = { ...transfersByGw };
    const newChipsByGw = { ...chipsByGw };
    const newHighlights = { ...highlightTransferIds };
    const newPairs = { ...solverTransferPairs };

    let runningItb = baselineItb;
    const startIndex = availableGWs.indexOf(sol.horizon_gws[0]);
    if (startIndex > 0) {
      for (let i = 0; i < startIndex; i++) {
        const gw = availableGWs[i];
        if (chipsByGw[gw] === "fh") continue;
        if (transfersByGw[gw]) runningItb += transfersByGw[gw].netDelta || 0;
      }
    }
    const fixedPlanForSummary = [];

    sol.plan.forEach(gwPlan => {
      const gw = gwPlan.gw;
      const getPts = (id) => { const p = globalPlayers.find(x => String(x.ID) === String(id)); return p ? (Number(p[`${gw}_Pts`]) || 0) : 0; };
      const posOrder = { G: 1, D: 2, M: 3, F: 4 };
      const getPos = (id) => { const p = globalPlayers.find(x => String(x.ID) === String(id)); return p ? posOrder[p.Pos] || 5 : 5; };

      let activeLineup = [...gwPlan.lineup];
      let activeBench = [...gwPlan.bench];
      const isSymmetricChip = sol.chips_used && (sol.chips_used[String(gw)] === "bb" || sol.chips_used[String(gw)] === "fh");

      // BUG 2 FIX: Auto-optimize the BB lineup visually so best players start,
      // using the opposing-play penalty for accurate EV ranking.
      if (isSymmetricChip) {
        const all15 = [...activeLineup, ...activeBench];
        const pObjs = all15.map(id => {
          const p = globalPlayers.find(x => String(x.ID) === String(id));
          return p ? { ...p } : { ID: id, Pos: 'M' };
        }).filter(Boolean);

        const opt = getValidLayoutWithPenalty(pObjs, gw);
        if (opt) {
          const starterSet = new Set(opt.optimalArray.slice(0, 11).map(p => String(p.ID)));
          activeLineup = opt.optimalArray.slice(0, 11).map(p => p.ID);
          activeBench = opt.optimalArray.slice(11).map(p => p.ID);
        }
      }

      const sortedLineup = activeLineup.sort((a, b) => {
        const posDiff = getPos(a) - getPos(b);
        if (posDiff !== 0) return posDiff;
        return getPts(b) - getPts(a);
      });

      newOverrides[gw] = { ids: [...sortedLineup, ...activeBench], cap: gwPlan.captain, vice: gwPlan.vice_captain, forcedZeros: [] };
      if (sol.chips_used && sol.chips_used[String(gw)]) newChipsByGw[gw] = sol.chips_used[String(gw)];

      let currentNetDelta = 0; // Track this GW's net delta

      if (gwPlan.transfers_in.length > 0 || gwPlan.transfers_out.length > 0) {
        
        // THE RE-APPLY FIX: Use hydratePlayer to pull the permanent locked squad prices, NEVER the current UI teamData!
        currentNetDelta = gwPlan.transfers_out.reduce((sum, id) => {
          const p = hydratePlayer(id);
          return sum + (p ? p.Price : 0);
        }, 0) - gwPlan.transfers_in.reduce((sum, id) => {
          const p = hydratePlayer(id);
          return sum + (p ? p.now_cost : 0);
        }, 0);

        newTransfersByGw[gw] = { count: gwPlan.transfers_in.length, hits: gwPlan.hits, netDelta: currentNetDelta, inIds: gwPlan.transfers_in, outIds: gwPlan.transfers_out };
        newHighlights[gw] = [...gwPlan.transfers_in];
        const newManualTransfersForGw = {};
        
        gwPlan.transfers_in.forEach((inId, idx) => {
          const outId = gwPlan.transfers_out[idx];
          const outP = hydratePlayer(outId); // Always fetches the accurate original player!
          if (outP) newManualTransfersForGw[inId] = outP;
        });

        // THE FIX: Delete the solver memory so it doesn't double-render alongside the manual memory!
        delete newPairs[gw];

        // CLEAN FIX: Attach the transfers directly to the master object we are building
        newOverrides[gw] = {
          ...newOverrides[gw],
          manualTransfers: {
            ...(newOverrides[gw]?.manualTransfers || {}),
            ...newManualTransfersForGw
          }
        };

        if (gwPlan.chip) newChipsByGw[gw] = gwPlan.chip;

      } else {
        delete newTransfersByGw[gw];
        delete newHighlights[gw];
        delete newPairs[gw];
      }

      let activeItbThisGw = runningItb + currentNetDelta;
      if (gwPlan.chip !== "fh") {
        runningItb += currentNetDelta;
      }
      
      fixedPlanForSummary.push({ ...gwPlan, itb: activeItbThisGw });
    });

    setManualOverrides(newOverrides); setTransfersByGw(newTransfersByGw); setChipsByGw(newChipsByGw); setHighlightTransferIds(newHighlights); setSolverTransferPairs(newPairs);

    setAppliedPlanSummary({
      horizon: `GW${sol.horizon_gws[0]} - GW${sol.horizon_gws[sol.horizon_gws.length - 1]}`,
      ev: sol.ev,
      objectiveScore: sol.objective_score,
      plan: fixedPlanForSummary,
      lockedBaselineEv: horizonEV,
      transfers: sol.plan.map(p => ({
        gw: p.gw, chip: p.chip, itb: p.itb, hits: p.hits, ft_at_start: p.ft_at_start,
        outs: p.transfers_out.map(id => globalPlayers.find(x => x.ID === id)?.Name || id),
        ins: p.transfers_in.map(id => globalPlayers.find(x => x.ID === id)?.Name || id)
      }))
    });

    if (sol.plan.length > 0) {
      const activePlan = sol.plan.find(p => p.gw === activeGW) || sol.plan[0];
      let nextSquad = [...teamData];
      if (activePlan.transfers_in.length > 0) {
        activePlan.transfers_in.forEach((inId, idx) => {
          const pIn = globalPlayers.find(p => String(p.ID) === String(inId));
          const outIndex = nextSquad.findIndex(p => String(p.ID) === String(activePlan.transfers_out[idx]));
          if (outIndex !== -1 && pIn) nextSquad[outIndex] = { ...pIn, Price: getPlayerPrice(pIn) };
        });
      } else {
        nextSquad = [...activePlan.lineup, ...activePlan.bench].map(id => {
          const existing = teamData.find(t => String(t.ID) === String(id));
          const hydrated = hydratePlayer(id);
          if (existing && hydrated) return { ...hydrated, replacedPlayer: existing.replacedPlayer };
          return hydrated;
        }).filter(Boolean);
      }

      const getPts = (p) => Number(p[`${activePlan.gw}_Pts`]) || 0;
      const finalLineup = activePlan.lineup.map(id => nextSquad.find(p => String(p.ID) === String(id))).filter(Boolean);
      const finalBench = activePlan.bench.map(id => nextSquad.find(p => String(p.ID) === String(id))).filter(Boolean);

      const sortedStarters = [
        ...finalLineup.filter(p => p.Pos === "G").sort((a, b) => getPts(b) - getPts(a)),
        ...finalLineup.filter(p => p.Pos === "D").sort((a, b) => getPts(b) - getPts(a)),
        ...finalLineup.filter(p => p.Pos === "M").sort((a, b) => getPts(b) - getPts(a)),
        ...finalLineup.filter(p => p.Pos === "F").sort((a, b) => getPts(b) - getPts(a)),
      ];
      const sortedBench = [
        ...finalBench.filter(p => p.Pos === "G"),
        ...finalBench.filter(p => p.Pos !== "G").sort((a, b) => getPts(b) - getPts(a))
      ];

      setTeamData([...sortedStarters, ...sortedBench]);
      setCaptainId(activePlan.captain); setViceId(activePlan.vice_captain);
    }
    setPendingSolutions([]);
  };

  const updateFutureTimelines = (oldSquad, newSquad, currentOverrides, currentTransfers, currentPairs, customMapping = null) => {
    let mapping = {};
    let removedIds = [];
    let addedIds = [];

    if (customMapping) {
      Object.keys(customMapping).forEach(k => {
        mapping[String(k)] = String(customMapping[k]);
        removedIds.push(String(k));
        addedIds.push(String(customMapping[k]));
      });
    } else {
      const oldIds = oldSquad.map(p => String(p.ID));
      const newIds = newSquad.map(p => String(p.ID));
      removedIds = oldIds.filter(id => !newIds.includes(id) && !id.startsWith("blank_"));
      addedIds = newIds.filter(id => !oldIds.includes(id) && !id.startsWith("blank_"));
      for (let i = 0; i < Math.min(removedIds.length, addedIds.length); i++) {
        mapping[removedIds[i]] = addedIds[i];
      }
    }

    const nextOverrides = { ...currentOverrides };
    const nextTransfers = { ...currentTransfers };
    const nextPairs = { ...currentPairs };

    for (let gw = activeGW + 1; gw <= Math.max(...(availableGWs || [])); gw++) {

      // 1. SURGICAL SCRUB: Remove redundant "Buy" plans to kill the ghost button,
      // but DO NOT filter "outIds" so the Y->Z to X->Z cascade survives perfectly!
      if (nextTransfers[gw]) {
        nextTransfers[gw].inIds = (nextTransfers[gw].inIds || []).filter(id => !addedIds.includes(String(id)));
        nextTransfers[gw].count = nextTransfers[gw].inIds.length;
        if (nextTransfers[gw].count === 0) delete nextTransfers[gw];
      }

      if (nextOverrides[gw]) {
        const lock = nextOverrides[gw];
        const updatedIds = lock.ids.map(id => mapping[String(id)] || String(id));

        // Anti-Time-Paradox: Only wipe the GW if the cascade creates literal duplicate players
        const uniqueIds = new Set(updatedIds);
        if (uniqueIds.size !== updatedIds.length) {
          delete nextOverrides[gw];
          delete nextTransfers[gw];
          delete nextPairs[gw];

          // THE FIX: Plunge the timeline into darkness so the UI doesn't glow for a deleted GW!
          setHighlightTransferIds(prev => { const n = { ...prev }; delete n[gw]; return n; });
          setTransfersByGw(prev => { const n = { ...prev }; delete n[gw]; return n; });

          continue;
        }

        const updatedTransfers = {};
        if (lock.manualTransfers) {
          for (const [inId, outPlayer] of Object.entries(lock.manualTransfers)) {
            // KILL OBSOLETE MOVES & GLOWS: Skip this move if the player is already naturally in the incoming squad
            if (addedIds.includes(String(inId)) || newSquad.some(p => String(p.ID) === String(inId))) {

              // FIX: highlightTransferIds is an object of arrays. Target the specific GW array.
              setHighlightTransferIds(prev => ({
                ...prev,
                [gw]: Array.from(prev[gw] || []).filter(id => String(id) !== String(inId))
              }));

              // FIX: transfersByGw is an object of objects. Safely reduce the count.
              setTransfersByGw(prev => {
                const currentGwTransfers = prev[gw];
                if (!currentGwTransfers) return prev;

                const newInIds = Array.from(currentGwTransfers.inIds || []).filter(id => String(id) !== String(inId));
                const newCount = Math.max(0, (currentGwTransfers.count || 1) - 1);

                if (newCount === 0) {
                  const next = { ...prev };
                  delete next[gw];
                  return next;
                }
                return { ...prev, [gw]: { ...currentGwTransfers, inIds: newInIds, count: newCount } };
              });

              continue;
            }

            let newOutPlayer = outPlayer;
            const outIdStr = String(outPlayer?.ID);
            if (outPlayer && mapping[outIdStr]) {
              const mappedId = mapping[outIdStr];
              let mappedP = globalPlayers.find(p => String(p.ID) === mappedId) || newSquad.find(p => String(p.ID) === mappedId);
              if (mappedP) newOutPlayer = { ...mappedP, Price: getPlayerPrice(mappedP) };
            }
            updatedTransfers[mapping[String(inId)] || String(inId)] = newOutPlayer;
          }
        }

        // --- RE-OPTIMIZE LINEUP FOR FUTURE GAMEWEEKS ---
        // Instantly sub out the cascaded player if their EV is bad in this future gameweek
        const reconstructedSquad = updatedIds.map(id => {
          if (String(id).startsWith("blank_")) {
            const replaced = updatedTransfers[id];
            return { ID: id, isBlank: true, Pos: replaced?.Pos || "M", Name: "", Team: "", Price: 0, replacedPlayer: replaced };
          }
          return hydratePlayer(id);
        }).filter(Boolean);

        const opt = getValidLayoutWithPenalty(reconstructedSquad, gw);

        nextOverrides[gw] = {
          ...lock,
          ids: opt ? opt.optimalArray.map(p => p.ID) : updatedIds,
          manualTransfers: updatedTransfers,
          cap: opt ? opt.cap : mapping[String(lock.cap)] || lock.cap,
          vice: opt ? opt.vice : mapping[String(lock.vice)] || lock.vice
        };
      }

      if (nextPairs[gw]) {
        const updatedGwPairs = {};
        for (const [inId, pairData] of Object.entries(nextPairs[gw])) {
          // KILL GHOST BUTTON & GLOW: Skip this solver memory if the player naturally returns to squad
          if (addedIds.includes(String(inId)) || newSquad.some(p => String(p.ID) === String(inId))) {
            setHighlightTransferIds(prev => ({ ...prev, [gw]: Array.from(prev[gw] || []).filter(id => String(id) !== String(inId)) }));
            setTransfersByGw(prev => {
              const currentGwTransfers = prev[gw];
              if (!currentGwTransfers) return prev;
              const newInIds = Array.from(currentGwTransfers.inIds || []).filter(id => String(id) !== String(inId));
              const newCount = Math.max(0, (currentGwTransfers.count || 1) - 1);
              if (newCount === 0) { const next = { ...prev }; delete next[gw]; return next; }
              return { ...prev, [gw]: { ...currentGwTransfers, inIds: newInIds, count: newCount } };
            });
            continue;
          }

          let newOut = pairData.outPlayer;
          const outIdStr = String(newOut?.ID);
          if (newOut && mapping[outIdStr]) {
            const mappedId = mapping[outIdStr];
            let mappedP = globalPlayers.find(p => String(p.ID) === mappedId) || newSquad.find(p => String(p.ID) === mappedId);
            if (mappedP) newOut = { ...mappedP, Price: getPlayerPrice(mappedP) };
          }
          updatedGwPairs[mapping[String(inId)] || String(inId)] = { outPlayer: newOut };
        }

        if (Object.keys(updatedGwPairs).length === 0) {
          delete nextPairs[gw];
        } else {
          nextPairs[gw] = updatedGwPairs;
        }
      }
    }
    return { nextOverrides, nextTransfers, nextPairs };
  };

  const handleDragStart = (event) => setActiveDragPlayer(event.active.data.current.player);

  const isValidSwap = (p1, p2) => {
    if (!p1 || !p2 || p1.isBlank || p2.isBlank) return false;
    if (p1.ID === p2.ID) return true;
    if (p1.Pos === "G" && p2.Pos !== "G") return false;
    if (p1.Pos !== "G" && p2.Pos === "G") return false;
    const currentStarters = teamData.slice(0, 11);
    const isP1Starter = currentStarters.some((p) => p.ID === p1.ID);
    const isP2Starter = currentStarters.some((p) => p.ID === p2.ID);
    if (isP1Starter === isP2Starter) return true;
    const newStarters = currentStarters.filter((p) => p.ID !== p1.ID && p.ID !== p2.ID);
    newStarters.push(isP1Starter ? p2 : p1);
    const counts = { G: 0, D: 0, M: 0, F: 0 };
    newStarters.forEach((p) => counts[p.Pos]++);
    return counts.G === 1 && counts.D >= 3 && counts.M >= 2 && counts.F >= 1 && newStarters.length === 11;
  };

  const handleDragEnd = (event) => {
    const { active, over } = event;
    setActiveDragPlayer(null);
    if (over && active.id !== over.id) {
      const p1 = active.data.current.player; const p2 = over.data.current.player;
      if (isValidSwap(p1, p2)) {
        const newArr = [...teamData];
        const idx1 = newArr.findIndex((p) => p.ID === p1.ID);
        const idx2 = newArr.findIndex((p) => p.ID === p2.ID);
        newArr[idx1] = p2; newArr[idx2] = p1;
        const normalized = idx1 >= 11 || idx2 >= 11 ? normalizeBenchGkFirst(newArr, activeGW) : newArr;
        const forcedZeros = manualOverrides[activeGW]?.forcedZeros || [];
        if ((Number(p1[`${activeGW}_Pts`]) || 0) === 0 && idx2 < 11) forcedZeros.push(p1.ID);
        if ((Number(p2[`${activeGW}_Pts`]) || 0) === 0 && idx1 < 11) forcedZeros.push(p2.ID);

        let newCap = captainId; let newVice = viceId;
        const getEV = (p) => p.isBlank ? -1000 : (Number(p[`${activeGW}_Pts`]) || 0);
        const starters = normalized.slice(0, 11);
        const starterIds = starters.map((p) => p.ID);

        if (!starterIds.includes(newCap)) {
          const sorted = [...starters].sort((a, b) => getEV(b) - getEV(a));
          newCap = sorted[0]?.ID;
          if (newCap === newVice) newVice = sorted[1]?.ID;
        }
        if (!starterIds.includes(newVice)) {
          const sorted = [...starters].sort((a, b) => getEV(b) - getEV(a));
          newVice = sorted.find((p) => p.ID !== newCap)?.ID;
        }

        setManualOverrides((prev) => clearFuture({ ...prev, [activeGW]: { ...prev[activeGW], ids: normalized.map((p) => p.ID), cap: newCap, vice: newVice, forcedZeros } }));
        setTeamData(normalized);

        setTransfersByGw(clearFuture);
        setHighlightTransferIds(clearFuture);
        setSolverTransferPairs(clearFuture);
        setChipsByGw(clearFuture);
        setAppliedPlanSummary(null);
      }
    }
  };

  const handleCapChange = (id, type) => {
    let newCap = captainId; let newVice = viceId;
    if (type === "C") { newCap = id; if (viceId === id) newVice = captainId; } else { newVice = id; if (captainId === id) newCap = viceId; }

    setManualOverrides((prev) => clearFuture({ ...prev, [activeGW]: { ...prev[activeGW], ids: teamData.map((p) => p.ID), cap: newCap, vice: newVice, forcedZeros: prev[activeGW]?.forcedZeros } }));
    setCaptainId(newCap); setViceId(newVice);

    setTransfersByGw(clearFuture);
    setHighlightTransferIds(clearFuture);
    setSolverTransferPairs(clearFuture);
    setChipsByGw(clearFuture);
    setAppliedPlanSummary(null);
  };

  const handleResetGW = () => {
    const opt = getValidLayoutWithPenalty(teamData, activeGW);
    if (!opt) return;

    setManualOverrides((prev) => clearFuture({ ...prev, [activeGW]: { ...prev[activeGW], ids: opt.optimalArray.map((p) => p.ID), cap: opt.cap, vice: opt.vice, forcedZeros: prev[activeGW]?.forcedZeros || [] } }));
    setTeamData(opt.optimalArray); setCaptainId(opt.cap); setViceId(opt.vice);

    setTransfersByGw(clearFuture);
    setHighlightTransferIds(clearFuture);
    setSolverTransferPairs(clearFuture);
    setChipsByGw(clearFuture);
    setAppliedPlanSummary(null);
  };

  const handleChipSelect = (gw, chipType) => {
    setChipsByGw((prev) => {
      const next = { ...prev };
      if (!chipType) { delete next[gw]; } else { Object.keys(next).forEach((g) => { if (next[g] === chipType) delete next[g]; }); next[gw] = chipType; }
      return clearFuture(next);
    });

    setManualOverrides(clearFuture);
    setTransfersByGw(clearFuture);
    setHighlightTransferIds(clearFuture);
    setSolverTransferPairs(clearFuture);
    setAppliedPlanSummary(null);
  };

  const handleTransferOut = (playerToDrop) => {
    const sellPrice = getPlayerPrice(playerToDrop);
    const blankId = `blank_${Date.now()}`;
    const newSquad = teamData.map((p) => String(p.ID) === String(playerToDrop.ID) ? { ID: blankId, isBlank: true, Pos: p.Pos, Name: "", Team: "", Price: 0, replacedPlayer: playerToDrop } : p);

    const opt = getValidLayoutWithPenalty(newSquad, activeGW);
    const finalSquad = opt ? opt.optimalArray : newSquad;

    let nextTransfers = { ...transfersByGw };
    nextTransfers[activeGW] = { ...(nextTransfers[activeGW] || { count: 0, netDelta: 0 }), netDelta: (nextTransfers[activeGW]?.netDelta || 0) + sellPrice };

    let nextOverrides = { ...manualOverrides };
    nextOverrides[activeGW] = {
      ...(nextOverrides[activeGW] || {}), ids: finalSquad.map(p => p.ID),
      cap: opt ? opt.cap : captainId, vice: opt ? opt.vice : viceId,
      manualTransfers: { ...(nextOverrides[activeGW]?.manualTransfers || {}), [blankId]: playerToDrop }
    };

    const mapping = { [playerToDrop.ID]: blankId };
    const { nextOverrides: cascadedO, nextTransfers: cascadedT, nextPairs: cascadedP } = updateFutureTimelines(teamData, finalSquad, nextOverrides, nextTransfers, solverTransferPairs, mapping);

    setTransfersByGw(cascadedT); setManualOverrides(cascadedO); setTeamData(finalSquad); setSolverTransferPairs(cascadedP);
    setHighlightTransferIds(clearFuture); setChipsByGw(clearFuture); setAppliedPlanSummary(null); setSelectedPlayer(null);
  };

  const handleAddPlayer = (newPlayer) => {
    const cost = getPlayerPrice(newPlayer);
    if (itb < cost) return alert("Insufficient funds!");

    const newSquad = teamData.map((p) => String(p.ID) === String(selectedPlayer.ID) ? { ...newPlayer, Price: cost, purchase_price: newPlayer.now_cost, selling_price: newPlayer.now_cost, replacedPlayer: selectedPlayer.replacedPlayer } : p);
    const opt = getValidLayoutWithPenalty(newSquad, activeGW);
    const finalSquad = opt ? opt.optimalArray : newSquad;

    let nextTransfers = { ...transfersByGw };
    nextTransfers[activeGW] = { ...(nextTransfers[activeGW] || { count: 0, netDelta: 0 }), count: (nextTransfers[activeGW]?.count || 0) + 1, netDelta: (nextTransfers[activeGW]?.netDelta || 0) - cost };

    const newManualTransfers = { ...(manualOverrides[activeGW]?.manualTransfers || {}) };
    delete newManualTransfers[selectedPlayer.ID];
    if (selectedPlayer.replacedPlayer) newManualTransfers[newPlayer.ID] = selectedPlayer.replacedPlayer;

    let nextOverrides = { ...manualOverrides };
    nextOverrides[activeGW] = {
      ...nextOverrides[activeGW], ids: finalSquad.map(p => p.ID),
      cap: opt ? opt.cap : captainId, vice: opt ? opt.vice : viceId,
      forcedZeros: nextOverrides[activeGW]?.forcedZeros || [], manualTransfers: newManualTransfers
    };

    const mapping = { [selectedPlayer.ID]: newPlayer.ID };
    if (selectedPlayer.replacedPlayer) mapping[selectedPlayer.replacedPlayer.ID] = newPlayer.ID;
    const { nextOverrides: cascadedO, nextTransfers: cascadedT, nextPairs: cascadedP } = updateFutureTimelines(teamData, finalSquad, nextOverrides, nextTransfers, solverTransferPairs, mapping);

    setTransfersByGw(cascadedT); setManualOverrides(cascadedO); setTeamData(finalSquad); setSolverTransferPairs(cascadedP);
    if (opt) { setCaptainId(opt.cap); setViceId(opt.vice); }
    setHighlightTransferIds((prev) => clearFuture({ ...prev, [activeGW]: [...(prev[activeGW] || []), newPlayer.ID] }));
    setChipsByGw(clearFuture); setAppliedPlanSummary(null); setSelectedPlayer(null); setSearchQuery("");
  };

  const handleUndoTransfer = (e, currentId, replacedPlayer) => {
    e.stopPropagation();
    const buyPlayer = teamData.find((p) => String(p.ID) === String(currentId)) || globalPlayers.find((p) => String(p.ID) === String(currentId));
    const buy = (!String(currentId).startsWith("blank_") && buyPlayer) ? getPlayerPrice(buyPlayer) : 0;
    const sell = getPlayerPrice(replacedPlayer);

    // FRESHEN REPLACED PLAYER: Ensure EV is up to date before optimizing the lineup
    // const freshReplacedPlayer = { ...(globalPlayers.find(p => String(p.ID) === String(replacedPlayer.ID)) || replacedPlayer), Price: getPlayerPrice(replacedPlayer) };
    const freshReplacedPlayer = hydratePlayer(replacedPlayer.ID, replacedPlayer) || replacedPlayer;

    const newSquad = teamData.map((p) => (String(p.ID) === String(currentId) ? freshReplacedPlayer : p));
    const opt = getValidLayoutWithPenalty(newSquad, activeGW);
    const finalSquad = opt ? opt.optimalArray : newSquad;

    let nextTransfers = { ...transfersByGw };
    const row = nextTransfers[activeGW] || { count: 0, netDelta: 0 };
    nextTransfers[activeGW] = { ...row, count: Math.max(0, row.count - (!String(currentId).startsWith("blank_") ? 1 : 0)), netDelta: row.netDelta - (sell - buy) };

    let nextOverrides = { ...manualOverrides };
    const newManualTransfers = { ...(nextOverrides[activeGW]?.manualTransfers || {}) };
    delete newManualTransfers[currentId];

    nextOverrides[activeGW] = {
      ...nextOverrides[activeGW], ids: finalSquad.map(p => p.ID),
      cap: opt ? opt.cap : captainId, vice: opt ? opt.vice : viceId,
      forcedZeros: nextOverrides[activeGW]?.forcedZeros || [], manualTransfers: newManualTransfers
    };

    const mapping = { [currentId]: replacedPlayer.ID };
    const { nextOverrides: cascadedO, nextTransfers: cascadedT, nextPairs: cascadedP } = updateFutureTimelines(teamData, finalSquad, nextOverrides, nextTransfers, solverTransferPairs, mapping);

    setTransfersByGw(cascadedT); setManualOverrides(cascadedO); setTeamData(finalSquad); setSolverTransferPairs(cascadedP);
    if (opt) { setCaptainId(opt.cap); setViceId(opt.vice); }
    setHighlightTransferIds((prev) => clearFuture({ ...prev, [activeGW]: Array.from(prev[activeGW] || []).filter((id) => String(id) !== String(currentId)) }));
    setChipsByGw(clearFuture); setAppliedPlanSummary(null);
  };

  const resetHighlightedTransfer = (player) => {
    const pair = (solverTransferPairs[activeGW] || {})[player.ID];
    if (pair?.outPlayer) {
      const idx = teamData.findIndex((p) => p.ID === player.ID);
      if (idx < 0) return;

      // FRESHEN REPLACED PLAYER: Ensure EV is up to date before optimizing the lineup
      // const freshOutPlayer = { ...(globalPlayers.find(p => String(p.ID) === String(pair.outPlayer.ID)) || pair.outPlayer), Price: getPlayerPrice(pair.outPlayer) };
      const freshOutPlayer = hydratePlayer(pair.outPlayer.ID, pair.outPlayer) || pair.outPlayer;
      const newSquad = [...teamData]; newSquad[idx] = freshOutPlayer;

      const buyPrice = getPlayerPrice(player); const sellPrice = getPlayerPrice(pair.outPlayer);

      let nextTransfers = { ...transfersByGw };
      const row = nextTransfers[activeGW] || { count: 0, netDelta: 0 };
      nextTransfers[activeGW] = {
        ...row, count: Math.max(0, row.count - 1), netDelta: row.netDelta - (sellPrice - buyPrice),
        inIds: Array.from(row.inIds || []).filter(id => String(id) !== String(player.ID)), outIds: Array.from(row.outIds || []).filter(id => String(id) !== String(pair.outPlayer.ID))
      };

      const opt = getValidLayoutWithPenalty(newSquad, activeGW);
      const finalSquad = opt ? opt.optimalArray : newSquad;

      let nextOverrides = { ...manualOverrides };
      nextOverrides[activeGW] = { ...nextOverrides[activeGW], ids: finalSquad.map(p => p.ID), cap: opt ? opt.cap : captainId, vice: opt ? opt.vice : viceId, forcedZeros: nextOverrides[activeGW]?.forcedZeros || [] };

      const mapping = { [player.ID]: pair.outPlayer.ID };
      const { nextOverrides: cascadedO, nextTransfers: cascadedT, nextPairs: cascadedP } = updateFutureTimelines(teamData, finalSquad, nextOverrides, nextTransfers, solverTransferPairs, mapping);

      setTransfersByGw(cascadedT); setManualOverrides(cascadedO); setTeamData(finalSquad);
      if (opt) { setCaptainId(opt.cap); setViceId(opt.vice); }

      const nP = { ...cascadedP };
      if (nP[activeGW]) { delete nP[activeGW][player.ID]; }
      setSolverTransferPairs(nP);

      setHighlightTransferIds((prev) => { const n = { ...prev }; if (n[activeGW]) { const gwSet = new Set(n[activeGW]); gwSet.delete(player.ID); n[activeGW] = Array.from(gwSet); } return clearFuture(n); });
      setChipsByGw(clearFuture); setAppliedPlanSummary(null); setSelectedPlayer(null); return;
    }
    if (player.replacedPlayer) { handleUndoTransfer({ stopPropagation: () => { } }, player.ID, player.replacedPlayer); return; }
    handleTransferOut(player);
  };

  const handleResetGWTransfers = () => {
    let previousSquadIds = [];
    const currentIndex = availableGWs.indexOf(activeGW);
    if (currentIndex > 0) {
      const prevGw = availableGWs[currentIndex - 1];
      previousSquadIds = manualOverrides[prevGw]?.ids || initialSquadIds;
    } else {
      previousSquadIds = initialSquadIds;
    }

    //const restoredSquadUnsorted = previousSquadIds.map(id => {
    //   const p = globalPlayers.find(x => String(x.ID) === String(id));
    //   const existing = teamData.find(t => String(t.ID) === String(id));
    //   return existing ? { ...p, Price: existing.Price } : { ...p, Price: getPlayerPrice(p) };
    // }).filter(Boolean);
    const restoredSquadUnsorted = previousSquadIds.map(id => hydratePlayer(id)).filter(Boolean);

    const opt = getValidLayoutWithPenalty(restoredSquadUnsorted, activeGW);
    const finalSquad = opt ? opt.optimalArray : restoredSquadUnsorted;

    let nextTransfers = { ...transfersByGw };
    delete nextTransfers[activeGW];

    let nextOverrides = { ...manualOverrides };
    nextOverrides[activeGW] = {
      ids: finalSquad.map(p => p.ID), cap: opt ? opt.cap : captainId, vice: opt ? opt.vice : viceId, forcedZeros: [], manualTransfers: {}
    };

    const { nextOverrides: cascadedO, nextTransfers: cascadedT, nextPairs: cascadedP } = updateFutureTimelines(teamData, finalSquad, nextOverrides, nextTransfers, solverTransferPairs);

    setTransfersByGw(cascadedT); setManualOverrides(cascadedO); setTeamData(finalSquad);
    if (opt) { setCaptainId(opt.cap); setViceId(opt.vice); }

    const nP = { ...cascadedP };
    delete nP[activeGW];
    setSolverTransferPairs(nP);

    setHighlightTransferIds(prev => { const next = { ...prev }; delete next[activeGW]; return clearFuture(next); });
    setChipsByGw(prev => { const next = { ...prev }; delete next[activeGW]; return clearFuture(next); });
    setSolverApplySnapshot(null); setAppliedPlanSummary(null);
  };

  // --- UI FIREWALL ---
  // Forces the Pitch to instantly drop stale undo buttons during GW tab switches
  const renderTeamData = useMemo(() => {
    const lock = manualOverrides[activeGW];
    return teamData.map(p => {
      if (p.isBlank && String(p.ID).startsWith("blank_")) return p;
      const cleanP = { ...p };
      if (lock?.manualTransfers && lock.manualTransfers[p.ID]) {
        cleanP.replacedPlayer = lock.manualTransfers[p.ID];
      } else {
        delete cleanP.replacedPlayer;
      }
      return cleanP;
    });
  }, [teamData, activeGW, manualOverrides]);

  return (
    <div className="flex flex-col w-full h-full pb-10">

      {/* Minimal Top Bar for Load */}
      <div className="w-full flex justify-end mb-4 z-dropdown">
        <form onSubmit={fetchTeam} className="flex gap-2 items-center bg-slate-900/40 px-4 py-2 rounded-xl border border-slate-800 backdrop-blur-sm shadow-xl">
          <div className="relative w-48">
            <Search className="absolute left-3 top-1/2 -translate-y-1/2 text-slate-500" size={14} />
            <input type="text" placeholder="FPL Team ID..." value={teamId} onChange={(e) => { setTeamId(e.target.value); setLastLoadedId(null); }} className="w-full bg-slate-950 border border-slate-700 rounded-lg py-1.5 pl-8 pr-3 text-xs text-slate-200 focus:outline-none focus:border-luigi-400 shadow-inner" />
          </div>
          <button type="submit" disabled={isLoading || (teamData.length > 0 && teamId === lastLoadedId)} className="bg-luigi-500 hover:bg-luigi-400 text-slate-950 font-bold px-3 py-1.5 rounded-lg text-xs flex items-center gap-1.5 shadow-lg transition-colors disabled:opacity-50 disabled:cursor-not-allowed">
            {isLoading ? <Loader2 size={14} className="animate-spin" /> : "Load"}
          </button>
        </form>
      </div>

      <div className="flex flex-col xl:flex-row gap-8 w-full">
        <div className="w-full xl:w-[72%] flex flex-col gap-4 xl:-mt-12 relative z-base">
          {teamData.length > 0 && isFixturesLoaded ? (
            <>

              {/* Pitch Rendering wrapper */}
              <DndContext sensors={sensors} collisionDetection={closestCenter} onDragStart={handleDragStart} onDragEnd={handleDragEnd}>

                <div className="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-2 bg-slate-900/30 p-3 rounded-xl border border-slate-800/50 mb-2">

                  {/* STATS ROW - Clean spacing, non-wrapping to prevent jitter */}
                  <div className="flex items-center gap-4 w-full overflow-x-auto hide-scrollbar">
                    <div className="flex flex-col">
                      <span className="text-[10px] font-black text-slate-500 uppercase">ITB</span>
                      <span className="text-sm font-mono font-bold text-emerald-400 tabular-nums">£{Math.abs(itb) < 0.05 ? "0.0" : itb.toFixed(1)}m</span>
                    </div>
                    <div className="flex flex-col">
                      <span className="text-[10px] font-black text-slate-500 uppercase">FT</span>
                      <span className="text-sm font-mono font-bold text-cyan-400 leading-tight whitespace-nowrap">
                        {(() => {
                          const chip = chipsByGw[activeGW]; const T = transfersByGw[activeGW]?.count ?? 0;
                          if (chip === "wc") return <><span className="text-yellow-400 text-xs font-black">⚡ WC</span> <span className="text-slate-500 text-[10px]">({T}/∞)</span></>;
                          if (chip === "fh") return <><span className="text-orange-400 text-xs font-black">↩ FH</span> <span className="text-slate-500 text-[10px]">({T}/∞)</span></>;
                          return `${T} / ${ftAtStartOfGw(activeGW, availableGWs, baselineFt, transfersByGw, chipsByGw)}${hitsThisGw > 0 ? ` (-${hitsThisGw * 4} pts)` : ""}`;
                        })()}
                      </span>
                    </div>
                    <div className="flex flex-col">
                      <span className="text-[10px] font-black text-slate-500 uppercase">Horizon</span>
                      <select value={horizon} onChange={(e) => setHorizon(Number(e.target.value))} className="bg-transparent text-sm font-mono font-bold text-luigi-400 outline-none cursor-pointer">
                        {Array.from({ length: maxAvailableHorizon }, (_, i) => i + 1).map((h) => (<option key={h} value={h} className="bg-slate-900">{h} {h === 1 ? "GW" : "GWs"}</option>))}
                      </select>
                    </div>
                    <div className="h-8 w-px bg-slate-700 hidden sm:block"></div>
                    <div className="flex flex-col">
                      <span className="text-[10px] font-black text-slate-500 uppercase whitespace-nowrap">GW {activeGW} EV</span>
                      <span className="text-sm font-mono font-bold text-cyan-400 tabular-nums">{activeGwEV.toFixed(2)}</span>
                    </div>
                    {horizonGWs.length > 1 && (
                      <div className="flex flex-col">
                        <span className="text-[10px] font-black text-slate-500 uppercase whitespace-nowrap">Horizon EV</span>
                        <span className="text-sm font-mono font-bold text-emerald-400 tabular-nums">{horizonEV.toFixed(2)}</span>
                      </div>
                    )}
                  </div>

                  {/* BUTTON ROW - Pushed to the right, strictly locked nowrap */}
                  <div className="flex flex-nowrap items-center justify-between gap-2 w-full">

                    {/* 1. RESET TRANSFERS/CHIPS BUTTON (Always Rendered, Disabled if Not Needed) */}
                    {(() => {
                      const canReset = (transfersByGw[activeGW]?.count > 0) || chipsByGw[activeGW] || (manualOverrides[activeGW]?.manualTransfers && Object.keys(manualOverrides[activeGW].manualTransfers).length > 0);
                      return (
                        <button
                          type="button"
                          onClick={handleResetGWTransfers}
                          disabled={!canReset}
                          className="flex items-center gap-1.5 px-3 py-1.5 rounded-lg bg-red-500/10 border border-red-500/20 text-red-400 text-[10px] font-black uppercase tracking-wider transition-all shadow-lg shrink-0 whitespace-nowrap hover:bg-red-500/20 hover:border-red-500/40 active:scale-95 disabled:opacity-30 disabled:cursor-not-allowed disabled:hover:bg-red-500/10 disabled:hover:border-red-500/20 disabled:active:scale-100 disabled:shadow-none"
                        >
                          <RotateCcw size={12} /> Reset
                        </button>
                      );
                    })()}

                    {/* 2. RESET LINEUP BUTTON (Always Rendered, Disabled if Not Needed) */}
                    {(() => {
                      let canResetLineup = false;
                      const gwLock = manualOverrides[activeGW];

                      if (gwLock?.ids && teamData.length === 15 && !teamData.some((p) => p.isBlank && !String(p.ID).startsWith("blank_"))) {
                        const opt = getValidLayoutWithPenalty(teamData, activeGW);
                        if (opt) {
                          const lockStarterSet = new Set(gwLock.ids.slice(0, 11));
                          const optStarterSet = new Set(opt.optimalArray.slice(0, 11).map((p) => p.ID));
                          const differentStarters = lockStarterSet.size !== optStarterSet.size || [...lockStarterSet].some((id) => !optStarterSet.has(id));
                          const meaningfulDiff = differentStarters || gwLock.cap !== opt.cap || gwLock.vice !== opt.vice;

                          if (meaningfulDiff) {
                            const getPts = (p) => Number(p[`${activeGW}_Pts`]) || 0;
                            const currentEV = teamData.slice(0, 11).reduce((sum, p) => sum + getPts(p) * (p.ID === gwLock.cap ? 2 : 1), 0);
                            const optEV = opt.optimalArray.slice(0, 11).reduce((sum, p) => sum + getPts(p) * (p.ID === opt.cap ? 2 : 1), 0);

                            if (optEV > currentEV + 0.01) {
                              canResetLineup = true;
                            }
                          }
                        }
                      }

                      return (
                        <button
                          onClick={handleResetGW}
                          disabled={!canResetLineup}
                          className="flex items-center gap-1.5 px-3 py-1.5 rounded-lg bg-luigi-500/10 border border-luigi-500/20 text-luigi-400 text-[10px] font-black uppercase tracking-wider transition-all shadow-lg shrink-0 whitespace-nowrap hover:bg-luigi-500/20 hover:border-luigi-500/40 active:scale-95 disabled:opacity-30 disabled:cursor-not-allowed disabled:hover:bg-luigi-500/10 disabled:hover:border-luigi-500/20 disabled:active:scale-100 disabled:shadow-none"
                          title="Reset Lineup to Optimal"
                        >
                          <RotateCcw size={12} /> Reset Lineup
                        </button>
                      );
                    })()}

                    {/* 3. CHIP DROPDOWN */}
                    <div className="flex items-center gap-1.5 shrink-0">
                      <span className="text-[10px] font-black text-slate-500 uppercase tracking-wider">Chip:</span>
                      <select value={chipsByGw[activeGW] || ""} onChange={(e) => handleChipSelect(activeGW, e.target.value || null)} className="bg-slate-900 border border-slate-700 rounded px-2 py-1 text-xs font-bold text-slate-300 focus:outline-none cursor-pointer focus:border-luigi-500">
                        <option value="">None</option><option value="wc">⚡ WC</option><option value="fh">↩ FH</option><option value="bb">⬆ BB</option><option value="tc">✕3 TC</option>
                      </select>
                    </div>

                  </div>
                </div>

                <DraftsComparisonTable
                  drafts={drafts}
                  horizonGWs={horizonGWs}
                  activeDraftId={activeDraftId}
                  globalPlayers={globalPlayers}
                  setActiveDraftId={setActiveDraftId}
                  getValidLayout={getValidLayoutWithPenalty}
                  availableGWs={availableGWs}
                  setDrafts={setDrafts}
                  baselineFt={baselineFt}
                  baselineItb={baselineItb}
                  ftAtStartOfGw={ftAtStartOfGw}
                  advancedSettings={advancedSettings}
                />

                {/* MULTIVERSE TIMELINE CONTROL BAR */}
                <div className="flex flex-col md:flex-row items-center justify-between gap-2 bg-slate-900/80 p-2 rounded-xl border border-[#2a2d5c] backdrop-blur-md shadow-lg mb-3 relative z-dropdown">

                  {/* LEFT: Custom Editable Dropdown Box */}
                  <div className="relative w-full md:w-56 shrink-0 z-popover">
                    <div className="flex items-center bg-[#0a0f1c] border border-[#2a2d5c] rounded-lg overflow-hidden shadow-[inset_0_2px_10px_rgba(0,0,0,0.5)] focus-within:border-indigo-500 transition-colors h-8">
                      <input
                        type="text"
                        value={drafts.find(d => d.id === activeDraftId)?.name || ""}
                        onChange={(e) => setDrafts(prev => prev.map(d => d.id === activeDraftId ? { ...d, name: e.target.value } : d))}
                        className="w-full bg-transparent text-indigo-100 font-bold text-[11px] py-1 px-3 outline-none placeholder:text-slate-600"
                        placeholder="Draft Name..."
                      />
                      <button
                        onClick={() => setShowDraftMenu(!showDraftMenu)}
                        className="px-2.5 h-full flex items-center justify-center bg-[#151833] border-l border-[#2a2d5c] hover:bg-[#1e2247] transition-colors"
                      >
                        <span className="text-indigo-400 text-[8px]">▼</span>
                      </button>
                    </div>

                    {showDraftMenu && (
                      <>
                        <div className="fixed inset-0 z-modal-backdrop" onClick={() => setShowDraftMenu(false)} />
                        <div className="absolute top-full left-0 mt-1.5 w-full bg-[#0a0f1c] border border-[#2a2d5c] rounded-lg shadow-[0_10px_40px_rgba(0,0,0,0.8)] overflow-hidden py-1 z-popover">
                          {drafts.map(d => (
                            <button
                              key={d.id}
                              onClick={() => { setActiveDraftId(d.id); setShowDraftMenu(false); }}
                              className={`w-full text-left px-3 py-2 text-[11px] font-bold transition-colors ${d.id === activeDraftId ? "bg-indigo-500/20 text-indigo-300" : "text-slate-400 hover:bg-[#151833] hover:text-slate-200"}`}
                            >
                              {d.name}
                            </button>
                          ))}
                        </div>
                      </>
                    )}
                  </div>

                  {/* CENTER: Gameweek Circles */}
                  <div className="flex gap-1.5 flex-wrap justify-center flex-1">
                    {horizonGWs.map((gw) => (
                      <button key={gw} type="button" onClick={() => setActiveGW(gw)} className={`small-touch-target relative w-7 h-7 rounded-full flex items-center justify-center text-[11px] font-bold transition-all ${activeGW === gw ? "bg-luigi-500 text-slate-950 scale-110 shadow-[0_0_10px_rgba(16,185,129,0.5)]" : "bg-slate-800 text-slate-400 hover:bg-slate-700 border border-slate-700"}`}>
                        {gw}
                        {chipsByGw[gw] && (<span className={`absolute -top-1 -right-1 w-3 h-3 rounded-full ${CHIP_CONFIG[chipsByGw[gw]].dot} flex items-center justify-center text-[6px] font-black text-slate-950 border border-slate-950 leading-none`} title={CHIP_CONFIG[chipsByGw[gw]].label}>{CHIP_CONFIG[chipsByGw[gw]].short[0]}</span>)}
                      </button>
                    ))}
                  </div>

                  {/* RIGHT: Clone / New Draft / Delete */}
                  {/* RIGHT: Clone / New Draft */}
                  <div className="flex items-center justify-end gap-1.5 w-full md:w-auto shrink-0">
                    <button onClick={handleCloneDraft} disabled={drafts.length >= 5} className="small-touch-target flex items-center gap-1.5 px-3 py-1.5 bg-indigo-500/10 hover:bg-indigo-500/20 text-indigo-400 border border-indigo-500/20 rounded-lg text-[10px] font-black uppercase tracking-wider transition-all shadow-md active:scale-95 disabled:opacity-50 disabled:cursor-not-allowed" title="Clone reality">
                      <Copy size={12} /> Clone
                    </button>
                    <button onClick={handleNewDraft} disabled={drafts.length >= 5} className="small-touch-target flex items-center gap-1.5 px-3 py-1.5 bg-emerald-500/10 hover:bg-emerald-500/20 text-emerald-400 border border-emerald-500/20 rounded-lg text-[10px] font-black uppercase tracking-wider transition-all shadow-md active:scale-95 disabled:opacity-50 disabled:cursor-not-allowed" title="New timeline">
                      <Plus size={12} /> New
                    </button>
                  </div>
                </div>

                <PitchView
                  teamData={renderTeamData}
                  activeDragPlayer={activeDragPlayer}
                  isValidSwap={isValidSwap}
                  captainId={captainId}
                  viceId={viceId}
                  handleCapChange={handleCapChange}
                  playerCardGWs={playerCardGWs}
                  fixtures={fixtures}
                  activeGW={activeGW}
                  setSelectedPlayer={setSelectedPlayer}
                  handleUndoTransfer={handleUndoTransfer}
                  highlightTransferIds={highlightTransferIds}
                  solverTransferPairs={solverTransferPairs}
                  resetHighlightedTransfer={resetHighlightedTransfer}
                  chipsByGw={chipsByGw}
                />

                <DragOverlay dropAnimation={null}>
                  {activeDragPlayer && !activeDragPlayer.isBlank ? (
                    <PlayerCardVisual player={activeDragPlayer} isBench={false} captainId={captainId} viceId={viceId} playerCardGWs={playerCardGWs} fixtures={fixtures} activeGW={activeGW} />
                  ) : null}
                </DragOverlay>
              </DndContext>
            </>
          ) : (
            <div className="w-full min-h-[500px] border-2 border-dashed border-slate-800 rounded-2xl flex items-center justify-center text-slate-500 bg-[#0a3a2a]/30 flex-col gap-4 relative overflow-hidden">
              {isLoadingDB || isLoading ? (
                <>
                  <div className="absolute inset-0 pointer-events-none flex flex-col items-center justify-evenly py-12 px-8">
                    {[1, 4, 4, 2].map((count, rowIdx) => (
                      <div key={rowIdx} className="flex justify-center gap-6 sm:gap-10">
                        {Array.from({ length: count }).map((_, i) => (
                          <div key={i} className="w-[52px] sm:w-[68px] h-[72px] sm:h-[92px] rounded-xl bg-slate-800/50 skeleton-pulse" style={{ animationDelay: `${(rowIdx * count + i) * 0.12}s` }} />
                        ))}
                      </div>
                    ))}
                  </div>
                  <Loader2 size={32} className="animate-spin text-emerald-500 z-base" />
                  <span className="z-base text-sm font-bold text-slate-400">{isLoading ? "Loading squad..." : "Booting Global Engine..."}</span>
                </>
              ) : (
                "Enter your FPL ID above to load your squad."
              )}
            </div>
          )}
        </div>

        {/* Right Column */}
        <div className="w-full xl:w-[28%] flex flex-col gap-4">

          {/* NEW HOME FOR TABS PANEL */}
          <div className="rounded-2xl border border-slate-700/50 bg-slate-950/80 backdrop-blur-md shadow-xl overflow-hidden relative shrink-0">
            <TabsPanel
              solverTab={solverTab}
              setSolverTab={setSolverTab}
              isSolving={isSolving}
              isRunningSens={isRunningSens}
              isChipSolving={isChipSolving}
              runMainSolver={runMainSolver}
              runSensAnalysis={runSensAnalysis}
              runChipSolve={runChipSolve}
              setShowAdvancedSettings={setShowAdvancedSettings}
              quickSettings={quickSettings}
              setQuickSettings={setQuickSettings}
              banSearch={banSearch}
              setBanSearch={setBanSearch}
              lockSearch={lockSearch}
              setLockSearch={setLockSearch}
              globalPlayers={globalPlayers}
              teamData={renderTeamData}
              solveGWLabel={solveGWLabel}
              numSims={numSims}
              setNumSims={setNumSims}
              sensResults={sensResults}
              setSensResults={setSensResults}
              sensViewGw={sensViewGw}
              setSensViewGw={setSensViewGw}
              chipSolveOptions={chipSolveOptions}
              setChipSolveOptions={setChipSolveOptions}
              chipSolveSolutions={chipSolveSolutions}
              setChipSolveSolutions={setChipSolveSolutions}
              horizonGWs={horizonGWs}
              baselineEv={horizonEV}
            />
          </div>

          <ActiveMovesPanel
            activeGW={activeGW}
            manualOverrides={manualOverrides}
            globalPlayers={globalPlayers}
            chipsByGw={chipsByGw}
            transfersByGw={transfersByGw}
          />

          <SolverOutputPanel
            pendingSolutions={pendingSolutions}
            setPendingSolutions={setPendingSolutions}
            isSolving={isSolving}
            globalPlayers={globalPlayers}
            applySolution={applySolution}
            appliedPlanSummary={appliedPlanSummary}
            setAppliedPlanSummary={setAppliedPlanSummary}
            baselineEv={horizonEV}
            comprehensiveSettings={comprehensiveSettings}
          />
        </div>

      </div>

      {/* MODALS */}
      {selectedPlayer && !selectedPlayer.isBlank && (
        <PlayerEditModal
          selectedPlayer={selectedPlayer} setSelectedPlayer={setSelectedPlayer} activeGW={activeGW} horizonGWs={horizonGWs} updatePlayerStat={updatePlayerStat} handleTransferOut={handleTransferOut} fixtures={fixtures} fixtureOverrides={fixtureOverrides} sessionEdits={sessionEdits} globalPlayers={globalPlayers}
        />
      )}
      {selectedPlayer && selectedPlayer.isBlank && (
        <PlayerSearchModal
          selectedPlayer={selectedPlayer} setSelectedPlayer={setSelectedPlayer} searchQuery={searchQuery} setSearchQuery={setSearchQuery} sortConfig={sortConfig} setSortConfig={setSortConfig} globalPlayers={globalPlayers} ownedPlayerIds={ownedPlayerIds} activeGW={activeGW} itb={itb} handleAddPlayer={handleAddPlayer}
        />
      )}
      {showAdvancedSettings && (
        <AdvancedSettingsModal
          setShowAdvancedSettings={setShowAdvancedSettings} comprehensiveSettings={comprehensiveSettings} setComprehensiveSettings={setComprehensiveSettings} advancedSettings={advancedSettings} setAdvancedSettings={setAdvancedSettings}
        />
      )}

      {/* LOADING PORTALS */}
      {isSolving && createPortal(
        <div className="fixed inset-0 z-modal flex flex-col items-center justify-center bg-slate-950/80 backdrop-blur-md p-6">
          <div className="pointer-events-none absolute inset-0 bg-[radial-gradient(circle_at_50%_35%,rgba(16,185,129,0.14),transparent_50%)]" />
          <div className="relative flex max-w-md flex-col items-center gap-8 rounded-2xl border border-luigi-500/20 bg-slate-950/90 px-10 py-12 shadow-[0_0_60px_rgba(16,185,129,0.15)]">
            <div className="relative flex h-32 w-32 items-center justify-center">
              <div className="absolute inset-0 rounded-full border-4 border-slate-800" />
              <div className="absolute inset-0 animate-spin rounded-full border-4 border-luigi-500 border-t-transparent" />
              {/* BRANDED LOGO */}
              <img src="/l-logo.png" alt="Solving" className="relative w-12 h-12 object-contain animate-pulse drop-shadow-[0_0_15px_rgba(16,185,129,0.6)]" />
            </div>
            <div className="text-center">
              <p className="mb-2 text-lg font-black uppercase tracking-[0.2em] text-luigi-400">Solving</p>
              <p className="font-mono text-xs text-slate-400">Elapsed {solveElapsedSec}s · up to {quickSettings.iterations} iteration(s)</p>
            </div>
            <button type="button" onClick={() => abortControllerRef.current?.abort()} className="mt-4 px-6 py-2 rounded-xl bg-slate-900 border border-slate-700 text-slate-400 hover:text-white hover:border-slate-500 font-bold transition-all text-sm">Cancel Solve</button>
          </div>
        </div>, document.body
      )}

      {isChipSolving && createPortal(
        <div className="fixed inset-0 z-modal flex flex-col items-center justify-center bg-slate-950/80 backdrop-blur-md p-6">
          <div className="pointer-events-none absolute inset-0 bg-[radial-gradient(circle_at_50%_35%,rgba(168,85,247,0.14),transparent_50%)]" />
          <div className="relative flex max-w-md flex-col items-center gap-8 rounded-2xl border border-purple-500/20 bg-slate-950/90 px-10 py-12 shadow-[0_0_60px_rgba(168,85,247,0.15)]">
            <div className="relative flex h-32 w-32 items-center justify-center">
              <div className="absolute inset-0 rounded-full border-4 border-slate-800" />
              <div className="absolute inset-0 animate-spin rounded-full border-4 border-purple-500 border-t-transparent" />
              {/* BRANDED LOGO */}
              <img src="l-logo.png" alt="Solving" className="relative w-12 h-12 object-contain animate-pulse drop-shadow-[0_0_15px_rgba(168,85,247,0.6)]" />
            </div>
            <div className="text-center">
              <p className="mb-2 text-lg font-black uppercase tracking-[0.2em] text-purple-400">Chip Solving</p>
              <p className="font-mono text-xs text-slate-400">Elapsed {chipSolveTimer}s</p>

            </div>
            <button type="button" onClick={() => abortControllerRef.current?.abort()} className="mt-4 px-6 py-2 rounded-xl bg-slate-900 border border-slate-700 text-slate-400 hover:text-white hover:border-slate-500 font-bold transition-all text-sm">Cancel Solve</button>
          </div>
        </div>, document.body
      )}

      {isRunningSens && createPortal(
        <div className="fixed inset-0 z-modal flex flex-col items-center justify-center bg-slate-950/80 backdrop-blur-md p-6">
          <div className="pointer-events-none absolute inset-0 bg-[radial-gradient(circle_at_50%_35%,rgba(6,182,212,0.14),transparent_50%)]" />
          <div className="relative flex max-w-md flex-col items-center gap-8 rounded-2xl border border-cyan-500/20 bg-slate-950/90 px-10 py-12 shadow-[0_0_60px_rgba(6,182,212,0.15)]">
            <div className="relative flex h-32 w-32 items-center justify-center">
              <div className="absolute inset-0 rounded-full border-4 border-slate-800" />
              <div className="absolute inset-0 animate-spin rounded-full border-4 border-cyan-500 border-t-transparent" />
              {/* BRANDED LOGO */}
              <img src="l-logo.png" alt="Solving" className="relative w-12 h-12 object-contain animate-pulse drop-shadow-[0_0_15px_rgba(6,182,212,0.6)]" />
            </div>
            <div className="text-center">
              <p className="mb-2 text-lg font-black uppercase tracking-[0.2em] text-cyan-400">Sensitivity Analysis</p>
              <p className="font-mono text-xs text-slate-400">Elapsed {sensTimer}s · {numSims} sims running…</p>

            </div>
            <button type="button" onClick={() => abortControllerRef.current?.abort()} className="mt-4 px-6 py-2 rounded-xl bg-slate-900 border border-slate-700 text-slate-400 hover:text-white hover:border-slate-500 font-bold transition-all text-sm">Cancel Solve</button>
          </div>
        </div>, document.body
      )}

      {showIdPrompt && (
        <div className="fixed inset-0 z-modal flex items-center justify-center bg-black/80 backdrop-blur-sm p-4">
          <div className="bg-slate-950 border border-slate-800 w-full max-w-sm rounded-2xl p-6 flex flex-col items-center">
            <Shield size={24} className="text-luigi-400 mb-4" />
            <h3 className="text-xl font-black text-slate-100 mb-2">Save as Default ID?</h3>
            <div className="flex gap-3 w-full mt-4">
              <button onClick={() => setShowIdPrompt(false)} className="flex-1 bg-slate-900 text-slate-300 py-2.5 rounded-xl border border-slate-700">Not Now</button>
              <button onClick={() => { setUserProfile((prev) => ({ ...prev, defaultTeamId: pendingTeamId })); setShowIdPrompt(false); }} className="flex-1 bg-luigi-500 text-slate-950 py-2.5 rounded-xl font-bold">Save ID</button>
            </div>
          </div>
        </div>
      )}
      {/* INITIAL LOGIN ID PROMPT */}
      {showInitialIdPrompt && (
        <div className="fixed inset-0 z-critical flex items-center justify-center bg-black/80 backdrop-blur-sm p-4">
          <div className="bg-slate-950 border border-slate-800 w-full max-w-sm rounded-2xl p-6 flex flex-col items-center shadow-[0_0_40px_rgba(16,185,129,0.1)]">
            <Shield size={32} className="text-emerald-500 mb-4" />
            <h3 className="text-xl font-black text-slate-100 mb-2">Welcome!</h3>
            <p className="text-xs text-slate-400 text-center mb-6">Enter your FPL Team ID to set it as your default for future logins.</p>
            <input
              type="number"
              value={initialIdInput}
              onChange={(e) => setInitialIdInput(e.target.value)}
              placeholder="e.g. 123456"
              className="w-full bg-slate-900 border border-slate-700 rounded-lg py-2.5 px-4 text-sm font-bold text-slate-200 focus:outline-none focus:border-emerald-500 text-center mb-4"
            />
            <div className="flex gap-3 w-full">
              <button onClick={() => setShowInitialIdPrompt(false)} className="flex-1 bg-slate-900 text-slate-400 py-2.5 rounded-xl border border-slate-700 hover:text-slate-300 transition-colors text-sm font-bold">Skip</button>
              <button onClick={handleSaveInitialId} className="flex-1 bg-emerald-500 text-slate-950 py-2.5 rounded-xl font-black hover:bg-emerald-400 transition-colors shadow-lg text-sm">Save Default ID</button>
            </div>
          </div>
        </div>
      )}
    </div>
  );
}