const { useState, useEffect, useCallback } = React;

const API = "";
const mono = "'JetBrains Mono', monospace";
const disp = "'Space Grotesk', sans-serif";

async function api(path, opts = {}) {
  const token = localStorage.getItem("dkinvest_token");
  const headers = { "Content-Type": "application/json", ...(token ? { Authorization: `Bearer ${token}` } : {}) };
  const res = await fetch(`${API}${path}`, { ...opts, headers: { ...headers, ...opts.headers } });
  if (res.status === 401) { localStorage.removeItem("dkinvest_token"); window.location.reload(); }
  if (!res.ok) { const e = await res.json().catch(() => ({})); throw new Error(e.detail || res.statusText); }
  return res.json();
}
const get = (p) => api(p);
const post = (p, body) => api(p, { method: "POST", body: JSON.stringify(body) });

// ═══ TOOLTIP DESCRIPTIONS ════════════════════════════════════════════════════
const AGENT_TIPS = {
  framework_compliance: "Checks ROIC quality, capital allocation efficiency, and compliance with investment framework criteria (e.g. Greenblatt, quality/growth stock-type rules).",
  earnings_quality: "Piotroski F-Score (0-9), accrual ratio, cash flow vs earnings comparison, and Altman Z-score. Higher = more trustworthy earnings.",
  fundamental: "Valuation ratios (P/E, P/B, EV/EBITDA), profitability (ROE, margins), growth rates, and balance sheet health. Positive = undervalued.",
  technical: "RSI, MACD, price vs moving averages (SMA20/50/200), volume trends, and support/resistance levels. Positive = bullish momentum.",
  sentiment: "Analyst consensus rating (1-5 scale), target price upside, and number of covering analysts. More analysts = higher confidence.",
  volatility_structure: "30-day realized volatility percentile, volume profile analysis, and correlation with market index. Low vol = positive score.",
  peer_comparison: "Relative valuation and quality vs sector peers. Compares P/E, margins, growth, and ROIC against 5-10 comparable companies.",
  macro_economic: "Impact of interest rates, inflation, currency, and economic cycle on this stock's sector. Positive = macro tailwinds.",
  news_intelligence: "Sentiment analysis of recent news articles. Requires NewsAPI. Shows neutral (0.00) when no news is available.",
  annual_report: "RAG analysis of the company's annual report PDF. Requires ChromaDB and an uploaded PDF. Neutral until configured.",
  insider_trading: "Insider buy/sell transaction patterns. Cluster buying = very bullish. Neutral when no insider data is available.",
  dividend_return: "Dividend yield, payout sustainability, growth history, and coverage ratio. Zero for non-dividend stocks.",
  regime_detection: "Market-wide signal based on OMXC25/S&P500 trend and VIX volatility. Same score for all stocks. Positive = bull market.",
  macro_signal: "Macro regime overlay: rates environment, inflation momentum, liquidity conditions, and risk appetite indicators.",
  narrative_signal: "Exposure to active market narratives (e.g. AI, green energy, inflation). Based on news topic clustering.",
  market_map: "Position in the market correlation graph. Stocks in strong clusters with high centrality score higher.",
};

const METRIC_TIPS = {
  price: "Current market price from Yahoo Finance (last trading day close).",
  target: "Analyst consensus target price. Average of all covering analysts' 12-month price targets.",
  upside: "Percentage difference between current price and analyst target. Positive = analysts expect the stock to rise.",
  risk: "Risk assessment: low (stable, diversified), medium (normal volatility), high (volatile, concentrated, or in drawdown).",
  composite_score: "Weighted average of all 19 agent scores. Range: -1 (strong sell) to +1 (strong buy). Weights are adaptive based on past accuracy.",
  confidence: "How certain the system is about this recommendation. Low confidence means many agents had insufficient data or disagreed.",
};

// ═══ TOOLTIP COMPONENT ═══════════════════════════════════════════════════════
function Tip({ text, children }) {
  const [show, setShow] = useState(false);
  const [pos, setPos] = useState({ x: 0, y: 0 });
  const handleEnter = (e) => {
    const rect = e.currentTarget.getBoundingClientRect();
    setPos({ x: rect.left, y: rect.bottom + 4 });
    setShow(true);
  };
  return <span onMouseEnter={handleEnter} onMouseLeave={() => setShow(false)}
    style={{ cursor: "help", borderBottom: text ? "1px dotted #475569" : "none", position: "relative" }}>
    {children}
    {show && text && <span style={{
      position: "fixed", left: Math.min(pos.x, window.innerWidth - 320), top: pos.y,
      zIndex: 9999, maxWidth: 300, padding: "8px 10px", background: "#1e293b",
      border: "1px solid #334155", borderRadius: 6, color: "#e2e8f0",
      fontSize: 10, lineHeight: 1.5, fontFamily: "'Inter',sans-serif", fontWeight: 400,
      boxShadow: "0 4px 12px rgba(0,0,0,0.5)", pointerEvents: "none",
    }}>{text}</span>}
  </span>;
}

