// ─────────────────────────────────────────────────────────────────────────
// Meridian — HEUTE (Today)
// The daily feed: an Ampel verdict, "Handeln / Prüfen" action cards, the
// "Neu seit gestern" change log, the "Diese Woche" foresight catalysts, and
// an effectiveness panel (portfolio vs MSCI World) — built to be readable in
// under a minute on mobile.
//
// Robustness contract: the backend (GET /api/feed, /api/performance) is being
// built in parallel. EVERY field can be missing or degraded, so we guard each
// access, default to empty arrays, and never render NaN / "undefined".
// ─────────────────────────────────────────────────────────────────────────

const _tIsNum = (v) => typeof v === "number" && isFinite(v);
const _tNum0 = (v) => (_tIsNum(v) ? v : 0);
const _tArr = (v) => (Array.isArray(v) ? v : []);

// Ampel level → palette. Falls back to amber for unknown levels.
const VERDICT_TONE = {
  green: { accent: "var(--pos-fg)", soft: "var(--signal-bg)", dot: "var(--pos-strong)", icon: "circle-check-big", label: "🟢" },
  amber: { accent: "var(--mixed-accent)", soft: "var(--mixed-soft)", dot: "var(--mixed-accent)", icon: "circle-alert", label: "🟡" },
  red:   { accent: "var(--neg-fg)", soft: "var(--danger-bg)", dot: "var(--neg-strong)", icon: "octagon-alert", label: "🔴" },
};

// recommended_action → primary CTA label (German)
const ACTION_CTA = {
  review: "Prüfen",
  add: "Nachkauf prüfen",
  trim: "Trimmen",
  sell: "Verkauf prüfen",
  watch: "Beobachten",
};

// kind → icon for an event card
const KIND_ICON = {
  earnings: "bar-chart-2",
  dividend: "coins",
  macro: "landmark",
  news: "newspaper",
  research: "file-text",
  call: "headphones",
  valuation: "scale",
  signal: "git-fork",
  price: "trending-up",
  aaqs: "gauge",
  catalyst: "calendar-clock",
};
const kindIcon = (k) => KIND_ICON[k] || "bell";

// severity → small dot color
const SEV_DOT = { high: "var(--neg-fg)", medium: "var(--mixed-accent)", low: "var(--fg-3)" };

function tDate(d) { return fmt.date(d); }
function tWhen(ev) {
  // Prefer the event date; fall back to created_at. Use relTime when it's a
  // proper timestamp, else the German date.
  const ts = ev.created_at || ev.event_date;
  if (!ts) return "—";
  return relTime(ts);
}

/* ── A single before→after mini-diff ──────────────────────────────────────── */
function BeforeAfter({ before, after }) {
  if (before == null && after == null) return null;
  const fmtVal = (v) => (v == null || v === "" ? "—" : String(v));
  return (
    <Row gap={7} align="center" wrap style={{ fontSize: 12, marginTop: 8 }}>
      <span className="chip" style={{ background: "var(--bg-tint)", color: "var(--fg-2)", padding: "2px 9px" }}>{fmtVal(before)}</span>
      <Icon name="arrow-right" size={12} style={{ color: "var(--fg-3)" }} />
      <span className="chip chip-tinted" style={{ padding: "2px 9px", fontWeight: 600 }}>{fmtVal(after)}</span>
    </Row>
  );
}

