const { useState, useEffect, useRef, useCallback } = React;

// ─── API routes ───────────────────────────────────────────────────────────────
const DATA_BASE  = "/data";
const TRADE_BASE = "/trade";

const FINNHUB_KEY_DEFAULT = "d7fhr61r01qpjqqksd40d7fhr61r01qpjqqksd4g";

// ─── Auth helpers ─────────────────────────────────────────────────────────────
const getToken = () => localStorage.getItem("spyic_token") || "";
// Authenticated headers — used for every fetch
const h = () => ({
  "Content-Type": "application/json",
  ...(getToken() ? { "Authorization": `Bearer ${getToken()}` } : {}),
});

// ─── Block keywords for news filter ──────────────────────────────────────────
const BLOCK_KEYWORDS = [
  "fomc","federal reserve","interest rate decision","rate decision",
  "cpi","consumer price index","nonfarm","non-farm","nfp","payroll",
  "gdp","gross domestic product","pce","core pce","ppi","producer price",
  "unemployment","jobs report","fed chair","powell","inflation",
  "retail sales","ism manufacturing","ism services",
  "consumer confidence","michigan sentiment",
];

// ─── Strategy rules ────────────────────────────────────────────────────────────
const RULES = {
  ticker:           "SPY",
  targetDTE:        1,
  shortDeltaMin:    0.15,
  shortDeltaMax:    0.20,
  wingWidth:        5,
  scanStart:        { h:15, m:45 },
  entryStart:       { h:15, m:50 },
  entryEnd:         { h:15, m:58 },
  hardCloseH:       15, hardCloseM: 55,
  profitTargetLow:  0.45,
  profitTargetHigh: 0.55,
  ivThreshold:      20,
  stopMultiplier:   1.0,
  monitorInterval:  60000,
};

// ─── Helpers ──────────────────────────────────────────────────────────────────
const fmt    = (n, d=2) => n == null ? "—" : Number(n).toFixed(d);
const fmtPct = (n)      => n == null ? "—" : `${(n*100).toFixed(1)}%`;
const ts     = ()       => new Date().toLocaleTimeString("en-US",{hour12:false});

function getETNow() {
  return new Date(new Date().toLocaleString("en-US",{timeZone:"America/New_York"}));
}
function getDTE(expDate) {
  return Math.ceil((new Date(expDate+"T16:00:00") - new Date()) / 86400000);
}
function parseSymbol(sym) {
  try {
    const m = sym.match(/^([A-Z]+)(\d{6})([CP])(\d{8})$/);
    if (!m) return null;
    const [,root,date,cp,sp] = m;
    return { root, expDate:`20${date.slice(0,2)}-${date.slice(2,4)}-${date.slice(4,6)}`,
             strike:parseInt(sp)/1000, type:cp==="C"?"call":"put" };
  } catch { return null; }
}
function msUntilET(h, m) {
  const now = getETNow(), t = new Date(now);
  t.setHours(h, m, 0, 0);
  return Math.max(0, t - now);
}
function todayET()    { return getETNow().toISOString().slice(0,10); }
function tomorrowET() { const e=getETNow(); e.setDate(e.getDate()+1); return e.toISOString().slice(0,10); }

// ─── Audio alert ──────────────────────────────────────────────────────────────
function playAlert(freq=440, duration=800, repeats=3) {
  try {
    const ctx = new (window.AudioContext || window.webkitAudioContext)();
    for (let i=0; i<repeats; i++) {
      const osc=ctx.createOscillator(), gain=ctx.createGain();
      osc.connect(gain); gain.connect(ctx.destination);
      osc.frequency.value=freq;
      gain.gain.setValueAtTime(0.3, ctx.currentTime+i*0.4);
      gain.gain.exponentialRampToValueAtTime(0.001, ctx.currentTime+i*0.4+duration/1000);
      osc.start(ctx.currentTime+i*0.4);
      osc.stop(ctx.currentTime+i*0.4+duration/1000);
    }
  } catch(_) {}
}

// ─── Journal: generate insights from stats ────────────────────────────────────
function generateInsights(stats) {
  if (!stats || stats.closed < 5) return ["Need at least 5 closed trades to generate insights."];
  const ins = [];

  // Overall win rate
  const wr = stats.winRate;
  if (wr >= 0.75) ins.push(`✅ Strong win rate of ${(wr*100).toFixed(0)}% — strategy performing well.`);
  else if (wr >= 0.60) ins.push(`✅ Solid win rate of ${(wr*100).toFixed(0)}% — on track with expectations.`);
  else if (wr >= 0.50) ins.push(`⚠ Win rate ${(wr*100).toFixed(0)}% — slightly below 1DTE IC target (~65%). Monitor closely.`);
  else ins.push(`🛑 Win rate ${(wr*100).toFixed(0)}% — below threshold. Consider tightening delta range or increasing wing width.`);

  // IV regime comparison
  const hi = stats.highIV, nor = stats.normalIV;
  if (hi.count >= 3 && nor.count >= 3) {
    const hiWR = hi.wins / hi.count, norWR = nor.wins / nor.count;
    if (hiWR > norWR + 0.10)
      ins.push(`📈 High-IV days outperform: ${(hiWR*100).toFixed(0)}% win vs ${(norWR*100).toFixed(0)}% normal. Prioritize entries when VIXY > 20.`);
    else if (norWR > hiWR + 0.10)
      ins.push(`📉 Normal-IV trades outperform (${(norWR*100).toFixed(0)}% vs ${(hiWR*100).toFixed(0)}%). Strikes may be too narrow in high-IV.`);
    else
      ins.push(`⚖ IV regime has minimal impact on win rate — strategy is consistent across conditions.`);
    if (hi.avgPnl > nor.avgPnl + 5)
      ins.push(`💰 High-IV entries yield $${fmt(hi.avgPnl - nor.avgPnl)} more avg P&L vs normal IV.`);
  }

  // Day of week
  const dayWRs = ["Mon","Tue","Wed","Thu"]
    .map(d => ({ day: d, ...(stats.byDay[d] || {wins:0,losses:0,pnl:0}) }))
    .map(d => ({ ...d, total: d.wins + d.losses, wr: d.wins + d.losses > 0 ? d.wins / (d.wins + d.losses) : null }))
    .filter(d => d.total >= 2);
  if (dayWRs.length >= 2) {
    const best = [...dayWRs].sort((a,b) => b.wr - a.wr)[0];
    const worst = [...dayWRs].sort((a,b) => a.wr - b.wr)[0];
    ins.push(`📅 Best day: ${best.day} (${(best.wr*100).toFixed(0)}% win). Weakest: ${worst.day} (${(worst.wr*100).toFixed(0)}% win).`);
  }

  // Average credit vs P&L
  if (stats.avgCredit > 0 && stats.closed >= 5) {
    const retPct = (stats.avgPnl / stats.avgCredit * 100).toFixed(0);
    ins.push(`💵 Avg return on credit: ${retPct}% (avg P&L $${fmt(stats.avgPnl)} on avg credit $${fmt(stats.avgCredit)}).`);
  }

  // Stop frequency
  if (stats.closed >= 5) {
    const stopRate = stats.losses / stats.closed;
    if (stopRate > 0.35)
      ins.push(`🛑 Stop rate ${(stopRate*100).toFixed(0)}% — consider reviewing market conditions on loss days.`);
  }

  // Total P&L trajectory
  if (stats.totalPnl > 0)
    ins.push(`📊 Cumulative P&L: +$${fmt(stats.totalPnl)} over ${stats.closed} closed trades.`);
  else
    ins.push(`📊 Cumulative P&L: -$${fmt(Math.abs(stats.totalPnl))} over ${stats.closed} closed trades — still building edge.`);

  return ins;
}