// ═══ SHARED COMPONENTS ═══════════════════════════════════════════════════════
function ScoreBar({ value }) {
  const w = Math.abs(value||0)*50, pos = (value||0) >= 0;
  return <div style={{display:"flex",alignItems:"center",gap:4,minWidth:90}}><div style={{width:56,height:4,background:"#1a1a2e",borderRadius:3,position:"relative"}}><div style={{position:"absolute",left:pos?"50%":`${50-w}%`,width:`${w}%`,height:"100%",background:pos?"#22c55e":"#ef4444",borderRadius:3}}/></div><span style={{fontSize:9,fontFamily:mono,color:pos?"#22c55e":"#ef4444",minWidth:32,textAlign:"right"}}>{pos?"+":""}{(value||0).toFixed(2)}</span></div>;
}
function Badge({ action }) {
  const c = {BUY:{bg:"#052e16",b:"#166534",t:"#22c55e"},HOLD:{bg:"#1c1917",b:"#44403c",t:"#a8a29e"},SELL:{bg:"#2d0a0a",b:"#7f1d1d",t:"#ef4444"}}[action]||{bg:"#1c1917",b:"#44403c",t:"#a8a29e"};
  return <span style={{padding:"2px 6px",borderRadius:3,background:c.bg,border:`1px solid ${c.b}`,color:c.t,fontSize:9,fontWeight:700,letterSpacing:1,fontFamily:mono}}>{action}</span>;
}
function Btn({ children, onClick, variant="default", disabled, style:s={} }) {
  const v = {default:{background:"#1e293b",color:"#94a3b8"},primary:{background:"#1d4ed8",color:"#e2e8f0"},danger:{background:"#7f1d1d",color:"#fca5a5"},success:{background:"#14532d",color:"#86efac"},ghost:{background:"transparent",color:"#64748b",border:"1px solid #1e293b"}}[variant];
  return <button onClick={onClick} disabled={disabled} style={{padding:"5px 12px",borderRadius:4,border:"none",cursor:disabled?"default":"pointer",fontSize:10,fontFamily:mono,fontWeight:600,opacity:disabled?0.5:1,...v,...s}}>{children}</button>;
}
function Loading() { return <div style={{padding:40,textAlign:"center",color:"#475569"}}>Loading...</div>; }
function Card({ title, tip, children, style:s={} }) {
  return <div style={{background:"#080c14",borderRadius:8,border:"1px solid #1e293b",padding:12,...s}}>
    {title&&<div style={{fontSize:11,fontWeight:600,fontFamily:disp,color:"#94a3b8",marginBottom:8}}>{tip?<Tip text={tip}>{title}</Tip>:title}</div>}
    {children}</div>;
}
function Metric({ label, value, color, sub, tip }) {
  return <Card><div style={{fontSize:9,color:"#64748b",marginBottom:4}}>{tip?<Tip text={tip}>{label}</Tip>:label}</div>
    <div style={{fontSize:20,fontWeight:700,fontFamily:mono,color:color||"#e2e8f0"}}>{value}</div>
    {sub&&<div style={{fontSize:9,fontFamily:mono,color:"#64748b"}}>{sub}</div>}</Card>;
}

// ═══ LOGIN ════════════════════════════════════════════════════════════════════
function LoginScreen({ onLogin }) {
  const [u,setU]=useState(""); const [p,setP]=useState(""); const [err,setErr]=useState("");
  const [isReg,setIsReg]=useState(false); const [dn,setDn]=useState("");
  const doAuth=async()=>{try{setErr(""); let data; if(isReg){data=await post("/api/auth/register",{username:u,password:p,display_name:dn||u});}
    else{const form=new URLSearchParams();form.append("username",u);form.append("password",p);
      const res=await fetch("/api/auth/login",{method:"POST",body:form});if(!res.ok)throw new Error("Invalid credentials");data=await res.json();}
    localStorage.setItem("dkinvest_token",data.access_token);onLogin(data.user);}catch(e){setErr(e.message);}};
  const is={width:"100%",padding:8,background:"#080c14",border:"1px solid #1e293b",borderRadius:5,color:"#e2e8f0",fontSize:11,fontFamily:mono,marginBottom:8};
  return <div style={{minHeight:"100vh",background:"#04060c",display:"flex",alignItems:"center",justifyContent:"center"}}>
    <div style={{width:320,padding:32,background:"#080c14",borderRadius:12,border:"1px solid #1e293b"}}>
      <h2 style={{fontSize:24,fontWeight:700,fontFamily:disp,color:"#e2e8f0",textAlign:"center",marginBottom:20}}>DKInvest</h2>
      {isReg&&<input value={dn} onChange={e=>setDn(e.target.value)} placeholder="Display name" style={is}/>}
      <input value={u} onChange={e=>setU(e.target.value)} placeholder="Username" style={is} onKeyDown={e=>e.key==="Enter"&&doAuth()}/>
      <input value={p} onChange={e=>setP(e.target.value)} placeholder="Password" type="password" style={is} onKeyDown={e=>e.key==="Enter"&&doAuth()}/>
      {err&&<div style={{color:"#ef4444",fontSize:10,marginBottom:8}}>{err}</div>}
      <Btn onClick={doAuth} variant="primary" style={{width:"100%",padding:10,marginBottom:8}}>{isReg?"Register":"Sign In"}</Btn>
      <div style={{textAlign:"center"}}><span onClick={()=>setIsReg(!isReg)} style={{fontSize:10,color:"#818cf8",cursor:"pointer"}}>{isReg?"Already have an account?":"Create account"}</span></div>
    </div></div>;
}

// ═══ HOME ═════════════════════════════════════════════════════════════════════
function HomeTab({ recs }) {
  const buys=(recs||[]).filter(r=>r.action==="BUY").length;
  const sells=(recs||[]).filter(r=>r.action==="SELL").length;
  const holds=(recs||[]).filter(r=>r.action==="HOLD").length;
  const top=(recs||[]).sort((a,b)=>(b.composite_score||0)-(a.composite_score||0)).slice(0,5);
  return <div style={{padding:"16px 24px"}}>
    <div style={{display:"grid",gridTemplateColumns:"repeat(4,1fr)",gap:10,marginBottom:16}}>
      <Metric label="Total Stocks" value={(recs||[]).length} color="#818cf8" tip="Number of stocks in your watchlist being tracked by DKInvest."/>
      <Metric label="BUY Signals" value={buys} color="#22c55e" tip="Stocks where the weighted agent consensus recommends buying. Composite score > +0.15 with sufficient confidence."/>
      <Metric label="SELL Signals" value={sells} color="#ef4444" tip="Stocks where agents recommend selling or reducing position. Composite score < -0.15."/>
      <Metric label="HOLD" value={holds} color="#a8a29e" tip="Stocks with neutral outlook or insufficient confidence for a directional call."/></div>
    <Card title="Top Opportunities" tip="Stocks ranked by composite score (weighted average of all 19 agent signals). Higher = stronger buy conviction.">
      {top.map(r=><div key={r.ticker} style={{display:"flex",justifyContent:"space-between",alignItems:"center",padding:"6px 0",borderBottom:"1px solid #0f172a"}}>
        <div style={{display:"flex",alignItems:"center",gap:8}}><Badge action={r.action}/>
          <span style={{fontSize:12,fontWeight:600,color:"#e2e8f0"}}>{r.ticker}</span>
          <span style={{fontSize:10,color:"#64748b"}}>{r.company_name}</span></div>
        <ScoreBar value={r.composite_score}/></div>)}
    </Card></div>;
}