/* ── Action card (Handeln / Prüfen) ───────────────────────────────────────── */
function ActionCard({ ev, onOpenStock, onOpenHermes, onDismiss, busy }) {
  const isStock = ev.entity_type === "stock" || ev.entity_type === "position";
  const ticker = isStock ? ev.entity_key : null;
  const cta = ACTION_CTA[ev.recommended_action] || "Prüfen";
  const sevColor = SEV_DOT[ev.severity] || "var(--fg-3)";
  const onPrimary = () => { if (ticker) onOpenStock(ticker); else onOpenHermes(); };

  return (
    <div className="card" style={{ borderLeft: `3px solid ${sevColor}` }}>
      <Row gap={11} align="flex-start">
        {isStock
          ? <StockLogo isin={ev.logo_isin} ticker={ticker} name={ev.title} size={36} />
          : <div style={{ width: 36, height: 36, borderRadius: 9, background: "var(--bg-tint)", display: "grid", placeItems: "center", flexShrink: 0, color: "var(--fg-2)" }}><Icon name={kindIcon(ev.kind)} size={16} /></div>}
        <div style={{ flex: 1, minWidth: 0 }}>
          <Row justify="space-between" align="flex-start" gap={10}>
            <div style={{ fontWeight: 600, fontSize: 15, lineHeight: 1.3, minWidth: 0 }}>{ev.title || "—"}</div>
            {ticker && <span className="chip chip-tinted mono" style={{ fontSize: 11, flexShrink: 0 }}>{ticker}</span>}
          </Row>
          {ev.summary && <p className="muted" style={{ fontSize: 13, lineHeight: 1.55, margin: "6px 0 0" }}>{ev.summary}</p>}
          <BeforeAfter before={ev.before} after={ev.after} />
          <Row justify="space-between" align="center" wrap style={{ marginTop: 12, gap: 10 }}>
            <Row gap={6} style={{ fontSize: 11.5, color: "var(--fg-3)" }}>
              <Icon name={kindIcon(ev.kind)} size={12} style={{ color: "var(--fg-3)" }} />
              <span>{tWhen(ev)}</span>
            </Row>
            <Row gap={6} wrap>
              <button className="btn btn-sm btn-primary" onClick={onPrimary}>
                <Icon name="arrow-right" size={13} style={{ color: "#fff" }} /> {cta}
              </button>
              {/* TODO prefill: pass a question string once onOpenHermes accepts one */}
              <button className="btn btn-sm" onClick={() => onOpenHermes()} title="Hermes fragen">
                <Icon name="sparkles" size={13} /> Hermes
              </button>
              <button className="btn btn-sm btn-ghost" onClick={() => onDismiss(ev.id)} disabled={busy} title="Ignorieren">
                <Icon name={busy ? "loader" : "x"} size={13} className={busy ? "spin" : ""} />
              </button>
            </Row>
          </Row>
        </div>
      </Row>
    </div>
  );
}

/* ── Compact change row (Neu seit gestern) ────────────────────────────────── */
function ChangeRow({ ev, onOpenStock, first }) {
  const isStock = ev.entity_type === "stock" || ev.entity_type === "position";
  const ticker = isStock ? ev.entity_key : null;
  const clickable = !!ticker;
  return (
    <button
      onClick={() => clickable && onOpenStock(ticker)}
      className="mover-row"
      style={{ display: "flex", gap: 11, alignItems: "flex-start", padding: "11px 8px", background: "transparent", border: 0, borderTop: first ? 0 : "1px solid var(--border-1)", width: "100%", textAlign: "left", cursor: clickable ? "pointer" : "default", borderRadius: 8 }}>
      {isStock
        ? <StockLogo isin={ev.logo_isin} ticker={ticker} name={ev.title} size={28} />
        : <div style={{ width: 28, height: 28, borderRadius: 8, background: "var(--bg-tint)", display: "grid", placeItems: "center", flexShrink: 0, color: "var(--fg-2)" }}><Icon name={kindIcon(ev.kind)} size={13} /></div>}
      <div style={{ flex: 1, minWidth: 0 }}>
        <Row gap={8} align="baseline" style={{ minWidth: 0 }}>
          <span style={{ fontWeight: 600, fontSize: 13.5, lineHeight: 1.3 }}>{ev.title || "—"}</span>
          {ticker && <span className="mono muted" style={{ fontSize: 11 }}>{ticker}</span>}
        </Row>
        {ev.summary && <div className="muted" style={{ fontSize: 12, lineHeight: 1.45, marginTop: 2 }}>{ev.summary}</div>}
      </div>
      <span className="muted-2" style={{ fontSize: 11, whiteSpace: "nowrap", flexShrink: 0, marginTop: 2 }}>{tWhen(ev)}</span>
    </button>
  );
}

