// ─────────────────────────────────────────────────────────────────────────
// Meridian — Portfolio table + Stock detail (wired to the shared store)
// ─────────────────────────────────────────────────────────────────────────
function Portfolio({ theme, onOpenStock, store }) {
  const data = store.data;
  const all = data ? data.positions : [];
  const s = data && data.summary;
  const [q, setQ] = useState("");
  const [sig, setSig] = useState("all");
  const [sort, setSort] = useState({ key: "value", dir: "desc" });

  const rows = useMemo(() => {
    let r = all.filter((p) =>
      (sig === "all" || p.signal === sig) &&
      (p.name.toLowerCase().includes(q.toLowerCase()) || (p.t || "").toLowerCase().includes(q.toLowerCase()) || (p.sector || "").toLowerCase().includes(q.toLowerCase())));
    const { key, dir } = sort;
    r = [...r].sort((a, b) => {
      let av = a[key], bv = b[key];
      if (av == null) av = -Infinity; if (bv == null) bv = -Infinity;
      if (typeof av === "string") return dir === "asc" ? av.localeCompare(bv) : bv.localeCompare(av);
      return dir === "asc" ? av - bv : bv - av;
    });
    return r;
  }, [q, sig, sort, all]);

  const toggleSort = (key) => setSort((s) => ({ key, dir: s.key === key && s.dir === "desc" ? "asc" : "desc" }));
  const Th = ({ k, children, num }) => (
    <th className={"sortable" + (num ? " num" : "")} onClick={() => toggleSort(k)}>
      <span style={{ display: "inline-flex", alignItems: "center", gap: 3, justifyContent: num ? "flex-end" : "flex-start" }}>
        {children}
        {sort.key === k && <Icon name={sort.dir === "desc" ? "chevron-down" : "chevron-up"} size={12} style={{ color: "var(--fg-2)" }} />}
      </span>
    </th>
  );

  const counts = { all: all.length, buy: all.filter(p=>p.signal==="buy").length, hold: all.filter(p=>p.signal==="hold").length, sell: all.filter(p=>p.signal==="sell").length };

  return (
    <div className="rise">
      <PageHeader title="Portfolio"
        subtitle={s ? `${all.length} holdings · ${fmt.eur0(s.equityValue)} at market · ${fmt.eur0(s.invested)} invested` : "Loading positions…"}
        actions={<button className="btn btn-sm" onClick={store.reload}><Icon name="refresh-cw" size={13} /> Reload</button>} />

      {store.error ? (
        <Card><EmptyState icon="cloud-off" title="Couldn't load positions" body={store.error.message} action={<button className="btn btn-sm" onClick={store.reload}>Retry</button>} /></Card>
      ) : store.loading ? (
        <Card className="card-pad-0"><div style={{ padding: 18 }}><Col gap={10}>{Array.from({length:6}).map((_,i)=><Skel key={i} h={44} />)}</Col></div></Card>
      ) : all.length === 0 ? (
        <Card><EmptyState icon="wallet" title="No positions yet" body="Connect Finanzfluss in Settings and run a portfolio refresh to pull your holdings." /></Card>
      ) : (
      <>
      {/* filter bar */}
      <Row justify="space-between" wrap style={{ gap: 12, marginBottom: 14 }}>
        <div className="input-icon" style={{ width: 280, maxWidth: "100%" }}>
          <Icon name="search" size={15} />
          <input className="input" placeholder="Search ticker, name or sector" value={q} onChange={(e) => setQ(e.target.value)} />
        </div>
        <div className="segmented">
          {["all", "buy", "hold", "sell"].map((k) => (
            <button key={k} className={sig === k ? "active" : ""} onClick={() => setSig(k)}>
              {k === "all" ? "All" : k[0].toUpperCase() + k.slice(1)} <span className="mono" style={{ opacity: 0.6 }}>{counts[k]}</span>
            </button>
          ))}
        </div>
      </Row>

      <Card className="card-pad-0">
        <div className="scroll-nice" style={{ overflowX: "auto" }}>
          <table className="tbl" style={{ minWidth: 920 }}>
            <thead>
              <tr style={{ background: "var(--bg-surface)" }}>
                <th style={{ paddingLeft: 20 }} className="sortable" onClick={() => toggleSort("name")}>
                  <span style={{ display: "inline-flex", alignItems: "center", gap: 3 }}>Holding {sort.key === "name" && <Icon name={sort.dir === "desc" ? "chevron-down" : "chevron-up"} size={12} />}</span>
                </th>
                <Th k="shares" num>Shares</Th>
                <Th k="avg" num>Avg</Th>
                <Th k="price" num>Price</Th>
                <Th k="value" num>Value</Th>
                <Th k="pl" num>P&L</Th>
                <Th k="alloc" num>Alloc</Th>
                <Th k="aaqs" num>AAQS</Th>
                <Th k="fvGap" num>Fair value</Th>
                <th style={{ paddingRight: 20 }} className="num">Signal</th>
              </tr>
            </thead>
            <tbody>
              {rows.map((p) => (
                <tr key={p.t} className="clickable" onClick={() => onOpenStock(p.t)}>
                  <td style={{ paddingLeft: 20 }}>
                    <Row gap={11}>
                      <StockLogo isin={p.isin} ticker={p.ticker} name={p.name} size={34} />
                      <div style={{ minWidth: 0 }}>
                        <div style={{ fontWeight: 600, fontSize: 14, whiteSpace: "nowrap" }}>{p.name}</div>
                        <div className="mono muted" style={{ fontSize: 11 }}>{p.t} · {p.sector}</div>
                      </div>
                    </Row>
                  </td>
                  <td className="num">{fmt.num0(p.shares)}</td>
                  <td className="num muted">{fmt.eur(p.avg)}</td>
                  <td className="num">{fmt.eur(p.price)}</td>
                  <td className="num" style={{ fontWeight: 600 }}>{fmt.eur(p.value)}</td>
                  <td className="num">
                    <div style={{ color: p.pl >= 0 ? "var(--pos-fg)" : "var(--neg-fg)", fontWeight: 600 }}>{fmt.sEur(p.pl)}</div>
                    <div style={{ color: p.pl >= 0 ? "var(--pos-fg)" : "var(--neg-fg)", fontSize: 12 }}>{fmt.sPct(p.plPct)}</div>
                  </td>
                  <td className="num muted">{fmt.pct(p.alloc)}</td>
                  <td className="num"><div style={{ display: "inline-flex", justifyContent: "flex-end" }}><AaqsMeter score={p.aaqs} width={42} /></div></td>
                  <td className="num"><div style={{ display: "inline-flex", justifyContent: "flex-end" }}><FvBar gap={p.fvGap} width={48} /></div></td>
                  <td className="num" style={{ paddingRight: 20 }}><SignalBadge signal={p.signal} /></td>
                </tr>
              ))}
            </tbody>
            <tfoot>
              <tr style={{ borderTop: "2px solid var(--border-1)" }}>
                <td style={{ paddingLeft: 20, fontWeight: 600 }}>Total · {rows.length}</td>
                <td colSpan={3}></td>
                <td className="num" style={{ fontWeight: 700, paddingTop: 14, paddingBottom: 14 }}>{fmt.eur(rows.reduce((a, p) => a + p.value, 0))}</td>
                <td className="num" style={{ fontWeight: 600, color: rows.reduce((a,p)=>a+p.pl,0) >= 0 ? "var(--pos-fg)" : "var(--neg-fg)" }}>{fmt.sEur(rows.reduce((a, p) => a + p.pl, 0))}</td>
                <td className="num muted">{fmt.pct(rows.reduce((a, p) => a + p.alloc, 0))}</td>
                <td colSpan={3}></td>
              </tr>
            </tfoot>
          </table>
        </div>
        {rows.length === 0 && <EmptyState icon="search-x" title="No matches" body="Try a different search or signal filter." />}
      </Card>
      </>
      )}
    </div>
  );
}