// ═══ STOCKS ═══════════════════════════════════════════════════════════════════
function StocksTab({ recs, onRefresh, onAddStock }) {
  const [expanded,setExpanded]=useState(null); const [detail,setDetail]=useState(null);
  const [ticker,setTicker]=useState(""); const [adding,setAdding]=useState(false);
  const doAdd=async()=>{if(!ticker)return; setAdding(true); try{await onAddStock({ticker:ticker.toUpperCase()});setTicker("");}catch(e){}setAdding(false);};
  const loadDetail=async(t)=>{if(expanded===t){setExpanded(null);return;} setExpanded(t); setDetail(null);
    try{const thesis=await get(`/api/stocks/${t}/thesis`).catch(()=>null); setDetail({thesis,rec:(recs||[]).find(r=>r.ticker===t)});}catch(e){setDetail(null);}};
  return <div style={{padding:"16px 24px"}}>
    <div style={{display:"flex",justifyContent:"space-between",alignItems:"center",marginBottom:12}}>
      <div style={{fontSize:13,fontWeight:600,fontFamily:disp,color:"#e2e8f0"}}>Stock Analysis</div>
      <div style={{display:"flex",gap:6}}>
        <input value={ticker} onChange={e=>setTicker(e.target.value)} placeholder="Add ticker..." style={{width:110,padding:5,background:"#04060c",border:"1px solid #1e293b",borderRadius:4,color:"#e2e8f0",fontSize:10,fontFamily:mono}} onKeyDown={e=>e.key==="Enter"&&doAdd()}/>
        <Btn onClick={doAdd} variant="primary" disabled={adding}>{adding?"Adding...":"+ Add"}</Btn>
        <Btn onClick={onRefresh} variant="ghost">Refresh</Btn></div></div>
    {(recs||[]).map(r=><div key={r.ticker} style={{background:"#080c14",borderRadius:8,border:"1px solid #1e293b",padding:12,marginBottom:8}}>
      <div style={{display:"flex",justifyContent:"space-between",alignItems:"center",cursor:"pointer"}} onClick={()=>loadDetail(r.ticker)}>
        <div style={{display:"flex",alignItems:"center",gap:10}}><Badge action={r.action}/>
          <span style={{fontSize:13,fontWeight:600,color:"#e2e8f0"}}>{r.ticker}</span>
          <span style={{fontSize:10,color:"#64748b"}}>{r.company_name}</span></div>
        <div style={{display:"flex",alignItems:"center",gap:12}}>
          <Tip text={METRIC_TIPS.composite_score}><ScoreBar value={r.composite_score}/></Tip>
          <Tip text={METRIC_TIPS.confidence}><span style={{fontSize:10,fontFamily:mono,color:"#64748b"}}>conf:{((r.confidence||0)*100).toFixed(0)}%</span></Tip>
          <span style={{fontSize:10,color:"#475569"}}>{expanded===r.ticker?"\u25B2":"\u25BC"}</span></div></div>
      {expanded===r.ticker&&<div style={{marginTop:10,borderTop:"1px solid #1e293b",paddingTop:10}}>
        {r.agents&&Object.keys(r.agents).length>0&&<div style={{marginBottom:12}}>
          <div style={{fontSize:9,color:"#818cf8",fontWeight:700,marginBottom:6}}>
            <Tip text="Each agent analyzes the stock from a different angle. Scores range from -1 (very bearish) to +1 (very bullish). Hover over agent names for details.">AGENT SCORES</Tip></div>
          <div style={{display:"grid",gridTemplateColumns:"repeat(auto-fill,minmax(200px,1fr))",gap:4}}>
            {Object.entries(r.agents).sort((a,b)=>Math.abs(b[1])-Math.abs(a[1])).map(([name,score])=>
              <div key={name} style={{display:"flex",justifyContent:"space-between",alignItems:"center",padding:"3px 6px",background:"#04060c",borderRadius:4}}>
                <Tip text={AGENT_TIPS[name]||`${name.replace(/_/g," ")} agent signal. Score: ${score>=0?"+":""}${score.toFixed(2)}`}>
                  <span style={{fontSize:9,color:"#94a3b8"}}>{name.replace(/_/g," ")}</span></Tip>
                <ScoreBar value={score}/></div>)}</div></div>}
        <div style={{display:"grid",gridTemplateColumns:"repeat(4,1fr)",gap:8,marginBottom:12}}>
          {r.current_price&&<div style={{padding:"4px 8px",background:"#04060c",borderRadius:4}}>
            <div style={{fontSize:8,color:"#64748b"}}><Tip text={METRIC_TIPS.price}>Price</Tip></div>
            <div style={{fontSize:12,fontFamily:mono,color:"#e2e8f0"}}>{r.current_price?.toFixed(2)}</div></div>}
          {r.target_price&&<div style={{padding:"4px 8px",background:"#04060c",borderRadius:4}}>
            <div style={{fontSize:8,color:"#64748b"}}><Tip text={METRIC_TIPS.target}>Target</Tip></div>
            <div style={{fontSize:12,fontFamily:mono,color:"#818cf8"}}>{r.target_price?.toFixed(2)}</div></div>}
          {r.upside_pct!=null&&<div style={{padding:"4px 8px",background:"#04060c",borderRadius:4}}>
            <div style={{fontSize:8,color:"#64748b"}}><Tip text={METRIC_TIPS.upside}>Upside</Tip></div>
            <div style={{fontSize:12,fontFamily:mono,color:(r.upside_pct||0)>0?"#22c55e":"#ef4444"}}>{(r.upside_pct||0)>0?"+":""}{r.upside_pct?.toFixed(1)}%</div></div>}
          {r.risk_level&&<div style={{padding:"4px 8px",background:"#04060c",borderRadius:4}}>
            <div style={{fontSize:8,color:"#64748b"}}><Tip text={METRIC_TIPS.risk}>Risk</Tip></div>
            <div style={{fontSize:12,fontFamily:mono,color:{low:"#22c55e",medium:"#eab308",high:"#ef4444"}[r.risk_level]||"#94a3b8"}}>{r.risk_level}</div></div>}</div>
        {detail?.thesis?.available&&<div style={{marginBottom:10}}>
          <div style={{display:"grid",gridTemplateColumns:"1fr 1fr",gap:12}}>
            <div><div style={{fontSize:9,color:"#22c55e",fontWeight:700,marginBottom:4}}><Tip text="AI-generated analysis of why this stock could outperform. Based on fundamentals, technicals, and market positioning.">BULL CASE</Tip></div><div style={{fontSize:10,color:"#94a3b8",lineHeight:1.5}}>{detail.thesis.bull_case}</div></div>
            <div><div style={{fontSize:9,color:"#ef4444",fontWeight:700,marginBottom:4}}><Tip text="AI-generated analysis of key risks and why this stock could underperform. Considers valuation, macro headwinds, and sector risks.">BEAR CASE</Tip></div><div style={{fontSize:10,color:"#94a3b8",lineHeight:1.5}}>{detail.thesis.bear_case}</div></div></div>
          {detail.thesis.catalysts?.length>0&&<div style={{marginTop:8}}><div style={{fontSize:9,color:"#818cf8",fontWeight:700,marginBottom:3}}><Tip text="Specific upcoming events or developments that could move the stock price significantly.">CATALYSTS</Tip></div>{detail.thesis.catalysts.map((c,i)=><span key={i} style={{fontSize:9,color:"#94a3b8",display:"inline-block",background:"#1e1b4b",padding:"2px 6px",borderRadius:3,margin:"0 4px 3px 0"}}>{c}</span>)}</div>}
          {detail.thesis.risk_factors?.length>0&&<div style={{marginTop:6}}><div style={{fontSize:9,color:"#f59e0b",fontWeight:700,marginBottom:3}}><Tip text="Key risk factors that could negatively impact the investment thesis.">RISKS</Tip></div>{detail.thesis.risk_factors.map((rf,i)=><span key={i} style={{fontSize:9,color:"#94a3b8",display:"inline-block",background:"#1c1917",padding:"2px 6px",borderRadius:3,margin:"0 4px 3px 0"}}>{rf}</span>)}</div>}</div>}
        {r.reasoning_summary&&<div style={{padding:8,background:"#04060c",borderRadius:4}}><div style={{fontSize:9,color:"#64748b",fontWeight:700,marginBottom:3}}><Tip text="AI-generated summary combining all agent signals, risk assessment, and market context into a final investment view.">REASONING</Tip></div><div style={{fontSize:10,color:"#94a3b8",lineHeight:1.5}}>{r.reasoning_summary}</div></div>}
      </div>}</div>)}
    {(!recs||recs.length===0)&&<div style={{padding:40,textAlign:"center",color:"#475569"}}>No recommendations yet.</div>}</div>;
}