// ─── Main component ───────────────────────────────────────────────────────────
function ICTerminal() {

  // ── Auth state ──────────────────────────────────────────────────────────────
  const [authed,        setAuthed]        = useState(false);
  const [authChecking,  setAuthChecking]  = useState(true);
  const [loginUser,     setLoginUser]     = useState("admin");
  const [loginPass,     setLoginPass]     = useState("");
  const [loginError,    setLoginError]    = useState("");
  const [liveMode,      setLiveMode]      = useState(false);

  // ── Trade history state ─────────────────────────────────────────────────────
  const [tradeHistory,     setTradeHistory]     = useState([]);
  const [tradeStats,       setTradeStats]       = useState(null);
  const [currentTradeId,   setCurrentTradeId]   = useState(null);
  const currentTradeIdRef  = useRef(null);
  useEffect(() => { currentTradeIdRef.current = currentTradeId; }, [currentTradeId]);

  // ── Chain / market state ────────────────────────────────────────────────────
  const [tab, setTab]                 = useState("builder");
  const [chain, setChain]             = useState([]);
  const [expiries, setExpiries]       = useState([]);
  const [selectedExp, setSelectedExp] = useState("");
  const [spyPrice, setSpyPrice]       = useState(null);
  const [vix, setVix]                 = useState(null);
  const [loading, setLoading]         = useState(false);
  const [logs, setLogs]               = useState([]);
  const [position, setPosition]       = useState(null);
  const [orderResult, setOrderResult] = useState(null);
  const [autoMode, setAutoMode]       = useState(false);
  const [autoStatus, setAutoStatus]   = useState("idle");
  const [placing, setPlacing]         = useState(false);
  const [newsEvents, setNewsEvents]   = useState([]);
  const [newsBlocked, setNewsBlocked] = useState(false);
  const [finnhubKey, setFinnhubKey]   = useState(FINNHUB_KEY_DEFAULT);
  const [nextWakeTime, setNextWakeTime] = useState(null);
  const [ntfyEnabled, setNtfyEnabled]   = useState(true);

  // ── P&L monitor state ───────────────────────────────────────────────────────
  const [currentValue,   setCurrentValue]   = useState(null);
  const [currentPnl,     setCurrentPnl]     = useState(null);
  const [pnlPct,         setPnlPct]         = useState(null);
  const [monitorStatus,  setMonitorStatus]  = useState("idle");
  const [alertFired,     setAlertFired]     = useState(false);
  const [lastPoll,       setLastPoll]       = useState(null);

  const pnlRef       = useRef(null);
  const sleepRef     = useRef(null);
  const watchRef     = useRef(null);
  const monitorRef   = useRef(null);
  const autoRef      = useRef(false);
  const posRef       = useRef(null);

  useEffect(() => { posRef.current = position; }, [position]);
  useEffect(() => { pnlRef.current = currentPnl; }, [currentPnl]);

  // ── Auth: check on mount ───────────────────────────────────────────────────
  useEffect(() => {
    const checkAuth = async () => {
      try {
        const healthRes = await fetch("/health");
        const health    = await healthRes.json();
        if (!health.authEnabled) {
          setAuthed(true);
          setLiveMode(health.liveMode || false);
          setAuthChecking(false);
          return;
        }
        // Auth is enabled — validate stored token
        const token = localStorage.getItem("spyic_token");
        if (token) {
          const r = await fetch("/api/trades?limit=1", {
            headers: { "Authorization": `Bearer ${token}` },
          });
          if (r.ok) {
            setAuthed(true);
            setLiveMode(health.liveMode || false);
          } else {
            localStorage.removeItem("spyic_token");
          }
        }
      } catch {}
      setAuthChecking(false);
    };
    checkAuth();
  }, []);

  // ── Login ──────────────────────────────────────────────────────────────────
  const login = useCallback(async () => {
    setLoginError("");
    try {
      const r = await fetch("/api/login", {
        method:  "POST",
        headers: { "Content-Type": "application/json" },
        body:    JSON.stringify({ username: loginUser, password: loginPass }),
      });
      const d = await r.json();
      if (r.ok) {
        localStorage.setItem("spyic_token", d.token);
        setAuthed(true);
        // Fetch mode info
        const mr = await fetch("/api/mode", { headers: { "Authorization": `Bearer ${d.token}` } });
        if (mr.ok) { const md = await mr.json(); setLiveMode(md.liveMode); }
      } else {
        setLoginError(d.error || "Login failed");
      }
    } catch {
      setLoginError("Cannot connect to server");
    }
  }, [loginUser, loginPass]);

  const logout = useCallback(() => {
    localStorage.removeItem("spyic_token");
    setAuthed(false);
    setLoginPass("");
    setLoginError("");
  }, []);

  // ── History: load trades + stats from backend ─────────────────────────────
  const fetchHistory = useCallback(async () => {
    try {
      const [tr, sr] = await Promise.all([
        fetch("/api/trades", { headers: h() }),
        fetch("/api/stats",  { headers: h() }),
      ]);
      if (tr.ok) { const d = await tr.json(); setTradeHistory(d.trades || []); }
      if (sr.ok) setTradeStats(await sr.json());
    } catch {}
  }, []);

  useEffect(() => { if (authed) fetchHistory(); }, [authed, fetchHistory]);

  // ── Record trade open on backend ──────────────────────────────────────────
  const recordTradeOpen = useCallback(async (pos) => {
    try {
      const r = await fetch("/api/trades", {
        method:  "POST",
        headers: h(),
        body:    JSON.stringify({
          enteredAt:        pos.enteredAt,
          expiry:           pos.expiry,
          shortPutStrike:   pos.shortPut.strike,
          shortCallStrike:  pos.shortCall.strike,
          longPutStrike:    pos.longPut.strike,
          longCallStrike:   pos.longCall.strike,
          creditDollars:    pos.creditDollars,
          profitTarget:     pos.pt,
          stopLoss:         pos.stop,
          ivAtEntry:        vix,
          spyPriceAtEntry:  spyPrice,
          isHighIV:         pos.isHighIV,
          dte:              getDTE(pos.expiry),
          mode:             liveMode ? "live" : "paper",
        }),
      });
      if (r.ok) {
        const trade = await r.json();
        setCurrentTradeId(trade.id);
        currentTradeIdRef.current = trade.id;
        fetchHistory();
      }
    } catch {}
  }, [vix, spyPrice, liveMode, fetchHistory]);

  // ── Record trade close on backend ─────────────────────────────────────────
  const recordTradeClose = useCallback(async (pnl, reason) => {
    const id = currentTradeIdRef.current;
    if (!id) return;
    try {
      await fetch(`/api/trades/${id}`, {
        method:  "PUT",
        headers: h(),
        body:    JSON.stringify({
          closedAt:    new Date().toISOString(),
          pnl:         pnl != null ? Math.round(pnl * 100) / 100 : null,
          closeReason: reason,
        }),
      });
      setCurrentTradeId(null);
      currentTradeIdRef.current = null;
      fetchHistory();
    } catch {}
  }, [fetchHistory]);

  const log = useCallback((msg, type="info") => {
    setLogs(l => [{time:ts(), msg, type}, ...l].slice(0,100));
  }, []);

  // ── Push notification (ntfy.sh via server) ──────────────────────────────
  const notify = useCallback(async (title, message, priority=0) => {
    log(`📱 ${title}: ${message}`, "info");
    if (!ntfyEnabled) return;
    // Map 0/1/2 priority to ntfy 3/4/5
    const ntfyPri = priority === 0 ? 3 : priority === 1 ? 4 : 5;
    try {
      await fetch("/api/notify", {
        method:  "POST",
        headers: h(),
        body: JSON.stringify({ title, message, priority: ntfyPri }),
      });
    } catch(e) { log(`Push failed: ${e.message}`, "warn"); }
  }, [ntfyEnabled, log]);

  // ── Fetch chain + prices ──────────────────────────────────────────────────
  const fetchData = useCallback(async (quiet=false) => {
    if (!quiet) setLoading(true);
    try {
      const [snapRes, vixRes, chainRes] = await Promise.all([
        fetch(`${DATA_BASE}/v2/stocks/SPY/snapshot`,  {headers:h()}),
        fetch(`${DATA_BASE}/v2/stocks/VIXY/snapshot`, {headers:h()}),
        fetch(`${DATA_BASE}/v1beta1/options/snapshots/SPY?feed=indicative&limit=500`,{headers:h()}),
      ]);
      if (snapRes.ok)  { const s=await snapRes.json();  setSpyPrice(s?.latestTrade?.p||s?.minuteBar?.c||null); }
      if (vixRes.ok)   { const v=await vixRes.json();   setVix(v?.latestTrade?.p||v?.minuteBar?.c||null); }
      if (!chainRes.ok){ if(!quiet) log(`Chain error: ${chainRes.status}`,"error"); return []; }

      const data = await chainRes.json();
      const raw  = Object.entries(data.snapshots||{}).map(([sym,s])=>{
        const p=parseSymbol(sym); if(!p) return null;
        const bid=s?.latestQuote?.bp, ask=s?.latestQuote?.ap;
        return { symbol:sym, ...p, bid, ask,
          mid:(bid!=null&&ask!=null)?(bid+ask)/2:null,
          last:s?.latestTrade?.p, iv:s?.greeks?.impliedVolatility,
          delta:s?.greeks?.delta, theta:s?.greeks?.theta,
          dte:getDTE(p.expDate) };
      }).filter(Boolean).sort((a,b)=>a.expDate.localeCompare(b.expDate)||a.strike-b.strike);

      // Fill missing put deltas from put-call parity
      const callDeltaMap = {};
      raw.filter(c=>c.type==="call"&&c.delta!=null).forEach(c=>{
        if (!callDeltaMap[c.expDate]) callDeltaMap[c.expDate]={};
        callDeltaMap[c.expDate][c.strike]=c.delta;
      });
      raw.forEach(c=>{
        if (c.type==="put"&&c.delta==null) {
          const cd=callDeltaMap[c.expDate]?.[c.strike];
          if (cd!=null) c.delta=cd-1;
        }
      });

      const contracts   = raw.filter(c=>c.dte>=1);
      const uniqueExp   = [...new Set(contracts.map(c=>c.expDate))].sort();
      setExpiries(uniqueExp);
      if (!selectedExp||!uniqueExp.includes(selectedExp)) {
        const best=uniqueExp.find(e=>getDTE(e)===1)||uniqueExp.find(e=>getDTE(e)===2)||uniqueExp[0];
        setSelectedExp(best||"");
      }
      setChain(contracts);
      const withDelta=contracts.filter(c=>c.delta!=null).length;
      if (!quiet) log(`Chain loaded — ${contracts.length} contracts (${withDelta} with Δ)`,"success");
      return contracts;
    } catch(e) {
      if (!quiet) log(`Fetch error: ${e.message}`,"error");
      return [];
    } finally { if (!quiet) setLoading(false); }
  }, [selectedExp, log]);

  // ── Quote for a single option ─────────────────────────────────────────────
  const getOptionMid = useCallback(async (symbol) => {
    try {
      const r = await fetch(`${DATA_BASE}/v1beta1/options/snapshots/${symbol}?feed=indicative`,{headers:h()});
      if (!r.ok) return null;
      const d = await r.json();
      const s = d.snapshots?.[symbol];
      const bid=s?.latestQuote?.bp, ask=s?.latestQuote?.ap;
      return (bid!=null&&ask!=null)?(bid+ask)/2 : s?.latestTrade?.p ?? null;
    } catch { return null; }
  }, []);

  // ── Current IC value (cost to close all 4 legs) ───────────────────────────
  const calcCurrentValue = useCallback(async (pos) => {
    if (!pos) return null;
    const [spMid,lpMid,scMid,lcMid] = await Promise.all([
      getOptionMid(pos.shortPut.symbol),
      getOptionMid(pos.longPut.symbol),
      getOptionMid(pos.shortCall.symbol),
      getOptionMid(pos.longCall.symbol),
    ]);
    if ([spMid,lpMid,scMid,lcMid].some(v=>v==null)) return null;
    return { currentVal:(spMid+scMid)-(lpMid+lcMid), spMid,lpMid,scMid,lcMid };
  }, [getOptionMid]);

  // ── Close IC (BTC all 4 legs) ─────────────────────────────────────────────
  const closeIC = useCallback(async (pos, reason) => {
    if (!pos) return;
    setMonitorStatus("closing");
    log(`🔄 Closing IC — reason: ${reason}`, "warn");
    const closingLegs = [
      {symbol:pos.shortPut.symbol,  side:"buy"},
      {symbol:pos.longPut.symbol,   side:"sell"},
      {symbol:pos.shortCall.symbol, side:"buy"},
      {symbol:pos.longCall.symbol,  side:"sell"},
    ];
    let allOk = true;
    for (const leg of closingLegs) {
      try {
        const r = await fetch(`${TRADE_BASE}/v2/orders`, {
          method:"POST", headers:h(),
          body:JSON.stringify({...leg, qty:"1", type:"market", time_in_force:"day"}),
        });
        const d = await r.json();
        if (r.ok) log(`✓ CLOSED ${leg.side.toUpperCase()} ${leg.symbol}`,"success");
        else { log(`✗ ${leg.symbol}: ${d.message}`,"error"); allOk=false; }
      } catch(e) { log(`✗ ${leg.symbol}: ${e.message}`,"error"); allOk=false; }
    }
    if (allOk) {
      log(`✅ IC fully closed — ${reason}`,"success");
      setMonitorStatus("closed");
      setPosition(null);
      posRef.current = null;
      await recordTradeClose(pnlRef.current, reason);
      await notify(`IC CLOSED — ${reason}`, `Reason: ${reason}`, 1);
    } else {
      log("⚠ Partial close — check Alpaca dashboard immediately","error");
      setMonitorStatus("idle");
      playAlert(220, 1000, 5);
      await notify("⚠ CLOSE FAILED", `Auto-close failed for: ${reason}. Manual action required NOW.`, 2);
    }
    if (monitorRef.current) clearInterval(monitorRef.current);
  }, [log, notify, recordTradeClose]);

  // ── P&L Monitor loop ──────────────────────────────────────────────────────
  const startMonitor = useCallback((pos) => {
    if (monitorRef.current) clearInterval(monitorRef.current);
    setMonitorStatus("monitoring");
    log("📊 P&L monitor started — polling every 60s","info");

    const poll = async () => {
      const activePos = posRef.current;
      if (!activePos) { clearInterval(monitorRef.current); return; }
      const result = await calcCurrentValue(activePos);
      if (!result) { log("Could not fetch quotes — retrying next poll","warn"); return; }
      const { currentVal } = result;
      const pnlPerShare = activePos.credit - currentVal;
      const pnlDollars  = pnlPerShare * 100;
      const pnlPercent  = pnlPerShare / activePos.credit;
      setCurrentValue(currentVal * 100);
      setCurrentPnl(pnlDollars);
      setPnlPct(pnlPercent);
      pnlRef.current = pnlDollars;
      setLastPoll(new Date().toLocaleTimeString());
      log(`📊 P&L: ${pnlDollars>=0?"+":""}$${fmt(pnlDollars)} (${(pnlPercent*100).toFixed(1)}%) | IC value: $${fmt(currentVal*100)}`,"info");
      const et  = getETNow();
      const hm  = et.getHours()*60 + et.getMinutes();
      const hcl = RULES.hardCloseH*60 + RULES.hardCloseM;
      if (hm >= hcl && getDTE(activePos.expiry) <= 0) {
        clearInterval(monitorRef.current);
        log("⏰ Hard close time reached (3:55 PM on expiry day)","warn");
        await closeIC(activePos, "Hard close — expiry day 3:55 PM ET");
        return;
      }
      if (pnlDollars >= activePos.pt) {
        clearInterval(monitorRef.current);
        setMonitorStatus("tp_hit");
        log(`🎯 PROFIT TARGET HIT — $${fmt(pnlDollars)} (${(pnlPercent*100).toFixed(1)}%)`, "success");
        playAlert(880, 600, 3);
        await notify("🎯 PROFIT TARGET HIT", `IC profit: +$${fmt(pnlDollars)} (${(pnlPercent*100).toFixed(1)}%). Auto-closing.`, 1);
        await closeIC(activePos, `Profit target hit (+$${fmt(pnlDollars)})`);
        return;
      }
      if (pnlDollars <= -activePos.stop) {
        clearInterval(monitorRef.current);
        setMonitorStatus("stop_hit");
        log(`🛑 STOP LOSS HIT — $${fmt(Math.abs(pnlDollars))} loss`, "error");
        playAlert(220, 1000, 5);
        await notify("🛑 STOP LOSS HIT", `IC loss: -$${fmt(Math.abs(pnlDollars))}. Auto-closing.`, 2);
        await closeIC(activePos, `Stop loss hit (-$${fmt(Math.abs(pnlDollars))})`);
        return;
      }
      if (!alertFired && pnlDollars <= -(activePos.stop * 0.8)) {
        setAlertFired(true);
        log("⚠ WARNING: Approaching stop loss threshold","warn");
        playAlert(440, 500, 2);
        await notify("⚠ IC WARNING", `IC approaching stop: -$${fmt(Math.abs(pnlDollars))}. Stop at -$${fmt(activePos.stop)}.`, 0);
      }
    };
    poll();
    monitorRef.current = setInterval(poll, RULES.monitorInterval);
  }, [calcCurrentValue, closeIC, alertFired, log, notify]);

  // ── News scan ─────────────────────────────────────────────────────────────
  const scanNews = useCallback(async () => {
    log("📰 Scanning economic calendar…","info");
    if (!finnhubKey || finnhubKey === "YOUR_FINNHUB_KEY_HERE") {
      log("⚠ No Finnhub key — news scan skipped","warn"); return {blocked:false,events:[]};
    }
    try {
      const r = await fetch(`/finnhub/calendar/economic?from=${todayET()}&to=${tomorrowET()}&token=${finnhubKey}`, {headers:h()});
      if (!r.ok) { log(`Finnhub ${r.status}`,"warn"); return {blocked:false,events:[]}; }
      const data = await r.json();
      const events = (data.economicCalendar||[]).filter(e=>{
        const impact=(e.impact||"").toLowerCase(), name=(e.event||"").toLowerCase();
        return impact==="high"||Number(e.impact)>=3||BLOCK_KEYWORDS.some(k=>name.includes(k));
      });
      if (events.length>0) {
        log(`🚨 ${events.length} high-impact event(s) — BLOCKING entry`,"error");
        events.forEach(e=>log(`  • ${e.event} (impact: ${e.impact})`,"warn"));
        setNewsEvents(events); setNewsBlocked(true);
        return {blocked:true,events};
      }
      log("✅ News clear","success"); setNewsEvents([]); setNewsBlocked(false);
      return {blocked:false,events:[]};
    } catch(e) { log(`News scan error: ${e.message}`,"warn"); return {blocked:false,events:[]}; }
  }, [finnhubKey, log]);

  // ── Build IC ──────────────────────────────────────────────────────────────
  const buildIC = useCallback((chainData, priceOverride) => {
    const price = priceOverride || spyPrice;
    if (!chainData.length||!selectedExp||!price) return null;
    const filtered = chainData.filter(c=>c.expDate===selectedExp);
    const shortPut  = filtered.filter(c=>c.type==="put"&&c.delta!=null)
      .sort((a,b)=>Math.abs(Math.abs(a.delta)-0.175)-Math.abs(Math.abs(b.delta)-0.175))
      .find(c=>Math.abs(c.delta)>=0.12&&Math.abs(c.delta)<=0.22);
    const shortCall = filtered.filter(c=>c.type==="call"&&c.delta!=null)
      .sort((a,b)=>Math.abs(a.delta-0.175)-Math.abs(b.delta-0.175))
      .find(c=>c.delta>=0.12&&c.delta<=0.22);
    if (!shortPut||!shortCall) return null;
    const longPut  = filtered.find(c=>c.type==="put" &&Math.abs(c.strike-(shortPut.strike -RULES.wingWidth))<0.51);
    const longCall = filtered.find(c=>c.type==="call"&&Math.abs(c.strike-(shortCall.strike+RULES.wingWidth))<0.51);
    if (!longPut||!longCall) return null;
    const credit = ((shortPut.mid||0)+(shortCall.mid||0)-(longPut.mid||0)-(longCall.mid||0));
    const isHighIV = vix && vix > RULES.ivThreshold;
    const ptPct    = isHighIV ? RULES.profitTargetHigh : RULES.profitTargetLow;
    return { shortPut, longPut, shortCall, longCall, credit, ptPct, isHighIV };
  }, [selectedExp, spyPrice, vix]);

  // ── Place IC ──────────────────────────────────────────────────────────────
  const placeIC = useCallback(async (icData) => {
    if (!icData||placing) return;
    setPlacing(true);
    log("Placing IC — 4 legs…","info");
    const {shortPut,longPut,shortCall,longCall,credit,ptPct,isHighIV} = icData;
    const legDefs = [
      {symbol:shortPut.symbol, side:"sell"},{symbol:longPut.symbol,   side:"buy"},
      {symbol:shortCall.symbol,side:"sell"},{symbol:longCall.symbol,  side:"buy"},
    ];
    const results=[];
    for (const leg of legDefs) {
      try {
        const r=await fetch(`${TRADE_BASE}/v2/orders`,{method:"POST",headers:h(),
          body:JSON.stringify({...leg,qty:"1",type:"market",time_in_force:"day"})});
        const d=await r.json();
        results.push({ok:r.ok,data:d,...leg});
        log(`${r.ok?"✓":"✗"} ${leg.side.toUpperCase()} ${leg.symbol}`,r.ok?"success":"error");
      } catch(e) { results.push({ok:false,...leg}); log(`✗ ${leg.symbol}: ${e.message}`,"error"); }
    }
    const allOk     = results.every(r=>r.ok);
    const creditD   = credit*100, pt=creditD*ptPct, stop=creditD*RULES.stopMultiplier;
    const newPos    = {shortPut,longPut,shortCall,longCall,credit,creditDollars:creditD,
      pt,stop,ptPct,isHighIV,enteredAt:new Date().toISOString(),expiry:selectedExp};
    setPosition(newPos); posRef.current=newPos;
    setOrderResult({allOk,results});
    setAlertFired(false);
    setAutoStatus("placed");
    log(allOk?`✅ IC placed! Credit:$${fmt(creditD)} PT:$${fmt(pt)} Stop:$${fmt(stop)}`:"⚠ Partial fill",allOk?"success":"warn");
    await notify("📈 IC ENTERED",`SPY IC opened. Credit:$${fmt(creditD)} | PT:$${fmt(pt)} | Stop:$${fmt(stop)}`,0);
    setTab("monitor");
    setPlacing(false);
    if (allOk) {
      startMonitor(newPos);
      await recordTradeOpen(newPos);
    }
    return newPos;
  }, [placing,selectedExp,log,notify,startMonitor,recordTradeOpen]);

  // ── Stop auto ────────────────────────────────────────────────────────────
  const stopAuto = useCallback(() => {
    autoRef.current=false;
    if (sleepRef.current)  { clearTimeout(sleepRef.current);  sleepRef.current=null; }
    if (watchRef.current)  { clearInterval(watchRef.current); watchRef.current=null; }
    setAutoStatus("idle"); setAutoMode(false); setNextWakeTime(null);
    log("Auto-mode stopped","warn");
  }, [log]);

  // ── Entry window watcher ──────────────────────────────────────────────────
  const startWatchWindow = useCallback(() => {
    setAutoStatus("watching");
    log("⏰ Entry window 3:50–3:58 PM ET — watching…","info");
    watchRef.current = setInterval(async () => {
      if (!autoRef.current) { clearInterval(watchRef.current); return; }
      const et=getETNow(), hm=et.getHours()*60+et.getMinutes();
      if (hm > RULES.entryEnd.h*60+RULES.entryEnd.m) {
        clearInterval(watchRef.current);
        log("Entry window closed — nothing placed today","warn");
        stopAuto(); return;
      }
      const fresh = await fetchData(true);
      const ic = buildIC(fresh);
      if (ic && ic.credit > 0.05) {
        clearInterval(watchRef.current);
        await placeIC(ic);
        stopAuto();
      } else { log("IC not ready — retry in 15s…","info"); }
    }, 15000);
  }, [fetchData, buildIC, placeIC, stopAuto, log]);

  // ── Auto engine ───────────────────────────────────────────────────────────
  const runAuto = useCallback(async () => {
    if (!autoRef.current) return;
    const et=getETNow(), day=et.getDay();
    if (day===0||day===5||day===6) {
      log(`📅 ${["Sun","Mon","Tue","Wed","Thu","Fri","Sat"][day]} — no trading (Mon–Thu only)`,"warn");
      stopAuto(); return;
    }
    const msToScan = msUntilET(RULES.scanStart.h, RULES.scanStart.m);
    if (msToScan > 0) {
      const wakeAt=new Date(Date.now()+msToScan);
      setAutoStatus("sleeping"); setNextWakeTime(wakeAt.toLocaleTimeString("en-US",{hour12:true}));
      log(`😴 Sleeping — waking at ${wakeAt.toLocaleTimeString()} ET.`,"info");
      sleepRef.current = setTimeout(async () => {
        if (!autoRef.current) return;
        setNextWakeTime(null);
        log("⏰ Woke 3:45 PM — fetching data + scanning news…","info");
        setAutoStatus("scanning");
        const [fresh, newsResult] = await Promise.all([fetchData(true), scanNews()]);
        if (!autoRef.current) return;
        if (newsResult.blocked) { setAutoStatus("blocked"); stopAuto(); return; }
        const msToEntry = msUntilET(RULES.entryStart.h, RULES.entryStart.m);
        if (msToEntry > 0) {
          log(`News clear ✅ — waiting ${Math.round(msToEntry/1000)}s until 3:50…`,"info");
          sleepRef.current = setTimeout(() => { if(autoRef.current) startWatchWindow(); }, msToEntry);
        } else { startWatchWindow(); }
      }, msToScan);
    } else {
      const hm=et.getHours()*60+et.getMinutes();
      const es=RULES.entryStart.h*60+RULES.entryStart.m, ee=RULES.entryEnd.h*60+RULES.entryEnd.m;
      if (hm>=es&&hm<=ee) {
        setAutoStatus("scanning");
        const news=await scanNews();
        if (news.blocked) { setAutoStatus("blocked"); stopAuto(); return; }
        startWatchWindow();
      } else { log("Past entry window today","warn"); stopAuto(); }
    }
  }, [fetchData, scanNews, startWatchWindow, stopAuto, log]);

  const toggleAuto = useCallback(() => {
    if (autoMode) { stopAuto(); return; }
    autoRef.current=true; setAutoMode(true);
    log("Auto-mode armed","info"); runAuto();
  }, [autoMode, stopAuto, runAuto, log]);

  useEffect(() => () => {
    stopAuto();
    if (monitorRef.current) clearInterval(monitorRef.current);
  }, [stopAuto]);

  // ─────────────────────────────────────────────────────────────────────────────
  // Derived values
  // ─────────────────────────────────────────────────────────────────────────────
  const ic         = buildIC(chain);
  const expDTE     = selectedExp ? getDTE(selectedExp) : null;
  const isHighIV   = vix && vix > RULES.ivThreshold;

  const statusColor = {idle:"#4a5080",sleeping:"#a78bfa",scanning:"#f0c040",
    watching:"#22d3ee",blocked:"#f87171",placed:"#34d399"}[autoStatus]||"#4a5080";
  const statusLabel = {idle:"IDLE",sleeping:`SLEEPING → ${nextWakeTime||"3:45 PM"}`,
    scanning:"SCANNING NEWS",watching:"WATCHING 3:50–3:58",
    blocked:"BLOCKED (NEWS)",placed:"ORDER PLACED"}[autoStatus]||"IDLE";
  const monitorColor = {idle:"#4a5080",monitoring:"#22d3ee",tp_hit:"#34d399",
    stop_hit:"#f87171",closing:"#f0c040",closed:"#a78bfa"}[monitorStatus]||"#4a5080";
  const pnlColor = currentPnl==null?"#4a5080":currentPnl>=0?"#34d399":"#f87171";

  // ─────────────────────────────────────────────────────────────────────────────
  // Auth: loading / login screens
  // ─────────────────────────────────────────────────────────────────────────────
  if (authChecking) {
    return (
      <div style={{fontFamily:"'IBM Plex Mono',monospace",background:"#07070f",minHeight:"100vh",
        display:"flex",alignItems:"center",justifyContent:"center",color:"#22d3ee"}}>
        Connecting…
      </div>
    );
  }

  if (!authed) {
    return (
      <div style={{fontFamily:"'IBM Plex Mono',monospace",background:"#07070f",minHeight:"100vh",
        display:"flex",alignItems:"center",justifyContent:"center"}}>
        <div style={{background:"#0d0d1f",border:"1px solid #22d3ee44",borderRadius:8,padding:"36px 44px",minWidth:320}}>
          <div style={{display:"flex",alignItems:"center",gap:10,marginBottom:28}}>
            <div style={{width:8,height:8,borderRadius:"50%",background:"#22d3ee",boxShadow:"0 0 8px #22d3ee"}}/>
            <span style={{color:"#22d3ee",fontWeight:700,fontSize:13,letterSpacing:"0.15em"}}>SPY IC BOT</span>
          </div>
          {loginError && (
            <div style={{background:"#2a0f0f",border:"1px solid #7f1d1d",borderRadius:5,
              padding:"8px 12px",marginBottom:14,color:"#f87171",fontSize:11}}>
              {loginError}
            </div>
          )}
          <input type="text" value={loginUser} onChange={e=>setLoginUser(e.target.value)}
            placeholder="Username"
            style={{width:"100%",background:"#07070f",border:"1px solid #2a2a3e",color:"#f0f0f8",
              padding:"9px 12px",borderRadius:5,fontFamily:"inherit",fontSize:12,marginBottom:10,
              boxSizing:"border-box"}}/>
          <input type="password" value={loginPass} onChange={e=>setLoginPass(e.target.value)}
            placeholder="Password" onKeyDown={e=>e.key==="Enter"&&login()}
            style={{width:"100%",background:"#07070f",border:"1px solid #2a2a3e",color:"#f0f0f8",
              padding:"9px 12px",borderRadius:5,fontFamily:"inherit",fontSize:12,marginBottom:18,
              boxSizing:"border-box"}}/>
          <button onClick={login}
            style={{width:"100%",background:"#22d3ee",color:"#07070f",border:"none",padding:"10px",
              borderRadius:5,fontFamily:"inherit",fontWeight:700,fontSize:12,cursor:"pointer"}}>
            LOGIN
          </button>
        </div>
      </div>
    );
  }

  // ─────────────────────────────────────────────────────────────────────────────
  // Main app
  // ─────────────────────────────────────────────────────────────────────────────
  return (
    <div style={{fontFamily:"'IBM Plex Mono',monospace",background:"#07070f",minHeight:"100vh",color:"#dde1f0"}}>

      {/* HEADER */}
      <div style={{borderBottom:"1px solid #151528",padding:"10px 18px",display:"flex",
        alignItems:"center",gap:10,flexWrap:"wrap"}}>
        <div style={{width:8,height:8,borderRadius:"50%",background:"#22d3ee",boxShadow:"0 0 8px #22d3ee"}}/>
        <span style={{color:"#22d3ee",fontWeight:700,fontSize:12,letterSpacing:"0.15em"}}>SPY IC TERMINAL v3</span>
        {liveMode && (
          <span style={{background:"#4a0000",border:"1px solid #f87171",borderRadius:3,
            padding:"2px 7px",fontSize:10,color:"#f87171",fontWeight:700}}>🔴 LIVE</span>
        )}
        {!liveMode && (
          <span style={{background:"#0a1a10",border:"1px solid #34d39944",borderRadius:3,
            padding:"2px 7px",fontSize:10,color:"#34d399"}}>PAPER</span>
        )}
        <div style={{marginLeft:"auto",display:"flex",gap:12,fontSize:11,alignItems:"center",flexWrap:"wrap"}}>
          {spyPrice && <span>SPY <span style={{color:"#f0c040",fontWeight:700}}>${fmt(spyPrice)}</span></span>}
          {vix      && <span>VIXY <span style={{color:isHighIV?"#f87171":"#34d399",fontWeight:700}}>${fmt(vix)}</span></span>}
          {tradeStats && tradeStats.closed > 0 && (
            <span style={{color:tradeStats.totalPnl>=0?"#34d399":"#f87171",fontSize:10}}>
              ALL-TIME {tradeStats.totalPnl>=0?"+":""}{fmt(tradeStats.totalPnl)}
            </span>
          )}
          {position && currentPnl!=null && (
            <span style={{color:pnlColor,fontWeight:700}}>
              P&L {currentPnl>=0?"+":""}{fmt(currentPnl)} ({pnlPct!=null?(pnlPct*100).toFixed(1)+"%":"—"})
            </span>
          )}
          <span style={{color:statusColor,fontWeight:700,fontSize:10}}>● {statusLabel}</span>
          {monitorStatus==="monitoring" && <span style={{color:"#22d3ee",fontSize:10}}>📊 MONITORING</span>}
        </div>
      </div>

      {/* RULES STRIP */}
      <div style={{background:"#0a0a1a",borderBottom:"1px solid #151528",padding:"5px 18px",
        fontSize:10,color:"#3a4060",display:"flex",gap:14,flexWrap:"wrap"}}>
        <span>15–20Δ · $5 WINGS · 1DTE · MON–THU</span>
        <span>SLEEP→3:45 · NEWS 3:45-3:50 · ENTRY 3:50-3:58</span>
        <span>PT {isHighIV?"55%":"45%"} · STOP 1:1 · AUTO-CLOSE + ALERT</span>
      </div>

      <div style={{padding:"14px 18px",maxWidth:1100,margin:"0 auto"}}>

        {/* ACTION BAR */}
        <div style={{display:"flex",gap:8,marginBottom:14,flexWrap:"wrap",alignItems:"center"}}>
          <button onClick={()=>fetchData(false)} disabled={loading}
            style={{background:loading?"#1a1a2e":"#22d3ee",color:"#07070f",border:"none",
              padding:"7px 14px",borderRadius:5,fontFamily:"inherit",fontWeight:700,fontSize:11,
              cursor:loading?"default":"pointer"}}>
            {loading?"LOADING…":"↻ REFRESH"}
          </button>
          <div style={{display:"flex",gap:5,flexWrap:"wrap"}}>
            {expiries.map(e=>{
              const d=getDTE(e),best=d===1||d===2;
              return <button key={e} onClick={()=>setSelectedExp(e)}
                style={{background:selectedExp===e?"#22d3ee":best?"#0f2030":"#0d0d1a",
                  color:selectedExp===e?"#07070f":best?"#22d3ee":"#4a5080",
                  border:`1px solid ${selectedExp===e?"#22d3ee":best?"#22d3ee44":"#1e1e3e"}`,
                  padding:"4px 9px",borderRadius:4,fontSize:10,fontFamily:"inherit",cursor:"pointer",
                  fontWeight:selectedExp===e?700:400}}>{e} ({d}d)</button>;
            })}
          </div>
          <button onClick={toggleAuto}
            style={{marginLeft:"auto",background:autoMode?"#0f2530":"#0d0d1a",
              color:autoMode?"#22d3ee":"#4a5080",
              border:`1px solid ${autoMode?"#22d3ee":"#1e1e3e"}`,
              padding:"7px 14px",borderRadius:5,fontFamily:"inherit",fontSize:11,fontWeight:700,cursor:"pointer"}}>
            {autoMode?"⬛ STOP AUTO":"▶ START AUTO"}
          </button>
        </div>

        {newsBlocked && (
          <div style={{background:"#2a0f0f",border:"1px solid #7f1d1d",borderRadius:6,
            padding:"10px 14px",marginBottom:12,fontSize:11}}>
            <div style={{color:"#f87171",fontWeight:700,marginBottom:5}}>🚨 ENTRY BLOCKED — HIGH-IMPACT EVENTS</div>
            {newsEvents.map((e,i)=><div key={i} style={{color:"#fca5a5"}}>• {e.event} (impact: {e.impact})</div>)}
          </div>
        )}

        {/* TABS */}
        <div style={{display:"flex",borderBottom:"1px solid #151528",marginBottom:14,flexWrap:"wrap"}}>
          {[
            ["builder","BUILDER"],
            ["monitor","MONITOR"],
            ["history","HISTORY"],
            ["journal","JOURNAL"],
            ["rules","RULES"],
            ["settings","SETTINGS"],
            ["log","LOG"],
          ].map(([t,l])=>(
            <button key={t} onClick={()=>setTab(t)}
              style={{background:"transparent",border:"none",
                borderBottom:tab===t?"2px solid #22d3ee":"2px solid transparent",
                color:tab===t?"#22d3ee":"#4a5080",padding:"7px 14px",fontFamily:"inherit",
                fontSize:11,fontWeight:700,cursor:"pointer"}}>
              {l}{t==="monitor"&&position?" ●":""}{t==="history"&&tradeStats?` (${tradeStats.closed})`:""}
            </button>
          ))}
        </div>

        {/* ── BUILDER ── */}
        {tab==="builder" && (
          <div>
            {!chain.length
              ? <div style={{color:"#4a5080",fontSize:12}}>Click REFRESH to load SPY chain.</div>
              : !ic
              ? <div style={{color:"#f0c040",fontSize:12}}>⚠ Cannot build IC — refresh chain or select different expiry.</div>
              : <>
                <div style={{color:"#3a4060",fontSize:10,marginBottom:10}}>
                  AUTO-BUILT · <span style={{color:"#22d3ee"}}>{selectedExp}</span> ({expDTE}DTE) · 15–20Δ · $5 wings
                </div>
                <div style={{overflowX:"auto",marginBottom:14}}>
                  <table style={{width:"100%",borderCollapse:"collapse",fontSize:11}}>
                    <thead><tr style={{color:"#2a3050",borderBottom:"1px solid #151528"}}>
                      {["ROLE","TYPE","STRIKE","DELTA","BID","ASK","MID","IV"].map(hd=>(
                        <th key={hd} style={{padding:"5px 9px",textAlign:"left",fontWeight:400}}>{hd}</th>))}
                    </tr></thead>
                    <tbody>
                      {[{role:"SELL PUT",leg:ic.shortPut,c:"#f87171"},
                        {role:"BUY PUT", leg:ic.longPut, c:"#4a5080"},
                        {role:"SELL CALL",leg:ic.shortCall,c:"#34d399"},
                        {role:"BUY CALL", leg:ic.longCall, c:"#4a5080"},
                      ].map(({role,leg,c})=>(
                        <tr key={leg.symbol} style={{borderBottom:"1px solid #0d0d1a"}}>
                          <td style={{padding:"7px 9px",color:c,fontWeight:700,fontSize:10}}>{role}</td>
                          <td style={{padding:"7px 9px",color:leg.type==="call"?"#34d399":"#f87171"}}>{leg.type.toUpperCase()}</td>
                          <td style={{padding:"7px 9px",fontWeight:700}}>${fmt(leg.strike)}</td>
                          <td style={{padding:"7px 9px",color:"#a78bfa"}}>{fmt(leg.delta,3)}</td>
                          <td style={{padding:"7px 9px",color:"#34d399"}}>{leg.bid!=null?`$${fmt(leg.bid)}`:"—"}</td>
                          <td style={{padding:"7px 9px",color:"#f87171"}}>{leg.ask!=null?`$${fmt(leg.ask)}`:"—"}</td>
                          <td style={{padding:"7px 9px",color:"#f0c040",fontWeight:600}}>{leg.mid!=null?`$${fmt(leg.mid)}`:"—"}</td>
                          <td style={{padding:"7px 9px",color:"#a78bfa"}}>{fmtPct(leg.iv)}</td>
                        </tr>
                      ))}
                    </tbody>
                  </table>
                </div>
                <div style={{display:"grid",gridTemplateColumns:"repeat(auto-fit,minmax(120px,1fr))",gap:8,marginBottom:14}}>
                  {[["CREDIT",`$${fmt(ic.credit*100)}`,"#f0c040"],
                    ["PROFIT TARGET",`$${fmt(ic.credit*100*ic.ptPct)} (${Math.round(ic.ptPct*100)}%)`,"#34d399"],
                    ["STOP LOSS",`$${fmt(ic.credit*100)} (1:1)`,"#f87171"],
                    ["MAX RISK",`$${fmt((RULES.wingWidth-ic.credit)*100)}`,"#f87171"],
                    ["IV REGIME",ic.isHighIV?"HIGH":"NORMAL",ic.isHighIV?"#f87171":"#34d399"],
                  ].map(([l,v,c])=>(
                    <div key={l} style={{background:"#0d0d1f",border:"1px solid #151528",borderRadius:5,padding:"8px 10px"}}>
                      <div style={{color:"#2a3050",fontSize:9,marginBottom:3}}>{l}</div>
                      <div style={{color:c,fontSize:13,fontWeight:700}}>{v}</div>
                    </div>
                  ))}
                </div>
                {!position
                  ? <button onClick={()=>placeIC(ic)} disabled={placing}
                      style={{background:placing?"#1a1a2e":"#22d3ee",color:"#07070f",border:"none",
                        padding:"11px 24px",borderRadius:5,fontFamily:"inherit",fontWeight:700,
                        fontSize:13,cursor:placing?"default":"pointer"}}>
                      {placing?"PLACING…":`▶ PLACE IC + START MONITOR (${liveMode?"LIVE":"PAPER"})`}
                    </button>
                  : <div style={{color:"#34d399",fontSize:12,fontWeight:700}}>✓ Position open — see MONITOR</div>
                }
              </>
            }
          </div>
        )}

        {/* ── MONITOR ── */}
        {tab==="monitor" && (
          <div>
            {!position ? <div style={{color:"#4a5080",fontSize:12}}>No open position.</div> : <>
              <div style={{background:"#0d0d1f",border:"1px solid #151528",borderRadius:8,padding:16,marginBottom:14}}>
                <div style={{display:"flex",justifyContent:"space-between",alignItems:"center",marginBottom:10}}>
                  <span style={{color:"#3a4060",fontSize:10,letterSpacing:"0.1em"}}>LIVE P&L</span>
                  <span style={{color:monitorColor,fontSize:10,fontWeight:700}}>● {monitorStatus.toUpperCase().replace("_"," ")}</span>
                  {lastPoll && <span style={{color:"#2a3050",fontSize:10}}>last poll: {lastPoll}</span>}
                </div>
                <div style={{fontSize:32,fontWeight:700,color:pnlColor,marginBottom:6}}>
                  {currentPnl!=null?`${currentPnl>=0?"+":""}$${fmt(Math.abs(currentPnl))}`:"Polling…"}
                </div>
                {pnlPct!=null && (
                  <div style={{fontSize:14,color:pnlColor,marginBottom:10}}>{(pnlPct*100).toFixed(1)}% of credit</div>
                )}
                {currentPnl!=null && position && (
                  <div style={{position:"relative",height:8,background:"#1a1a2e",borderRadius:4,overflow:"hidden"}}>
                    <div style={{position:"absolute",left:`${Math.min(100,(position.pt/(position.pt+position.stop))*100)}%`,
                      top:0,bottom:0,width:2,background:"#34d399",opacity:0.6}}/>
                    <div style={{position:"absolute",left:"0%",top:0,bottom:0,width:2,background:"#f87171",opacity:0.6}}/>
                    <div style={{position:"absolute",left:"50%",top:0,bottom:0,
                      width:`${Math.abs(currentPnl)/(position.pt+position.stop)*50}%`,
                      background:currentPnl>=0?"#34d399":"#f87171",
                      transform:currentPnl>=0?"none":"translateX(-100%)"}}/>
                  </div>
                )}
                <div style={{display:"flex",justifyContent:"space-between",fontSize:10,color:"#3a4060",marginTop:4}}>
                  <span>STOP -${fmt(position?.stop)}</span>
                  <span>ENTRY</span>
                  <span>PT +${fmt(position?.pt)}</span>
                </div>
              </div>
              <div style={{display:"grid",gridTemplateColumns:"repeat(auto-fit,minmax(130px,1fr))",gap:8,marginBottom:14}}>
                {[["CREDIT",`$${fmt(position.creditDollars)}`,"#f0c040"],
                  ["PROFIT TARGET",`$${fmt(position.pt)}`,"#34d399"],
                  ["STOP",`$${fmt(position.stop)}`,"#f87171"],
                  ["EXPIRY",position.expiry,"#22d3ee"],
                  ["ENTERED",new Date(position.enteredAt).toLocaleTimeString(),"#a78bfa"],
                  ["DTE",`${getDTE(position.expiry)}DTE`,"#22d3ee"],
                ].map(([l,v,c])=>(
                  <div key={l} style={{background:"#0d0d1f",border:"1px solid #151528",borderRadius:5,padding:"8px 10px"}}>
                    <div style={{color:"#2a3050",fontSize:9,marginBottom:3}}>{l}</div>
                    <div style={{color:c,fontSize:12,fontWeight:700}}>{v}</div>
                  </div>
                ))}
              </div>
              <div style={{background:"#100e06",border:"1px solid #2a2010",borderRadius:6,padding:12,marginBottom:12,fontSize:11}}>
                <div style={{color:"#f0c040",fontSize:9,marginBottom:6,letterSpacing:"0.1em"}}>AUTO-CLOSE RULES (ACTIVE)</div>
                <div style={{color:"#c09040",marginBottom:3}}>✅ Auto-close + notify when profit ≥ ${fmt(position.pt)} ({Math.round(position.ptPct*100)}%)</div>
                <div style={{color:"#c09040",marginBottom:3}}>🛑 Auto-close + notify when loss ≥ ${fmt(position.stop)} (1:1)</div>
                <div style={{color:"#c09040",marginBottom:3}}>⚠ Alert at 80% of stop (-${fmt(position.stop*0.8)})</div>
                <div style={{color:"#c09040"}}>📅 Hard close at 3:55 PM on expiry day</div>
              </div>
              {orderResult && (
                <div style={{background:orderResult.allOk?"#052e16":"#2a0f0f",
                  border:`1px solid ${orderResult.allOk?"#166534":"#7f1d1d"}`,borderRadius:6,
                  padding:12,marginBottom:12,fontSize:11}}>
                  <div style={{color:orderResult.allOk?"#34d399":"#f87171",fontWeight:700,marginBottom:4}}>
                    {orderResult.allOk?"✓ ALL 4 LEGS SUBMITTED":"⚠ CHECK DASHBOARD"}
                  </div>
                  {orderResult.results.map(r=>(
                    <div key={r.symbol} style={{color:r.ok?"#6ee7b7":"#fca5a5",marginBottom:2}}>
                      {r.ok?"✓":"✗"} {r.side?.toUpperCase()} {r.symbol}
                    </div>
                  ))}
                </div>
              )}
              <button onClick={async()=>{
                if(monitorRef.current) clearInterval(monitorRef.current);
                await closeIC(position,"Manual close");
              }}
                style={{background:"#2a0f0f",color:"#f87171",border:"1px solid #7f1d1d",
                  padding:"9px 18px",borderRadius:5,fontFamily:"inherit",fontWeight:700,
                  fontSize:11,cursor:"pointer"}}>
                CLOSE POSITION (MANUAL BTC)
              </button>
            </>}
          </div>
        )}

        {/* ── HISTORY ── */}
        {tab==="history" && (
          <div>
            {/* Stats cards */}
            {tradeStats && tradeStats.closed > 0 && (
              <div style={{display:"grid",gridTemplateColumns:"repeat(auto-fit,minmax(110px,1fr))",gap:8,marginBottom:14}}>
                {[
                  ["TOTAL TRADES",   tradeStats.closed,   "#22d3ee"],
                  ["WIN RATE",       tradeStats.winRate != null ? `${(tradeStats.winRate*100).toFixed(0)}%` : "—",
                                     tradeStats.winRate >= 0.6 ? "#34d399" : "#f87171"],
                  ["TOTAL P&L",      `${tradeStats.totalPnl>=0?"+":""}$${fmt(tradeStats.totalPnl)}`,
                                     tradeStats.totalPnl >= 0 ? "#34d399" : "#f87171"],
                  ["AVG P&L",        `${tradeStats.avgPnl>=0?"+":""}$${fmt(tradeStats.avgPnl)}`,
                                     tradeStats.avgPnl >= 0 ? "#34d399" : "#f87171"],
                  ["AVG CREDIT",     `$${fmt(tradeStats.avgCredit)}`, "#f0c040"],
                  ["WINS / LOSSES",  `${tradeStats.wins} / ${tradeStats.losses}`, "#a78bfa"],
                  ["OPEN",           tradeStats.open, "#22d3ee"],
                ].map(([l,v,c])=>(
                  <div key={l} style={{background:"#0d0d1f",border:"1px solid #151528",borderRadius:5,padding:"8px 10px"}}>
                    <div style={{color:"#2a3050",fontSize:9,marginBottom:3}}>{l}</div>
                    <div style={{color:c,fontSize:13,fontWeight:700}}>{v}</div>
                  </div>
                ))}
              </div>
            )}

            {/* Refresh button */}
            <div style={{display:"flex",justifyContent:"space-between",alignItems:"center",marginBottom:10}}>
              <span style={{color:"#3a4060",fontSize:10}}>{tradeHistory.length} trades total</span>
              <button onClick={fetchHistory}
                style={{background:"#0d0d1f",border:"1px solid #1e1e3e",color:"#4a5080",
                  padding:"4px 10px",borderRadius:4,fontFamily:"inherit",fontSize:10,cursor:"pointer"}}>
                ↻ refresh
              </button>
            </div>

            {/* Trade table */}
            {tradeHistory.length === 0 ? (
              <div style={{background:"#0d0d1f",border:"1px solid #151528",borderRadius:6,
                padding:"24px",textAlign:"center",color:"#4a5080",fontSize:12}}>
                No trade history yet. Place your first trade to start tracking!
              </div>
            ) : (
              <div style={{overflowX:"auto"}}>
                <table style={{width:"100%",borderCollapse:"collapse",fontSize:11}}>
                  <thead>
                    <tr style={{color:"#2a3050",borderBottom:"1px solid #151528"}}>
                      {["DATE","EXPIRY","SP/SC STRIKES","CREDIT","P&L","RETURN","REASON","DTE","MODE"].map(hd=>(
                        <th key={hd} style={{padding:"5px 9px",textAlign:"left",fontWeight:400,whiteSpace:"nowrap"}}>{hd}</th>
                      ))}
                    </tr>
                  </thead>
                  <tbody>
                    {[...tradeHistory].sort((a,b)=>new Date(b.enteredAt)-new Date(a.enteredAt)).map(t=>{
                      const pnl = t.pnl ?? null;
                      const ret = pnl != null && t.creditDollars ? Math.round(pnl/t.creditDollars*100) : null;
                      const pnlC = pnl == null ? "#4a5080" : pnl >= 0 ? "#34d399" : "#f87171";
                      return (
                        <tr key={t.id} style={{borderBottom:"1px solid #0d0d1a"}}>
                          <td style={{padding:"6px 9px",color:"#4a5080",whiteSpace:"nowrap"}}>
                            {new Date(t.enteredAt).toLocaleDateString()}
                          </td>
                          <td style={{padding:"6px 9px",color:"#22d3ee"}}>{t.expiry||"—"}</td>
                          <td style={{padding:"6px 9px",color:"#a78bfa",fontSize:10}}>
                            {t.shortPutStrike||"—"} / {t.shortCallStrike||"—"}
                          </td>
                          <td style={{padding:"6px 9px",color:"#f0c040"}}>
                            {t.creditDollars ? `$${fmt(t.creditDollars)}` : "—"}
                          </td>
                          <td style={{padding:"6px 9px",color:pnlC,fontWeight:700}}>
                            {pnl == null ? <span style={{color:"#22d3ee",fontSize:10}}>OPEN</span>
                                         : `${pnl>=0?"+":""}$${fmt(pnl)}`}
                          </td>
                          <td style={{padding:"6px 9px",color:pnlC}}>
                            {ret != null ? `${ret}%` : "—"}
                          </td>
                          <td style={{padding:"6px 9px",color:"#a78bfa",fontSize:10,whiteSpace:"nowrap"}}>
                            {t.closeReason||"—"}
                          </td>
                          <td style={{padding:"6px 9px",color:"#4a5080"}}>{t.dte||"—"}</td>
                          <td style={{padding:"6px 9px",fontSize:10}}>
                            <span style={{color:t.mode==="live"?"#f87171":"#34d399",
                              fontWeight:700}}>{(t.mode||"paper").toUpperCase()}</span>
                          </td>
                        </tr>
                      );
                    })}
                  </tbody>
                </table>
              </div>
            )}
          </div>
        )}

        {/* ── JOURNAL ── */}
        {tab==="journal" && (
          <div>
            <div style={{color:"#22d3ee",fontWeight:700,marginBottom:14,fontSize:13,letterSpacing:"0.05em"}}>
              STRATEGY JOURNAL
            </div>

            {!tradeStats || tradeStats.closed < 5 ? (
              <div style={{background:"#0d0d1f",border:"1px solid #151528",borderRadius:6,padding:20,
                color:"#4a5080",lineHeight:1.7}}>
                <div style={{color:"#f0c040",marginBottom:8}}>📊 Building data…</div>
                Need at least 5 closed trades to generate insights.
                {tradeStats && ` ${tradeStats.closed} / 5 trades completed.`}
                <div style={{marginTop:12,fontSize:10}}>
                  Every trade is recorded automatically. Come back after more trades for win rate analysis,
                  IV regime comparison, day-of-week breakdown, and personalized suggestions.
                </div>
              </div>
            ) : (
              <div>
                {/* IV Regime Analysis */}
                <div style={{background:"#0d0d1f",border:"1px solid #151528",borderRadius:6,padding:14,marginBottom:10}}>
                  <div style={{color:"#f0c040",fontWeight:700,marginBottom:10,fontSize:11}}>📊 IV REGIME PERFORMANCE</div>
                  <div style={{display:"grid",gridTemplateColumns:"1fr 1fr",gap:10}}>
                    {[["HIGH IV (VIXY>20)", tradeStats.highIV], ["NORMAL IV", tradeStats.normalIV]].map(([label, d])=>{
                      const wr = d.count > 0 ? d.wins/d.count : null;
                      return (
                        <div key={label} style={{background:"#07070f",borderRadius:5,padding:12}}>
                          <div style={{color:"#22d3ee",fontSize:10,marginBottom:8}}>{label}</div>
                          <div style={{display:"grid",gridTemplateColumns:"1fr 1fr",gap:6,fontSize:12}}>
                            <div>
                              <div style={{color:"#3a4060",fontSize:9,marginBottom:2}}>TRADES</div>
                              <div style={{color:"#dde1f0",fontWeight:700}}>{d.count}</div>
                            </div>
                            <div>
                              <div style={{color:"#3a4060",fontSize:9,marginBottom:2}}>WIN RATE</div>
                              <div style={{color:wr==null?"#4a5080":wr>=0.6?"#34d399":"#f87171",fontWeight:700}}>
                                {wr != null ? `${(wr*100).toFixed(0)}%` : "—"}
                              </div>
                            </div>
                            <div style={{gridColumn:"1/-1"}}>
                              <div style={{color:"#3a4060",fontSize:9,marginBottom:2}}>AVG P&L</div>
                              <div style={{color:d.avgPnl>=0?"#34d399":"#f87171",fontWeight:700}}>
                                {d.count > 0 ? `${d.avgPnl>=0?"+":""}$${fmt(d.avgPnl)}` : "—"}
                              </div>
                            </div>
                          </div>
                        </div>
                      );
                    })}
                  </div>
                </div>

                {/* Day of Week */}
                {Object.keys(tradeStats.byDay).length > 0 && (
                  <div style={{background:"#0d0d1f",border:"1px solid #151528",borderRadius:6,padding:14,marginBottom:10}}>
                    <div style={{color:"#f0c040",fontWeight:700,marginBottom:10,fontSize:11}}>📅 PERFORMANCE BY DAY</div>
                    <div style={{display:"grid",gridTemplateColumns:"repeat(4,1fr)",gap:8}}>
                      {["Mon","Tue","Wed","Thu"].map(day=>{
                        const d = tradeStats.byDay[day] || {wins:0,losses:0,pnl:0};
                        const total = d.wins + d.losses;
                        const wr = total ? d.wins / total : null;
                        return (
                          <div key={day} style={{background:"#07070f",borderRadius:5,padding:10}}>
                            <div style={{color:"#22d3ee",fontSize:10,marginBottom:6,fontWeight:700}}>{day.toUpperCase()}</div>
                            <div style={{color:"#dde1f0",fontSize:12}}>{total} trades</div>
                            <div style={{color:wr==null?"#4a5080":wr>=0.6?"#34d399":"#f87171",fontSize:12,fontWeight:700}}>
                              {wr != null ? `${(wr*100).toFixed(0)}% win` : "no data"}
                            </div>
                            <div style={{color:d.pnl>=0?"#34d399":"#f87171",fontSize:11}}>
                              {total > 0 ? `${d.pnl>=0?"+":""}$${fmt(d.pnl)}` : "—"}
                            </div>
                          </div>
                        );
                      })}
                    </div>
                  </div>
                )}

                {/* Insights */}
                <div style={{background:"#0a0f1a",border:"1px solid #22d3ee22",borderRadius:6,padding:14}}>
                  <div style={{color:"#22d3ee",fontWeight:700,marginBottom:10,fontSize:11}}>💡 INSIGHTS & RECOMMENDATIONS</div>
                  {generateInsights(tradeStats).map((insight, i)=>(
                    <div key={i} style={{padding:"8px 0",borderBottom:"1px solid #151528",
                      color:"#a0b0d0",fontSize:11,lineHeight:1.6}}>
                      {insight}
                    </div>
                  ))}
                </div>
              </div>
            )}
          </div>
        )}

        {/* ── RULES ── */}
        {tab==="rules" && (
          <div style={{fontSize:11,lineHeight:1.9}}>
            {[
              ["TICKER","SPY","Best ETF proxy for SPX condors. Deep liquidity, tight spreads."],
              ["DTE","1DTE","Maximizes overnight theta. Avoids 0DTE fill risk at EOD."],
              ["TRADING DAYS","Mon–Thu ONLY","No Friday entries = no weekend hold. Gap risk unacceptable for short premium."],
              ["SHORT DELTA","15–20Δ","~80-85% PoP. Optimal risk/reward per Tastylive & backtests."],
              ["WING WIDTH","$5","Defined max risk. Fast fills. Capital efficient for 1DTE."],
              ["SLEEP/WAKE","Single setTimeout to 3:45 PM","Zero polling all day. One wake event. No wasted API calls."],
              ["NEWS SCAN","3:45–3:50 PM","Finnhub calendar: FOMC, CPI, NFP, GDP, PCE, PPI, Fed speakers. Blocks entry if found."],
              ["ENTRY","3:50–3:58 PM","Late-day entry per Option Alpha 25k-trade study (37% avg return)."],
              ["PROFIT TARGET","45%/55% by IV","Auto-closes position + notifies. 55% in high-IV (VIXY>$20)."],
              ["STOP LOSS","1:1 credit","Auto-closes position + notifies. Alarm fires if auto-close fails."],
              ["ALERT AT","80% of stop","Early warning push + audio before stop hits."],
              ["HARD CLOSE","3:55 PM expiry day","Never hold through gamma explosion at close."],
              ["POSITION SIZE","1 IC per day","Max risk ~$500 per trade. Scale up as account grows."],
              ["TRADE LOG","Auto-recorded","Every trade written to trades.json — powers History & Journal tabs."],
            ].map(([r,v,w])=>(
              <div key={r} style={{background:"#0d0d1f",border:"1px solid #151528",borderRadius:5,
                padding:"9px 12px",marginBottom:6}}>
                <div style={{display:"flex",gap:10,marginBottom:3}}>
                  <span style={{color:"#22d3ee",fontWeight:700,minWidth:140}}>{r}</span>
                  <span style={{color:"#f0c040",fontWeight:700}}>{v}</span>
                </div>
                <div style={{color:"#4a5080",fontSize:10}}>{w}</div>
              </div>
            ))}
          </div>
        )}

        {/* ── SETTINGS ── */}
        {tab==="settings" && (
          <div style={{fontSize:12,maxWidth:520}}>
            <div style={{color:"#22d3ee",fontWeight:700,marginBottom:12,fontSize:13}}>SETTINGS</div>

            {[
              {title:"📰 Finnhub API Key",
               desc:"Free at finnhub.io. Used only during 3:45–3:50 PM news scan.",
               val:finnhubKey, set:setFinnhubKey, ph:"Paste Finnhub key",
               ok:finnhubKey&&finnhubKey!==FINNHUB_KEY_DEFAULT,
               okMsg:"✓ News scan enabled", failMsg:"⚠ No key — news scan skipped"},
              {title:"📱 ntfy.sh Notifications",
               desc:"Push alerts to your phone via ntfy.sh (topic: spy-gf-alert-trades). Toggle on/off.",
               val:ntfyEnabled?"enabled":"disabled", set:()=>setNtfyEnabled(!ntfyEnabled), ph:"",
               ok:ntfyEnabled, okMsg:"✓ Notifications ON — alerts sent to ntfy.sh", failMsg:"⚠ Notifications OFF"},
            ].map(({title,desc,val,set,ph,ok,okMsg,failMsg})=>(
              <div key={title} style={{background:"#0d0d1f",border:"1px solid #151528",
                borderRadius:6,padding:14,marginBottom:12}}>
                <div style={{color:"#f0c040",fontWeight:700,marginBottom:5}}>{title}</div>
                <div style={{color:"#4a5080",fontSize:10,marginBottom:8}}>{desc}</div>
                <input value={val} onChange={e=>set(e.target.value)} placeholder={ph}
                  style={{width:"100%",background:"#07070f",border:"1px solid #2a2a3e",color:"#f0f0f8",
                    padding:"8px 11px",borderRadius:5,fontFamily:"inherit",fontSize:11,boxSizing:"border-box"}}/>
                <div style={{color:ok?"#34d399":"#f87171",fontSize:10,marginTop:5}}>{ok?okMsg:failMsg}</div>
              </div>
            ))}

            {/* Server info */}
            <div style={{background:"#0a0f1a",border:"1px solid #22d3ee22",borderRadius:6,
              padding:12,fontSize:11,color:"#4a6080",marginBottom:12}}>
              <div style={{color:"#22d3ee",fontWeight:700,marginBottom:6}}>📡 Server</div>
              <div>Mode: <span style={{color:liveMode?"#f87171":"#34d399",fontWeight:700}}>
                {liveMode?"🔴 LIVE TRADING":"📄 Paper Trading"}
              </span></div>
              <div style={{marginTop:4,color:"#3a4060",fontSize:10}}>
                To switch modes, edit ALPACA_LIVE_MODE in .env and restart the server.
              </div>
              <div style={{marginTop:8}}>Proxy: <span style={{color:"#f0c040"}}>{window.location.origin}</span></div>
            </div>

            {/* Logout */}
            <button onClick={logout}
              style={{background:"#1a0f0f",color:"#f87171",border:"1px solid #7f1d1d",
                padding:"8px 18px",borderRadius:5,fontFamily:"inherit",fontSize:11,cursor:"pointer"}}>
              LOGOUT
            </button>
          </div>
        )}

        {/* ── LOG ── */}
        {tab==="log" && (
          <div style={{fontFamily:"monospace",fontSize:11}}>
            {logs.length===0&&<div style={{color:"#2a3050"}}>No activity yet.</div>}
            {logs.map((l,i)=>(
              <div key={i} style={{padding:"3px 0",borderBottom:"1px solid #0d0d1a",
                color:l.type==="error"?"#f87171":l.type==="success"?"#34d399":l.type==="warn"?"#f0c040":"#4a5080"}}>
                <span style={{color:"#1e2040",marginRight:10}}>{l.time}</span>{l.msg}
              </div>
            ))}
          </div>
        )}

      </div>
    </div>
  );
}

// ─── Mount ────────────────────────────────────────────────────────────────────
ReactDOM.createRoot(document.getElementById("root")).render(React.createElement(ICTerminal));