/* ── Stock detail ─────────────────────────────────────────────────────────── */
function StockDetail({ ticker, store, onBack, onOpenStock, onNavigate, onOpenHermes, theme }) {
  const data = store.data;
  const p = data ? (data.positions.find((x) => x.t === ticker) || data.positions[0]) : null;

  const related = useAsync(async () => {
    if (!p) return { research: [], catalysts: [] };
    const [pp, cc, cal] = await Promise.all([
      API.papers(100).catch(() => ({ papers: [] })),
      API.calls(100).catch(() => ({ calls: [] })),
      API.calendar(20).catch(() => ({ events: [] })),
    ]);
    const matchSym = (row) => (row.ticker && row.ticker.toUpperCase() === (p.ticker || "").toUpperCase()) || (row.isin && row.isin === p.isin);
    const research = [
      ...(pp.papers || []).filter(matchSym).map((r) => API.map.mapResearch(r, "analysis", data.recBySym)),
      ...(cc.calls || []).filter(matchSym).map((r) => API.map.mapResearch(r, "call", data.recBySym)),
    ];
    const catalysts = (cal.events || []).filter((e) => (e.ticker && e.ticker.toUpperCase() === (p.ticker || "").toUpperCase()) || (e.isin && e.isin === p.isin));
    return { research, catalysts };
  }, [p && p.t]);

  if (store.loading || !p) {
    return <div className="rise"><Row gap={10} style={{ marginBottom: 18 }}><button className="btn btn-sm btn-ghost" onClick={onBack}><Icon name="arrow-left" size={14} /> Portfolio</button></Row><SkelCard lines={5} /></div>;
  }

  const gapCap = p.fvGap == null ? 0 : Math.max(-40, Math.min(40, p.fvGap));
  const markerPct = 50 - (gapCap / 40) * 50;

  return (
    <div className="rise">
      <Row gap={10} style={{ marginBottom: 18 }}>
        <button className="btn btn-sm btn-ghost" onClick={onBack}><Icon name="arrow-left" size={14} /> Portfolio</button>
      </Row>

      {/* header */}
      <Row justify="space-between" align="flex-start" wrap style={{ gap: 16, marginBottom: 22 }}>
        <Row gap={14}>
          <StockLogo isin={p.isin} ticker={p.ticker} name={p.name} size={52} radius={13} initialsFontSize={17} />
          <div>
            <Row gap={10} align="center" wrap>
              <h1 style={{ fontSize: "var(--fs-2xl)", fontWeight: 600, letterSpacing: "var(--tracking-tighter)", margin: 0 }}>{p.name}</h1>
              <SignalBadge signal={p.signal} size="lg" />
            </Row>
            <Row gap={8} style={{ marginTop: 4, fontSize: 13, color: "var(--fg-2)" }} wrap>
              <span className="mono">{p.t}</span><span>·</span><span>{p.sector}</span>{p.isin && <><span>·</span><span className="mono">{p.isin}</span></>}
            </Row>
          </div>
        </Row>
        <div style={{ textAlign: "right" }}>
          <div style={{ fontSize: 28, fontWeight: 600, letterSpacing: "-0.02em", fontVariantNumeric: "tabular-nums" }}>{fmt.eur(p.price)}</div>
          <Delta value={p.plPct} kind="pct" size={14} style={{ justifyContent: "flex-end" }} />
        </div>
      </Row>

      <div style={{ display: "grid", gridTemplateColumns: "minmax(0, 1.7fr) minmax(0, 1fr)", gap: 16, alignItems: "start" }} className="dash-grid">
        {/* LEFT */}
        <Col gap={16} style={{ minWidth: 0 }}>
          {/* valuation gauge */}
          <Card>
            <SectionTitle icon="scale">Fair value vs price</SectionTitle>
            {p.fair == null ? (
              <EmptyState icon="help-circle" title="No valuation yet" body="Eulerpool hasn't scored this ISIN. Run an enrichment refresh." />
            ) : <>
              <Row justify="space-between" wrap style={{ gap: 16, marginBottom: 18 }}>
                <div><div className="kpi-label" style={{ whiteSpace: "nowrap" }}>Current price</div><div className="mono" style={{ fontSize: 20, fontWeight: 600, marginTop: 3 }}>{fmt.eur(p.price)}</div></div>
                <div><div className="kpi-label" style={{ whiteSpace: "nowrap" }}>Fair value</div><div className="mono" style={{ fontSize: 20, fontWeight: 600, marginTop: 3, color: "var(--sage-700)" }}>{fmt.eur(p.fair)}</div></div>
                <div style={{ textAlign: "right" }}><div className="kpi-label" style={{ whiteSpace: "nowrap" }}>Gap</div><div className="mono" style={{ fontSize: 20, fontWeight: 600, marginTop: 3, color: p.fvGap >= 0 ? "var(--pos-fg)" : "var(--neg-fg)" }}>{fmt.sPct(p.fvGap)}</div></div>
              </Row>
              <div style={{ position: "relative", height: 46 }}>
                <div style={{ position: "absolute", top: 18, left: 0, right: 0, height: 8, borderRadius: 999, background: "linear-gradient(90deg, var(--pos-bg), var(--bg-tint) 50%, var(--neg-bg))" }} />
                <div style={{ position: "absolute", top: 12, left: "50%", width: 2, height: 20, background: "var(--border-strong)", transform: "translateX(-50%)" }} />
                <div style={{ position: "absolute", top: 8, left: markerPct + "%", transform: "translateX(-50%)", display: "flex", flexDirection: "column", alignItems: "center" }}>
                  <div style={{ width: 16, height: 16, borderRadius: 999, background: "var(--bg-surface)", border: "3px solid " + (p.fvGap >= 0 ? "var(--pos-fg)" : "var(--neg-fg)"), boxShadow: "var(--elev-1)" }} />
                </div>
                <div style={{ position: "absolute", top: 34, left: 0, fontSize: 11, color: "var(--pos-fg)" }}>Undervalued</div>
                <div style={{ position: "absolute", top: 34, left: "50%", transform: "translateX(-50%)", fontSize: 11, color: "var(--fg-3)" }}>Fair</div>
                <div style={{ position: "absolute", top: 34, right: 0, fontSize: 11, color: "var(--neg-fg)" }}>Overvalued</div>
              </div>
            </>}
          </Card>

          {/* Quality */}
          <Card>
            <Row justify="space-between" style={{ marginBottom: 8 }}>
              <SectionTitle icon="award">Quality · AAQS</SectionTitle>
              {p.aaqs != null && <Row gap={8} align="baseline"><span className="mono" style={{ fontSize: 26, fontWeight: 600, color: aaqsColor(p.aaqs) }}>{fmt.num(p.aaqs)}</span><span className="muted" style={{ fontSize: 13 }}>/ 10</span></Row>}
            </Row>
            {p.aaqs == null ? <EmptyState icon="help-circle" title="No quality score" body="AAQS appears once Eulerpool enrichment covers this name." />
              : <div style={{ height: 12, borderRadius: 999, background: "var(--bg-tint)", overflow: "hidden" }}><div style={{ width: (Math.max(0, Math.min(10, p.aaqs)) / 10 * 100) + "%", height: "100%", borderRadius: 999, background: aaqsColor(p.aaqs) }} /></div>}
            {p.coverage && p.coverage.length > 0 && <Row gap={6} wrap style={{ marginTop: 12 }}>{p.coverage.map((c) => <span key={c} className="chip" style={{ fontSize: 11 }}>{c}</span>)}</Row>}
          </Card>

          {/* Hermes take */}
          {p.why && (
            <Card style={{ background: "linear-gradient(140deg, var(--signal-soft), var(--bg-surface))", borderColor: "var(--signal-border)" }}>
              <Row gap={11} align="flex-start">
                <div style={{ width: 34, height: 34, borderRadius: 10, background: "linear-gradient(140deg, var(--sage-500), var(--sage-800))", display: "grid", placeItems: "center", flexShrink: 0 }}><Icon name="sparkles" size={16} style={{ color: "#fff" }} /></div>
                <div style={{ flex: 1 }}>
                  <Row justify="space-between" align="center" style={{ marginBottom: 6 }}>
                    <span style={{ fontWeight: 600, fontSize: 14 }}>Engine's take</span>
                    <SignalBadge signal={p.signal} />
                  </Row>
                  <p style={{ fontSize: 13.5, lineHeight: 1.6, margin: 0, color: "var(--fg-1)" }}>{p.why}</p>
                  <button className="btn btn-sm" style={{ marginTop: 12 }} onClick={onOpenHermes}><Icon name="message-square" size={13} /> Discuss with Hermes</button>
                </div>
              </Row>
            </Card>
          )}
        </Col>

        {/* RIGHT RAIL */}
        <Col gap={16} style={{ minWidth: 0 }}>
          {/* your position */}
          <Card>
            <SectionTitle icon="wallet">Your position</SectionTitle>
            <Col gap={0}>
              {[
                ["Shares", fmt.num0(p.shares)],
                ["Avg cost", fmt.eur(p.avg)],
                ["Market value", fmt.eur(p.value)],
                ["Cost basis", fmt.eur(p.cost)],
                ["Allocation", fmt.pct(p.alloc)],
              ].map(([k, v], i) => (
                <Row key={k} justify="space-between" style={{ padding: "9px 0", borderTop: i ? "1px solid var(--border-1)" : 0, fontSize: 13.5, gap: 12 }}>
                  <span className="muted" style={{ whiteSpace: "nowrap" }}>{k}</span><span className="mono" style={{ fontWeight: 500, whiteSpace: "nowrap" }}>{v}</span>
                </Row>
              ))}
              <Row justify="space-between" style={{ padding: "11px 0 0", borderTop: "1px solid var(--border-1)", marginTop: 2 }}>
                <span style={{ fontWeight: 600, fontSize: 13.5 }}>Unrealised P&L</span>
                <div style={{ textAlign: "right" }}>
                  <div className="mono" style={{ fontWeight: 700, color: p.pl >= 0 ? "var(--pos-fg)" : "var(--neg-fg)" }}>{fmt.sEur(p.pl)}</div>
                  <div className="mono" style={{ fontSize: 12, color: p.pl >= 0 ? "var(--pos-fg)" : "var(--neg-fg)" }}>{fmt.sPct(p.plPct)}</div>
                </div>
              </Row>
            </Col>
          </Card>

          {/* key stats */}
          <Card>
            <SectionTitle icon="info">Snapshot</SectionTitle>
            <Col gap={0}>
              {[
                ["AAQS quality", p.aaqs != null ? <span className="mono" style={{ color: aaqsColor(p.aaqs), fontWeight: 600 }}>{fmt.num(p.aaqs)} / 10</span> : <span className="muted-2">—</span>],
                ["Fair value", p.fair != null ? <span className="mono">{fmt.eur(p.fair)}</span> : <span className="muted-2">—</span>],
                ["Fair-value gap", p.fvGap != null ? <span className="mono" style={{ color: p.fvGap >= 0 ? "var(--pos-fg)" : "var(--neg-fg)" }}>{fmt.sPct(p.fvGap)}</span> : <span className="muted-2">—</span>],
                ["Signal", <SignalBadge signal={p.signal} />],
                ["Conviction", <span style={{ fontWeight: 500 }}>{p.conviction || "—"}</span>],
              ].map(([k, v], i) => (
                <Row key={k} justify="space-between" align="center" style={{ padding: "9px 0", borderTop: i ? "1px solid var(--border-1)" : 0, fontSize: 13.5, gap: 12 }}>
                  <span className="muted" style={{ whiteSpace: "nowrap" }}>{k}</span>{v}
                </Row>
              ))}
            </Col>
          </Card>

          {/* related catalysts */}
          {related.data && related.data.catalysts.length > 0 && (
            <Card>
              <SectionTitle icon="calendar-clock">Upcoming catalysts</SectionTitle>
              <Col gap={10}>
                {related.data.catalysts.map((c, i) => (
                  <Row key={i} gap={11} align="flex-start">
                    <div style={{ textAlign: "center", flexShrink: 0, width: 40 }}>
                      <div className="mono" style={{ fontSize: 15, fontWeight: 600 }}>{new Date(c.date).getDate()}</div>
                      <div className="mono muted" style={{ fontSize: 10 }}>{fmt.wday(new Date(c.date))}</div>
                    </div>
                    <div style={{ flex: 1 }}>
                      <div style={{ fontSize: 13, fontWeight: 600 }}>{c.label}</div>
                    </div>
                  </Row>
                ))}
              </Col>
            </Card>
          )}

          {/* related research */}
          <Card>
            <SectionTitle icon="library" action={<button className="btn btn-sm btn-ghost" onClick={() => onNavigate("research")}>All <Icon name="arrow-right" size={12} /></button>}>Related research</SectionTitle>
            {related.loading ? <Col gap={8}><Skel h={36} /><Skel h={36} /></Col>
              : (related.data && related.data.research.length > 0) ? (
              <Col gap={2}>
                {related.data.research.map((r, i) => (
                  <button key={r.id} onClick={() => onNavigate("research")} className="mover-row" style={{ display: "flex", gap: 11, alignItems: "flex-start", padding: "10px 8px", background: "transparent", border: 0, borderTop: i ? "1px solid var(--border-1)" : 0, width: "100%", textAlign: "left", cursor: "pointer", borderRadius: 8 }}>
                    <div style={{ width: 28, height: 28, borderRadius: 8, background: "var(--bg-tint)", display: "grid", placeItems: "center", flexShrink: 0, color: "var(--fg-2)" }}><Icon name={r.type === "analysis" ? "file-text" : "headphones"} size={13} /></div>
                    <div style={{ flex: 1, minWidth: 0 }}>
                      <div style={{ fontWeight: 600, fontSize: 13, lineHeight: 1.3 }}>{r.title}</div>
                      <div className="muted" style={{ fontSize: 11.5, marginTop: 2 }}>{r.source} · {fmt.date(r.date)}</div>
                    </div>
                  </button>
                ))}
              </Col>
            ) : <EmptyState icon="file-search" title="No research yet" body={`No analyses linked to ${p.name} in your library.`} />}
          </Card>
        </Col>
      </div>
    </div>
  );
}

Object.assign(window, { Portfolio, StockDetail });