// ═══ PORTFOLIO ════════════════════════════════════════════════════════════════
function PortfolioTab() {
  const [pf,setPf]=useState(null); const [loading,setLoading]=useState(true);
  const [t,setT]=useState(""); const [sh,setSh]=useState(""); const [pr,setPr]=useState("");
  useEffect(()=>{(async()=>{try{setPf(await get("/api/portfolio"));}catch(e){}setLoading(false);})();},[]);
  const buy=async()=>{if(!t||!sh||!pr)return; await post("/api/portfolio/transaction",{ticker:t.toUpperCase(),transaction_type:"BUY",shares:+sh,price_per_share:+pr,transaction_date:new Date().toISOString().split("T")[0]});setPf(await get("/api/portfolio"));setT("");setSh("");setPr("");};
  if(loading)return <Loading/>;
  const h=pf?.holdings||[]; const tv=h.reduce((s,x)=>s+(x.current_value||0),0); const tc=h.reduce((s,x)=>s+(x.total_invested||0),0); const tp=tv-tc;
  return <div style={{padding:"16px 24px"}}>
    <div style={{display:"grid",gridTemplateColumns:"repeat(3,1fr)",gap:10,marginBottom:16}}>
      <Metric label="Portfolio Value" value={`${tv.toLocaleString(undefined,{minimumFractionDigits:0})}`} color="#e2e8f0" tip="Total current market value of all your holdings."/>
      <Metric label="Total P&L" value={`${tp>=0?"+":""}${tp.toLocaleString(undefined,{minimumFractionDigits:0})}`} color={tp>=0?"#22c55e":"#ef4444"} sub={tc>0?`${((tp/tc)*100).toFixed(1)}%`:""} tip="Profit or loss: current value minus total amount invested."/>
      <Metric label="Holdings" value={h.length} color="#818cf8" tip="Number of different stocks you currently hold."/></div>
    {h.map(x=><div key={x.ticker} style={{display:"flex",justifyContent:"space-between",padding:"8px 0",borderBottom:"1px solid #0f172a"}}>
      <div><span style={{fontSize:12,fontWeight:600,color:"#e2e8f0"}}>{x.ticker}</span> <span style={{fontSize:10,color:"#64748b"}}>{x.shares} @ {x.avg_purchase_price?.toFixed(2)}</span></div>
      <div style={{textAlign:"right"}}><div style={{fontSize:11,fontFamily:mono,color:"#e2e8f0"}}>{x.current_value?.toLocaleString()}</div>
        <div style={{fontSize:9,fontFamily:mono,color:(x.pnl_pct||0)>=0?"#22c55e":"#ef4444"}}>{(x.pnl_pct||0)>=0?"+":""}{x.pnl_pct?.toFixed(1)}%</div></div></div>)}
    <Card title="Record Purchase" style={{marginTop:16}}><div style={{display:"flex",gap:6}}>
      <input value={t} onChange={e=>setT(e.target.value)} placeholder="Ticker" style={{flex:1,padding:6,background:"#04060c",border:"1px solid #1e293b",borderRadius:4,color:"#e2e8f0",fontSize:10,fontFamily:mono}}/>
      <input value={sh} onChange={e=>setSh(e.target.value)} placeholder="Shares" type="number" style={{width:70,padding:6,background:"#04060c",border:"1px solid #1e293b",borderRadius:4,color:"#e2e8f0",fontSize:10,fontFamily:mono}}/>
      <input value={pr} onChange={e=>setPr(e.target.value)} placeholder="Price" type="number" style={{width:80,padding:6,background:"#04060c",border:"1px solid #1e293b",borderRadius:4,color:"#e2e8f0",fontSize:10,fontFamily:mono}}/>
      <Btn onClick={buy} variant="success">Buy</Btn></div></Card></div>;
}