/* ── Foresight row (Diese Woche) ──────────────────────────────────────────── */
function ForesightRow({ ev, onOpenStock, first }) {
  const isStock = ev.entity_type === "stock" || ev.entity_type === "position";
  const ticker = isStock ? ev.entity_key : null;
  // "In N Tagen" relative phrasing from event_date.
  let when = ev.event_date ? fmt.date(ev.event_date) : "—";
  if (ev.event_date) {
    const d = new Date(ev.event_date);
    if (!isNaN(d)) {
      const days = Math.round((d.setHours(0, 0, 0, 0) - new Date().setHours(0, 0, 0, 0)) / 86400000);
      if (days === 0) when = "Heute";
      else if (days === 1) when = "Morgen";
      else if (days > 1) when = "In " + days + " Tagen";
      else when = fmt.date(ev.event_date);
    }
  }
  return (
    <button
      onClick={() => ticker && onOpenStock(ticker)}
      className="mover-row"
      style={{ display: "flex", gap: 11, alignItems: "center", padding: "10px 8px", background: "transparent", border: 0, borderTop: first ? 0 : "1px solid var(--border-1)", width: "100%", textAlign: "left", cursor: ticker ? "pointer" : "default", 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="calendar-clock" size={13} />
      </div>
      <div style={{ flex: 1, minWidth: 0 }}>
        <Row gap={8} align="baseline">
          <span className="caps" style={{ fontSize: 10, color: "var(--sage-700)" }}>{when}</span>
          {ticker && <span className="mono muted" style={{ fontSize: 11 }}>{ticker}</span>}
        </Row>
        <div style={{ fontWeight: 600, fontSize: 13.5, lineHeight: 1.3, marginTop: 1 }}>{ev.title || "—"}</div>
        {ev.summary && <div className="muted" style={{ fontSize: 12, lineHeight: 1.4, marginTop: 2 }}>{ev.summary}</div>}
      </div>
    </button>
  );
}

/* ── Effectiveness chart (portfolio vs MSCI World, normalised to 100) ─────── */
const PERF_RANGES = [["3m", "3M"], ["6m", "6M"], ["1y", "1J"], ["2y", "2J"], ["max", "Alles"]];

function EffectivenessChart({ theme }) {
  const [range, setRange] = useState("1y");
  const perf = useAsync(() => API.performance(range).catch(() => null), [range]);
  const ref = useRef(null);
  const chart = useRef(null);
  const data = perf.data;

  // Normalise a [{date,value}] series to a base of 100.
  const norm = (series) => {
    const pts = _tArr(series).filter((p) => p && _tIsNum(p.value));
    if (pts.length === 0) return [];
    const base = pts[0].value || 1;
    return pts.map((p) => ({ t: p.date, v: (p.value / base) * 100 }));
  };

  const port = norm(data && data.portfolio);
  const bench = norm(data && data.benchmark);
  const benchAvailable = data ? data.benchmark_available !== false && bench.length > 0 : false;
  const benchName = (data && data.benchmark_name) || "MSCI World";
  const summary = (data && data.summary) || null;

  useEffect(() => {
    if (!ref.current || !window.Chart || port.length === 0) {
      if (chart.current) { chart.current.destroy(); chart.current = null; }
      return;
    }
    const ctx = ref.current.getContext("2d");
    const line = cssVar("--sage-600") || "#557D65";
    const benchLine = cssVar("--sky-accent") || "#5B91BC";
    const grid = cssVar("--border-1");
    const tick = cssVar("--fg-3");
    const surf = cssVar("--bg-surface");
    const ink = cssVar("--fg-1");
    const muted = cssVar("--fg-2");
    const datasets = [{
      label: "Portfolio", data: port.map((d) => d.v), borderColor: line, borderWidth: 2,
      backgroundColor: "transparent", fill: false, tension: 0.28, pointRadius: 0, pointHoverRadius: 4,
      pointHoverBackgroundColor: line, pointHoverBorderColor: surf, pointHoverBorderWidth: 2,
    }];
    if (benchAvailable) {
      datasets.push({
        label: benchName, data: bench.map((d) => d.v), borderColor: benchLine, borderWidth: 1.75,
        borderDash: [5, 4], backgroundColor: "transparent", fill: false, tension: 0.28, pointRadius: 0, pointHoverRadius: 4,
        pointHoverBackgroundColor: benchLine, pointHoverBorderColor: surf, pointHoverBorderWidth: 2,
      });
    }
    if (chart.current) chart.current.destroy();
    chart.current = new window.Chart(ctx, {
      type: "line",
      data: { labels: port.map((d) => d.t), datasets },
      options: {
        responsive: true, maintainAspectRatio: false,
        interaction: { mode: "index", intersect: false },
        plugins: {
          legend: {
            display: true, position: "bottom", align: "start",
            labels: { boxWidth: 10, boxHeight: 10, usePointStyle: true, pointStyle: "line", color: muted, font: { family: "Geist", size: 11.5 }, padding: 14 },
          },
          tooltip: {
            backgroundColor: surf, titleColor: muted, bodyColor: ink, borderColor: grid, borderWidth: 1,
            padding: 10, cornerRadius: 10, displayColors: true, boxWidth: 8, boxHeight: 8, usePointStyle: true,
            titleFont: { family: "Geist Mono", size: 11 }, bodyFont: { family: "Geist Mono", size: 12.5 },
            callbacks: {
              title: (it) => fmt.date(it[0].label),
              label: (it) => " " + it.dataset.label + ": " + fmt.sPct(it.parsed.y - 100),
            },
          },
        },
        scales: {
          x: { display: false, grid: { display: false } },
          y: {
            position: "right", grid: { color: grid, drawTicks: false }, border: { display: false },
            ticks: { color: tick, font: { family: "Geist Mono", size: 10 }, maxTicksLimit: 5, padding: 8, callback: (v) => fmt.num0(v) },
          },
        },
      },
    });
    return () => { if (chart.current) { chart.current.destroy(); chart.current = null; } };
  }, [port, bench, benchAvailable, theme]);

  const pr = summary ? summary.portfolio_return_pct : null;
  const br = summary ? summary.benchmark_return_pct : null;
  const alpha = summary ? summary.alpha_pct : null;
  const alphaNeg = _tIsNum(alpha) && alpha < 0;

  return (
    <Card>
      <Row justify="space-between" align="center" wrap style={{ gap: 10, marginBottom: 12 }}>
        <Row gap={8}>
          <Icon name="line-chart" size={16} style={{ color: "var(--fg-3)" }} />
          <h2 style={{ fontSize: "var(--fs-lg)", fontWeight: 600, letterSpacing: "var(--tracking-tight)", margin: 0 }}>Deine Performance vs {benchName}</h2>
        </Row>
        <div className="segmented">
          {PERF_RANGES.map(([r, l]) => <button key={r} className={range === r ? "active" : ""} onClick={() => setRange(r)}>{l}</button>)}
        </div>
      </Row>

      <div style={{ minHeight: 220 }}>
        {perf.loading ? (
          <div style={{ height: 220, display: "grid", placeItems: "center" }}><Icon name="loader" size={18} className="spin" style={{ color: "var(--fg-3)" }} /></div>
        ) : port.length < 2 ? (
          <EmptyState icon="line-chart" title="Noch keine Performance-Historie" body="Die Kurve füllt sich, sobald tägliche Snapshots vorliegen." />
        ) : (
          <div className="chart-wrap" style={{ height: 220 }}><canvas ref={ref} /></div>
        )}
      </div>

      {summary && port.length >= 2 && (
        <Row gap={0} align="stretch" wrap style={{ marginTop: 14, borderRadius: "var(--radius-3)", background: "var(--bg-sunken)", overflow: "hidden" }}>
          <div style={{ flex: 1, minWidth: 110, padding: "11px 13px" }}>
            <div className="kpi-label" style={{ fontSize: 10 }}>Portfolio</div>
            <div className="mono" style={{ fontSize: 17, fontWeight: 600, marginTop: 2, color: _tIsNum(pr) && pr >= 0 ? "var(--pos-fg)" : "var(--neg-fg)" }}>{_tIsNum(pr) ? fmt.sPct(pr) : "—"}</div>
          </div>
          <div style={{ width: 1, background: "var(--border-1)" }} />
          <div style={{ flex: 1, minWidth: 110, padding: "11px 13px" }}>
            <div className="kpi-label" style={{ fontSize: 10 }}>{benchName}</div>
            <div className="mono" style={{ fontSize: 17, fontWeight: 600, marginTop: 2, color: _tIsNum(br) && br >= 0 ? "var(--pos-fg)" : "var(--neg-fg)" }}>{benchAvailable && _tIsNum(br) ? fmt.sPct(br) : "—"}</div>
          </div>
          <div style={{ width: 1, background: "var(--border-1)" }} />
          <div style={{ flex: 1, minWidth: 110, padding: "11px 13px" }}>
            <div className="kpi-label" style={{ fontSize: 10 }}>Alpha</div>
            <div className="mono" style={{ fontSize: 19, fontWeight: 700, marginTop: 1, color: alphaNeg ? "var(--neg-fg)" : "var(--pos-fg)" }}>{_tIsNum(alpha) ? fmt.sPct(alpha) : "—"}</div>
          </div>
        </Row>
      )}
      {summary && summary.verdict && port.length >= 2 && (
        <p className="muted" style={{ fontSize: 13, lineHeight: 1.55, margin: "12px 0 0" }}>{summary.verdict}</p>
      )}
    </Card>
  );
}

/* ── HEUTE screen ─────────────────────────────────────────────────────────── */
function Today({ theme, onNavigate, onOpenStock, onOpenHermes }) {
  const feed = useAsync(() => API.feed(), []);
  const [dismissing, setDismissing] = useState(null);

  const data = feed.data || {};
  const verdict = data.verdict || null;
  const actions = _tArr(data.actions);
  const changes = _tArr(data.changes);
  const foresight = _tArr(data.foresight);
  const quiet = data.quiet === true || (!verdict && actions.length === 0 && changes.length === 0 && foresight.length === 0);

  const tone = (verdict && VERDICT_TONE[verdict.level]) || VERDICT_TONE.amber;

  const dismiss = async (id) => {
    if (!id) return;
    setDismissing(id);
    try { await API.feedDismiss(id); } catch {}
    setDismissing(null);
    feed.reload();
  };

  return (
    <div className="rise">
      <PageHeader
        title="Heute"
        subtitle={feed.data && feed.data.as_of ? `${fmt.date(feed.data.as_of)} · was heute zählt` : "Dein täglicher Überblick"}
        actions={<>
          <button className="btn btn-sm" onClick={() => feed.reload()} disabled={feed.loading}>
            <Icon name="refresh-cw" size={13} className={feed.loading ? "spin" : ""} /> Aktualisieren
          </button>
          <button className="btn btn-sm" onClick={() => onOpenHermes()}><Icon name="sparkles" size={13} /> Hermes fragen</button>
        </>}
      />

      {feed.loading ? (
        <Col gap={16}>
          <SkelCard lines={2} />
          <SkelCard lines={3} />
          <SkelCard lines={3} />
        </Col>
      ) : feed.error ? (
        <Card><EmptyState icon="cloud-off" title="Konnte den Tagesfeed nicht laden" body={feed.error.message} action={<button className="btn btn-sm" onClick={() => feed.reload()}><Icon name="refresh-cw" size={13} /> Erneut versuchen</button>} /></Card>
      ) : (
        <Col gap={16}>
          {/* Verdict / Ampel */}
          {verdict ? (
            <div className="card" style={{ borderLeft: `4px solid ${tone.accent}`, background: tone.soft }}>
              <Row gap={13} align="flex-start">
                <span className="dot" style={{ background: tone.dot, width: 14, height: 14, marginTop: 6, flexShrink: 0 }} />
                <div style={{ flex: 1, minWidth: 0 }}>
                  <div style={{ fontSize: 20, fontWeight: 600, letterSpacing: "-0.01em", lineHeight: 1.3 }}>{verdict.headline || "—"}</div>
                  {_tArr(verdict.stats).length > 0 && (
                    <Row gap={8} wrap style={{ marginTop: 12 }}>
                      {_tArr(verdict.stats).map((st, i) => (
                        <span key={i} className="chip" style={{ background: "var(--bg-surface)", border: "1px solid var(--border-1)", padding: "4px 11px", fontSize: 12.5 }}>
                          <span className="muted" style={{ marginRight: 6 }}>{st.label}</span>
                          <span className="mono" style={{ fontWeight: 600 }}>{st.value}</span>
                        </span>
                      ))}
                    </Row>
                  )}
                </div>
              </Row>
            </div>
          ) : quiet ? (
            <Card>
              <Col gap={10} align="center" style={{ padding: "32px 20px", textAlign: "center" }}>
                <div style={{ fontSize: 34, lineHeight: 1 }}>🌿</div>
                <div style={{ fontWeight: 600, fontSize: 16 }}>Heute ist nichts zu tun.</div>
                <div className="muted" style={{ fontSize: 13, maxWidth: 360 }}>Kein dringendes Ereignis seit gestern. Lehn dich zurück — Meridian meldet sich, wenn etwas Wichtiges passiert.</div>
              </Col>
            </Card>
          ) : null}

          {/* Effectiveness panel (near the top) */}
          <EffectivenessChart theme={theme} />

          {/* Handeln / Prüfen */}
          {actions.length > 0 && (
            <div>
              <SectionTitle icon="alert-triangle">Handeln / Prüfen</SectionTitle>
              <Col gap={12}>
                {actions.map((ev, i) => (
                  <ActionCard key={ev.id || i} ev={ev} onOpenStock={onOpenStock} onOpenHermes={onOpenHermes} onDismiss={dismiss} busy={dismissing === ev.id} />
                ))}
              </Col>
            </div>
          )}

          {/* Neu seit gestern */}
          {changes.length > 0 && (
            <Card>
              <SectionTitle icon="history">Neu seit gestern</SectionTitle>
              <Col gap={2}>
                {changes.map((ev, i) => <ChangeRow key={ev.id || i} ev={ev} onOpenStock={onOpenStock} first={i === 0} />)}
              </Col>
            </Card>
          )}

          {/* Diese Woche (Foresight) */}
          {foresight.length > 0 && (
            <Card>
              <SectionTitle icon="calendar-clock" action={<button className="btn btn-sm btn-ghost" onClick={() => onNavigate("overview")}>Kalender <Icon name="arrow-right" size={12} /></button>}>Diese Woche</SectionTitle>
              <Col gap={2}>
                {foresight.map((ev, i) => <ForesightRow key={ev.id || i} ev={ev} onOpenStock={onOpenStock} first={i === 0} />)}
              </Col>
            </Card>
          )}

          {/* Quiet but a verdict was present — gentle closer so it never looks empty */}
          {!quiet && actions.length === 0 && changes.length === 0 && foresight.length === 0 && (
            <Card>
              <Col gap={10} align="center" style={{ padding: "28px 20px", textAlign: "center" }}>
                <div style={{ fontSize: 30, lineHeight: 1 }}>🌿</div>
                <div style={{ fontWeight: 600, fontSize: 15 }}>Keine offenen Punkte heute.</div>
              </Col>
            </Card>
          )}
        </Col>
      )}
    </div>
  );
}

window.EffectivenessChart = EffectivenessChart;
window.Today = Today;

Object.assign(window, { Today, EffectivenessChart });