// ═══ MARKET INSIGHTS ═════════════════════════════════════════════════════════
function MarketInsightsTab() {
  const [macro,setMacro]=useState(null); const [narr,setNarr]=useState(null); const [mmap,setMmap]=useState(null); const [loading,setLoading]=useState(true);
  useEffect(()=>{(async()=>{const[m,n,mm]=await Promise.all([get("/api/macro/environment").catch(()=>null),get("/api/narratives/overview").catch(()=>null),get("/api/market-map/snapshot").catch(()=>null)]); setMacro(m);setNarr(n);setMmap(mm);setLoading(false);})();},[]);
  if(loading)return <Loading/>;
  const rc={inflationary_expansion:"#f97316",disinflationary_growth:"#22c55e",stagflation:"#ef4444",deflationary_recession:"#64748b"};
  const mr=macro?.regime?.regime||"unknown";
  return <div style={{padding:"16px 24px"}}>
    <div style={{fontSize:14,fontWeight:600,fontFamily:disp,color:"#e2e8f0",marginBottom:12}}>Market Insights</div>
    <div style={{display:"grid",gridTemplateColumns:"1fr 1fr",gap:12,marginBottom:16}}>
      <Card title="Macro Regime" tip="Current macroeconomic environment classification based on yield curves, inflation data, commodity prices, and cross-asset signals.">
        <div style={{display:"flex",alignItems:"center",gap:8,marginBottom:6}}>
        <div style={{width:10,height:10,borderRadius:"50%",background:rc[mr]||"#64748b"}}/>
        <span style={{fontSize:16,fontWeight:700,fontFamily:mono,color:rc[mr]||"#94a3b8"}}>{mr.replace(/_/g," ").toUpperCase()}</span></div>
        {macro?.regime?.strategy_hints?.description&&<div style={{fontSize:10,color:"#94a3b8",lineHeight:1.4}}>{macro.regime.strategy_hints.description}</div>}</Card>
      <Card title="Macro Features" tip="Individual macro indicators derived from bond yields, commodities, currencies, and equity indices. Updated daily.">
        {macro?.features&&Object.entries(macro.features).slice(0,6).map(([k,v])=><div key={k} style={{display:"flex",justifyContent:"space-between",padding:"3px 0",borderBottom:"1px solid #0f172a"}}>
        <span style={{fontSize:10,color:"#94a3b8"}}>{k.replace(/_/g," ")}</span>
        <span style={{fontSize:10,fontFamily:mono,color:v>0?"#22c55e":v<0?"#ef4444":"#64748b"}}>{typeof v==="number"?v.toFixed(3):v}</span></div>)}</Card></div>
    {(narr?.top_narratives||[]).length>0&&<><div style={{fontSize:12,fontWeight:600,fontFamily:disp,color:"#e2e8f0",marginBottom:8}}><Tip text="Market narratives extracted from news clustering. Each narrative represents a theme driving market attention (e.g. AI, interest rates, trade tensions).">Narratives</Tip></div>
    <div style={{display:"grid",gridTemplateColumns:"repeat(auto-fill,minmax(220px,1fr))",gap:10,marginBottom:16}}>
      {narr.top_narratives.map((n,i)=><Card key={i}><div style={{fontSize:11,fontWeight:600,color:"#e2e8f0",marginBottom:4}}>{n.name}</div>
        <div style={{display:"flex",gap:12}}>
          <div><Tip text="How dominant this narrative is in current news flow. Higher = more media attention."><span style={{fontSize:8,color:"#64748b"}}>Intensity</span></Tip><div style={{fontSize:12,fontFamily:mono,color:"#818cf8"}}>{(n.intensity||0).toFixed(2)}</div></div>
          <div><Tip text="Average sentiment of articles about this narrative. Positive = optimistic coverage, negative = fearful/bearish."><span style={{fontSize:8,color:"#64748b"}}>Sentiment</span></Tip><div style={{fontSize:12,fontFamily:mono,color:(n.sentiment||0)>0?"#22c55e":"#ef4444"}}>{(n.sentiment||0)>0?"+":""}{(n.sentiment||0).toFixed(2)}</div></div></div></Card>)}</div></>}
    </div>;
}

// ═══ ALERTS ═══════════════════════════════════════════════════════════════════
function AlertsTab() {
  const [alerts,setAlerts]=useState(null); const [loading,setLoading]=useState(true);
  useEffect(()=>{(async()=>{try{setAlerts(await get("/api/alerts?limit=50"));}catch(e){}setLoading(false);})();},[]);
  if(loading)return <Loading/>;
  return <div style={{padding:"16px 24px"}}>
    <div style={{fontSize:13,fontWeight:600,fontFamily:disp,color:"#e2e8f0",marginBottom:12}}>Alerts</div>
    {(alerts?.alerts||[]).map(a=><div key={a.id} style={{padding:"8px 0",borderBottom:"1px solid #0f172a",opacity:a.is_read?0.5:1}}>
      <div style={{display:"flex",justifyContent:"space-between"}}>
        <span style={{fontSize:11,fontWeight:a.is_read?400:600,color:"#e2e8f0"}}>{a.title}</span>
        <span style={{fontSize:9,fontFamily:mono,color:"#475569"}}>{new Date(a.created_at).toLocaleDateString()}</span></div>
      <div style={{fontSize:10,color:"#94a3b8",marginTop:2}}>{a.message}</div></div>)}
    {(alerts?.alerts||[]).length===0&&<div style={{padding:40,textAlign:"center",color:"#475569"}}>No alerts.</div>}</div>;
}

// ═══ DISCOVERY ════════════════════════════════════════════════════════════════
function DiscoveryTab() {
  const [data,setData]=useState(null); const [loading,setLoading]=useState(true); const [running,setRunning]=useState(false);
  useEffect(()=>{(async()=>{try{setData(await get("/api/discovery"));}catch(e){}setLoading(false);})();},[]);
  const runDisc=async()=>{setRunning(true);try{await post("/api/discovery/run",{});setTimeout(async()=>{try{setData(await get("/api/discovery"));}catch(e){}setRunning(false);},30000);}catch(e){setRunning(false);}};
  const dismiss=async(t)=>{try{await post("/api/discovery/dismiss",{ticker:t});setData(await get("/api/discovery"));}catch(e){}};
  const addWL=async(t,n)=>{try{await post("/api/watchlist/add",{ticker:t,company_name:n});setData(await get("/api/discovery"));}catch(e){}};
  if(loading)return <Loading/>;
  const report=data?.report; const cands=(report?.investigate||report?.candidates||[]);
  const dism=new Set(data?.dismissed_tickers||[]); const tracked=new Set(data?.tracked_tickers||[]);
  const vis=cands.filter(c=>!dism.has(c.ticker)&&!tracked.has(c.ticker));
  return <div style={{padding:"16px 24px"}}>
    <div style={{display:"flex",justifyContent:"space-between",alignItems:"center",marginBottom:16}}>
      <div><div style={{fontSize:14,fontWeight:600,fontFamily:disp,color:"#e2e8f0"}}>Stock Discovery</div>
        <div style={{fontSize:10,color:"#64748b"}}>Find new investment candidates</div></div>
      <Btn onClick={runDisc} variant="primary" disabled={running}>{running?"\u23F3 Scanning...":"\uD83D\uDD0D Run Discovery"}</Btn></div>
    {report&&<div style={{display:"grid",gridTemplateColumns:"repeat(3,1fr)",gap:10,marginBottom:16}}>
      <Metric label="Candidates" value={cands.length} color="#818cf8" tip="Total stocks found by the discovery scan that match investment criteria."/>
      <Metric label="Tracked" value={tracked.size} color="#22c55e" tip="Stocks already in your watchlist."/>
      <Metric label="Dismissed" value={dism.size} color="#64748b" tip="Stocks you dismissed. They won't appear again for 90 days."/></div>}
    {vis.length>0?vis.map(c=><div key={c.ticker} style={{background:"#080c14",borderRadius:8,border:"1px solid #1e293b",padding:12,marginBottom:8}}>
      <div style={{display:"flex",justifyContent:"space-between",alignItems:"center"}}>
        <div><span style={{fontSize:13,fontWeight:600,color:"#e2e8f0"}}>{c.ticker}</span>
          <span style={{fontSize:10,color:"#64748b",marginLeft:8}}>{c.company_name||c.name||""}</span>
          {c.sector&&<span style={{fontSize:8,background:"#1e1b4b",color:"#818cf8",padding:"1px 5px",borderRadius:3,marginLeft:6}}>{c.sector}</span>}</div>
        <div style={{display:"flex",gap:6}}><Btn onClick={()=>addWL(c.ticker,c.company_name||c.name)} variant="success">+ Add</Btn>
          <Btn onClick={()=>dismiss(c.ticker)} variant="ghost">Dismiss</Btn></div></div>
      {c.reason&&<div style={{fontSize:10,color:"#94a3b8",marginTop:4}}>{c.reason}</div>}
    </div>):<div style={{padding:40,textAlign:"center",color:"#475569"}}>{report?"All candidates tracked or dismissed.":"No discovery report. Click Run Discovery."}</div>}</div>;
}

// ═══ SIMULATION ═══════════════════════════════════════════════════════════════
function SimulationTab() {
  const [simDate,setSimDate]=useState("2024-06-01"); const [simTicker,setSimTicker]=useState("NOVO-B.CO");
  const [results,setResults]=useState(null); const [history,setHistory]=useState(null);
  const [running,setRunning]=useState(false); const [loading,setLoading]=useState(true);
  useEffect(()=>{(async()=>{try{setHistory(await get("/api/simulation/results"));}catch(e){}setLoading(false);})();},[]);
  const runSim=async()=>{setRunning(true);
    try{const resp=await post("/api/simulation/run",{date:simDate,ticker:simTicker}); const jid=resp.job_id;
      const poll=async(n)=>{if(n<=0){setRunning(false);return;}
        try{const j=await get(`/api/jobs/${jid}`);
          if(j.status==="completed"){setResults(j.result);setHistory(await get("/api/simulation/results"));setRunning(false);}
          else if(j.status==="failed"){setRunning(false);}
          else{setTimeout(()=>poll(n-1),3000);}
        }catch(e){setTimeout(()=>poll(n-1),3000);}};
      setTimeout(()=>poll(40),3000);
    }catch(e){setRunning(false);}};
  return <div style={{padding:"16px 24px"}}>
    <div style={{fontSize:14,fontWeight:600,fontFamily:disp,color:"#e2e8f0",marginBottom:4}}>Point-in-Time Simulation</div>
    <div style={{fontSize:10,color:"#64748b",marginBottom:16}}>Test what the system would have recommended on a past date and see how it performed</div>
    <Card title="Run Simulation" tip="Runs all agents using only data available up to the selected date. No lookahead bias. Then measures actual forward returns." style={{marginBottom:16}}>
      <div style={{display:"flex",gap:8,alignItems:"flex-end",flexWrap:"wrap"}}>
        <div><div style={{fontSize:9,color:"#64748b",marginBottom:3}}>Date</div>
          <input type="date" value={simDate} onChange={e=>setSimDate(e.target.value)} style={{padding:6,background:"#04060c",border:"1px solid #1e293b",borderRadius:4,color:"#e2e8f0",fontSize:10,fontFamily:mono}}/></div>
        <div><div style={{fontSize:9,color:"#64748b",marginBottom:3}}>Ticker</div>
          <input value={simTicker} onChange={e=>setSimTicker(e.target.value)} style={{width:120,padding:6,background:"#04060c",border:"1px solid #1e293b",borderRadius:4,color:"#e2e8f0",fontSize:10,fontFamily:mono}}/></div>
        <Btn onClick={runSim} variant="primary" disabled={running}>{running?"\u23F3 Simulating...":"\u25B6 Run"}</Btn></div></Card>
    {results?.results&&<Card title="Results" style={{marginBottom:16}}>
      {results.results.map((r,i)=><div key={i} style={{padding:"10px 0",borderBottom:"1px solid #0f172a"}}>
        <div style={{display:"flex",justifyContent:"space-between",alignItems:"center",marginBottom:6}}>
          <div style={{display:"flex",alignItems:"center",gap:8}}><Badge action={r.recommendation}/>
            <span style={{fontSize:13,fontWeight:600,color:"#e2e8f0"}}>{r.ticker}</span>
            <span style={{fontSize:10,color:"#64748b"}}>{r.simulation_date}</span></div>
          <span style={{fontSize:10,fontFamily:mono,color:"#e2e8f0"}}>Score: {r.score>=0?"+":""}{r.score?.toFixed(2)}</span></div>
        {r.forward_performance?.available&&<div style={{display:"grid",gridTemplateColumns:"repeat(5,1fr)",gap:6}}>
          {["7d","30d","90d"].map(p=>{const v=r.forward_performance[p+"_return"]; return v!=null?<div key={p} style={{padding:"4px 8px",background:"#04060c",borderRadius:4,textAlign:"center"}}>
            <div style={{fontSize:8,color:"#64748b"}}><Tip text={`Actual stock return ${p} after the simulation date.`}>{p}</Tip></div>
            <div style={{fontSize:12,fontFamily:mono,fontWeight:700,color:v>=0?"#22c55e":"#ef4444"}}>{v>=0?"+":""}{v}%</div></div>:null;})}
          {r.forward_performance.max_drawdown!=null&&<div style={{padding:"4px 8px",background:"#04060c",borderRadius:4,textAlign:"center"}}><div style={{fontSize:8,color:"#64748b"}}><Tip text="Maximum peak-to-trough decline in the forward period. Measures worst-case drawdown risk.">Max DD</Tip></div><div style={{fontSize:12,fontFamily:mono,color:"#ef4444"}}>{r.forward_performance.max_drawdown}%</div></div>}
          {r.forward_performance.correct_direction!=null&&<div style={{padding:"4px 8px",background:"#04060c",borderRadius:4,textAlign:"center"}}><div style={{fontSize:8,color:"#64748b"}}><Tip text="Did the recommendation match the actual outcome? BUY is correct if stock went up, SELL if it went down.">Correct?</Tip></div><div style={{fontSize:14}}>{r.forward_performance.correct_direction?"\u2705":"\u274C"}</div></div>}
        </div>}</div>)}</Card>}
    <Card title="Past Simulations" tip="History of all simulations you have run. Shows the recommendation, forward returns, and whether the direction was correct.">
      {(history?.results||[]).length>0?(history.results||[]).slice(0,10).map((r,i)=><div key={i} style={{display:"flex",justifyContent:"space-between",padding:"6px 0",borderBottom:"1px solid #0f172a"}}>
        <div style={{display:"flex",alignItems:"center",gap:6}}><Badge action={r.recommendation}/>
          <span style={{fontSize:11,color:"#e2e8f0"}}>{r.ticker}</span>
          <span style={{fontSize:9,color:"#64748b"}}>{r.simulation_date}</span></div>
        <div style={{display:"flex",gap:8}}>
          {r.forward_performance?.["30d_return"]!=null&&<span style={{fontSize:10,fontFamily:mono,color:(r.forward_performance["30d_return"]||0)>=0?"#22c55e":"#ef4444"}}>30d: {r.forward_performance["30d_return"]>=0?"+":""}{r.forward_performance["30d_return"]}%</span>}
          {r.forward_performance?.correct_direction!=null&&<span>{r.forward_performance.correct_direction?"\u2705":"\u274C"}</span>}</div>
      </div>):<div style={{padding:20,textAlign:"center",color:"#475569"}}>No simulations yet.</div>}</Card></div>;
}

// ═══ RESEARCH LAB ═════════════════════════════════════════════════════════════
function ResearchLabTab() {
  const [ml,setMl]=useState(null); const [perf,setPerf]=useState(null); const [weights,setWeights]=useState(null); const [running,setRunning]=useState({});
  useEffect(()=>{(async()=>{const[m,p,w]=await Promise.all([get("/api/ml/status").catch(()=>null),get("/api/performance").catch(()=>null),get("/api/ml/agent-weights").catch(()=>null)]);setMl(m);setPerf(p);setWeights(w);})();},[]);
  const run=async(id,ep)=>{setRunning(r=>({...r,[id]:true}));try{await post(ep,{});}catch(e){}setTimeout(()=>setRunning(r=>({...r,[id]:false})),3000);};
  const acts=[{id:"retrain",label:"Retrain ML",endpoint:"/api/ml/retrain",icon:"\uD83E\uDDE0"},{id:"learn",label:"Learning Cycle",endpoint:"/api/ml/run-learning",icon:"\uD83D\uDCCA"},{id:"research",label:"Research Pipeline",endpoint:"/api/research/run",icon:"\uD83E\uDDEA"},
    {id:"narratives",label:"Refresh Narratives",endpoint:"/api/narratives/refresh",icon:"\uD83D\uDCF0"},{id:"mmap",label:"Market Map",endpoint:"/api/market-map/refresh",icon:"\uD83D\uDDFA\uFE0F"},{id:"macro",label:"Update Macro",endpoint:"/api/macro/update",icon:"\uD83C\uDF0D"}];
  return <div style={{padding:"16px 24px"}}>
    <div style={{display:"flex",alignItems:"center",gap:8,marginBottom:16}}>
      <span style={{fontSize:14,fontWeight:600,fontFamily:disp,color:"#e2e8f0"}}>Research Lab</span>
      <span style={{fontSize:8,background:"#7f1d1d",color:"#fca5a5",padding:"2px 6px",borderRadius:3,fontFamily:mono}}>ADMIN</span></div>
    <Card title="Actions" style={{marginBottom:16}}><div style={{display:"grid",gridTemplateColumns:"repeat(3,1fr)",gap:8}}>
      {acts.map(a=><Btn key={a.id} onClick={()=>run(a.id,a.endpoint)} variant="primary" disabled={running[a.id]} style={{padding:10,display:"flex",flexDirection:"column",alignItems:"center",gap:3}}>
        <span style={{fontSize:16}}>{a.icon}</span><span style={{fontSize:9}}>{running[a.id]?"Running...":a.label}</span></Btn>)}</div></Card>
    <div style={{display:"grid",gridTemplateColumns:"1fr 1fr",gap:12}}>
      <Card title="ML Model" tip="LightGBM predictive model trained on historical recommendation outcomes. Needs 30+ evaluated outcomes before training.">
        <div style={{display:"flex",alignItems:"center",gap:6}}>
        <div style={{width:8,height:8,borderRadius:"50%",background:ml?.trained?"#22c55e":"#ef4444"}}/>
        <span style={{fontSize:12,fontWeight:600,color:ml?.trained?"#22c55e":"#ef4444"}}>{ml?.trained?"TRAINED":"NOT TRAINED"}</span></div></Card>
      {perf&&perf.evaluated>0&&<Card title="Signal Accuracy" tip="How often past recommendations were correct. Evaluated after 30 days by comparing predicted direction vs actual price movement.">
        <div style={{display:"grid",gridTemplateColumns:"repeat(3,1fr)",gap:8}}>
        <div><span style={{fontSize:9,color:"#64748b"}}>Evaluated</span><div style={{fontSize:18,fontFamily:mono,fontWeight:700,color:"#94a3b8"}}>{perf.evaluated}</div></div>
        <div><span style={{fontSize:9,color:"#22c55e"}}>BUY</span><div style={{fontSize:18,fontFamily:mono,fontWeight:700,color:"#22c55e"}}>{perf.buy?.hit_rate_pct?.toFixed(0)||0}%</div></div>
        <div><span style={{fontSize:9,color:"#ef4444"}}>SELL</span><div style={{fontSize:18,fontFamily:mono,fontWeight:700,color:"#ef4444"}}>{perf.sell?.hit_rate_pct?.toFixed(0)||0}%</div></div></div></Card>}</div></div>;
}

// ═══ MAIN APP ═════════════════════════════════════════════════════════════════
function DKInvestApp() {
  const [user,setUser]=useState(null); const [tab,setTab]=useState("home");
  const [recs,setRecs]=useState(null); const [loading,setLoading]=useState(true);
  useEffect(()=>{const t=localStorage.getItem("dkinvest_token"); if(t){get("/api/auth/me").then(u=>{setUser(u);loadRecs();}).catch(()=>{localStorage.removeItem("dkinvest_token");setLoading(false);});}else{setLoading(false);}},[]);
  const loadRecs=async()=>{try{const d=await get("/api/recommendations");setRecs(d.recommendations);}catch(e){}setLoading(false);};
  const addStock=async(s)=>{await post("/api/watchlist/add",s);setTimeout(loadRecs,2000);};
  const logout=()=>{localStorage.removeItem("dkinvest_token");setUser(null);setRecs(null);};
  if(loading)return <div style={{minHeight:"100vh",background:"#04060c",display:"flex",alignItems:"center",justifyContent:"center",color:"#64748b"}}>Loading...</div>;
  if(!user)return <LoginScreen onLogin={(u)=>{setUser(u);loadRecs();}}/>;
  const isAdmin=user.is_admin;
  const tabs=[{id:"home",label:"Home",icon:"\uD83C\uDFE0"},{id:"stocks",label:"Stocks",icon:"\uD83D\uDCCA"},{id:"portfolio",label:"Portfolio",icon:"\uD83D\uDCBC"},
    {id:"insights",label:"Insights",icon:"\uD83C\uDF0D"},{id:"discovery",label:"Discovery",icon:"\uD83D\uDD0D"},{id:"simulation",label:"Simulation",icon:"\u23F1\uFE0F"},
    {id:"alerts",label:"Alerts",icon:"\uD83D\uDD14"},...(isAdmin?[{id:"research",label:"Research",icon:"\uD83D\uDD2C"}]:[])];
  return <div style={{minHeight:"100vh",background:"#04060c",color:"#e2e8f0",fontFamily:"'Inter',sans-serif"}}>
    <style>{`@import url('https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;600;700&family=Inter:wght@400;500;600;700&family=Space+Grotesk:wght@500;700&display=swap');*{box-sizing:border-box;margin:0;padding:0}::-webkit-scrollbar{width:6px}::-webkit-scrollbar-track{background:#0a0f18}::-webkit-scrollbar-thumb{background:#1e293b;border-radius:3px}input:focus,select:focus{border-color:#334155!important}`}</style>
    <div style={{borderBottom:"1px solid #1e293b",padding:"12px 24px",display:"flex",justifyContent:"space-between",alignItems:"center"}}>
      <div style={{display:"flex",alignItems:"center",gap:8}}>
        <div style={{width:7,height:7,borderRadius:"50%",background:"#22c55e",boxShadow:"0 0 8px #22c55e44"}}/>
        <h1 style={{fontSize:17,fontWeight:700,fontFamily:disp,letterSpacing:-0.5}}>DKInvest</h1>
        <span style={{fontSize:9,fontFamily:mono,color:"#818cf8",background:"#1e1b4b",padding:"1px 5px",borderRadius:2}}>v9</span></div>
      <div style={{display:"flex",alignItems:"center",gap:12}}>
        <span style={{fontSize:11,color:"#64748b"}}>{user.display_name||user.username}</span>
        <Btn onClick={logout} variant="ghost">Logout</Btn></div></div>
    <div style={{display:"flex",borderBottom:"1px solid #1e293b",overflowX:"auto"}}>
      {tabs.map(t=><button key={t.id} onClick={()=>setTab(t.id)} style={{padding:"9px 14px",border:"none",background:"transparent",cursor:"pointer",fontFamily:mono,fontSize:10,color:tab===t.id?"#e2e8f0":"#64748b",borderBottom:tab===t.id?"2px solid #818cf8":"2px solid transparent",display:"flex",alignItems:"center",gap:4,whiteSpace:"nowrap"}}>
        <span>{t.icon}</span>{t.label}</button>)}</div>
    {tab==="home"&&<HomeTab recs={recs}/>}
    {tab==="stocks"&&<StocksTab recs={recs} onRefresh={loadRecs} onAddStock={addStock}/>}
    {tab==="portfolio"&&<PortfolioTab/>}
    {tab==="insights"&&<MarketInsightsTab/>}
    {tab==="discovery"&&<DiscoveryTab/>}
    {tab==="simulation"&&<SimulationTab/>}
    {tab==="alerts"&&<AlertsTab/>}
    {tab==="research"&&isAdmin&&<ResearchLabTab/>}
    <div style={{padding:"12px 24px",borderTop:"1px solid #1e293b",display:"flex",justifyContent:"space-between"}}>
      <span style={{fontSize:9,color:"#334155"}}>DKInvest v9 · 19 agents · {isAdmin?"Admin":"User"}</span>
      <span style={{fontSize:9,color:"#334155"}}>Not financial advice</span></div></div>;
}

window.__dkinvest_app = DKInvestApp;
