const { useState: useStateL, useEffect: useEffectL, useMemo: useMemoL } = React;
const {
  IconSearch, IconHistogram, IconChart, IconSql, IconRefresh, IconHelp,
  IconSave, IconShare, IconMenu, IconPlus, IconExpand, IconCaretRight, IconCopy,
  IconClock, IconFx, IconCircle, IconDot, IconChevDown, IconChevRight,
  IconChevsLeft, IconChevsRight, IconChevLeft, IconInfo, IconArrowUp, IconBolt,
  IconPattern, IconHourglass, IconWarnTri, IconEq, IconNeq, IconX, IconGear,
} = window.Icons;

const { HIST_BARS, HIST_TIMES, FIELDS, LOG_ROWS_DEFAULT, LOG_ROWS_SQL, PATTERNS } = window.Data;
const SourceDetailsDrawerL = window.SourceDetailsDrawer;

// ─── Wrench (settings/tools) glyph used as a mode toggle
function IconWrench({ size = 14, sw = 1.6 }) {
  return (
    <svg width={size} height={size} viewBox="0 0 24 24" fill="none"
         stroke="currentColor" strokeWidth={sw} strokeLinecap="round" strokeLinejoin="round">
      <path d="M14 4a4 4 0 0 1 5.5 5.5L9 20l-5 1 1-5L15.5 5.5"/>
      <path d="m14 6 4 4"/>
    </svg>
  );
}

// ─── Toolbar — view-mode segmented + toggles + right cluster (Run query)
// Strictly matches the screenshot button set.
function LogsToolbar({ viewMode, onViewMode, sqlOn, onToggleSql,
                       histogramOn, onToggleHistogram, fnOn, onToggleFn,
                       running, onRun }) {
  const Mode = ({ k, Ico, title }) => {
    const active = viewMode === k;
    return (
      <button title={title} onClick={() => onViewMode(k)}
        className="icon-btn bordered"
        style={{
          background: active ? "var(--accent-dark)" : "var(--surface)",
          color: active ? "white" : "var(--ink-2)",
          borderColor: active ? "var(--accent-dark)" : "var(--border)",
        }}>
        <Ico size={14} sw={1.6}/>
      </button>
    );
  };
  return (
    <div style={{
      height: 44, flexShrink: 0,
      display: "flex", alignItems: "center", gap: 6,
      padding: "0 12px",
      background: "var(--canvas)",
      borderBottom: "1px solid var(--border)",
    }}>
      {/* Left: view-mode segmented */}
      <Mode k="list"    Ico={IconSearch}    title="Logs" />
      <Mode k="chart"   Ico={IconChart}     title="Chart" />
      <Mode k="vrl"     Ico={IconWrench}    title="VRL function editor" />
      <Mode k="pattern" Ico={IconPattern}   title="Patterns" />

      <div style={{ width: 1, height: 18, background: "var(--border)", margin: "0 2px" }} />

      {/* Histogram on/off (switch + bar-chart icon) */}
      <div className={`switch ${histogramOn ? "on" : ""}`} onClick={onToggleHistogram} />
      <button className="icon-btn bordered" title="Show histogram"
              onClick={onToggleHistogram}
              style={{
                background: histogramOn ? "var(--accent-bg)" : "var(--surface)",
                color: histogramOn ? "var(--accent-fg)" : "var(--ink-2)",
                borderColor: histogramOn ? "var(--accent-line)" : "var(--border)",
              }}>
        <IconHistogram size={14} />
      </button>

      {/* SQL mode on/off (switch + SQL icon) */}
      <div className={`switch ${sqlOn ? "on" : ""}`} onClick={onToggleSql} />
      <button className="icon-btn bordered" title="SQL mode" onClick={onToggleSql}
              style={{
                background: sqlOn ? "var(--accent-bg)" : "var(--surface)",
                color: sqlOn ? "var(--accent-fg)" : "var(--ink-2)",
                borderColor: sqlOn ? "var(--accent-line)" : "var(--border)",
              }}>
        <IconSql size={14} />
      </button>

      <button className="icon-btn bordered" title="Save view"><IconSave size={14} /></button>
      <button className="icon-btn bordered" title="Refresh">
        <IconRefresh size={14} />
        <IconChevDown size={9} style={{ marginLeft: -1 }}/>
      </button>
      <button className="icon-btn bordered" title="More"><IconMenu size={14} /></button>

      <div style={{ flex: 1 }} />

      {/* Function editor on/off (switch + fx) */}
      <div className={`switch ${fnOn ? "on" : ""}`} onClick={onToggleFn} />
      <button className="icon-btn bordered" title="Function editor"
              onClick={onToggleFn}
              style={{
                background: fnOn ? "var(--accent-bg)" : "var(--surface)",
                color: fnOn ? "var(--accent-fg)" : "var(--ink-2)",
                borderColor: fnOn ? "var(--accent-line)" : "var(--border)",
              }}>
        <IconFx size={13} />
        <IconChevDown size={9} style={{ marginLeft: -1 }}/>
      </button>

      <button className="icon-btn bordered" title="Save function"><IconSave size={14} /></button>

      <div style={{ width: 1, height: 18, background: "var(--border)", margin: "0 2px" }} />

      <button className="btn">
        <IconClock size={13} />
        <span>Past 3 Days</span>
        <IconChevDown size={12} />
      </button>

      <button className="btn-primary" onClick={onRun} disabled={running}
              style={{
                opacity: running ? 0.85 : 1,
                background: running ? "var(--muted)" : "var(--go)",
                borderColor: running ? "var(--muted)" : "var(--go)",
                padding: "0 12px 0 14px",
              }}>
        {running
          ? <span className="mono" style={{ display: "inline-flex", alignItems: "center", gap: 6 }}>
              <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="white" strokeWidth="2.4" strokeLinecap="round"
                   style={{ animation: "spin 1s linear infinite" }}>
                <path d="M21 12a9 9 0 1 1-3-6.7" />
              </svg>
              Running
            </span>
          : <>Run query<IconChevDown size={12} /></>
        }
      </button>

      <button className="icon-btn bordered" title="Refresh"><IconRefresh size={14} /></button>
      <button className="icon-btn bordered" title="Share"><IconShare size={13} /></button>
      <button className="icon-btn bordered" title="More options"><IconMenu size={13} /></button>
    </div>
  );
}

// ─── Query Editor row (becomes single column when fn editor is off)
function EditorRow({ sqlOn, fnOn, queryText, onQueryChange }) {
  const cols = fnOn ? "1fr 1fr" : "1fr";
  return (
    <div style={{
      flexShrink: 0,
      display: "grid", gridTemplateColumns: cols, gap: 0,
      background: "var(--surface)",
      borderBottom: "1px solid var(--border)",
    }}>
      <div style={{ padding: "10px 14px 12px", borderRight: fnOn ? "1px solid var(--border)" : "none", minHeight: 56 }}>
        <div style={{ display: "flex", alignItems: "center", gap: 8, marginBottom: 6 }}>
          <span className="mono" style={{ fontSize: 10, color: "var(--muted)" }}>1</span>
          <span style={{ fontSize: 12, color: "var(--ink-2)", fontWeight: 500 }}>Query Editor:</span>
        </div>
        {sqlOn ? (
          <input
            value={queryText}
            onChange={e => onQueryChange(e.target.value)}
            className="mono"
            spellCheck={false}
            style={{
              fontSize: 13, color: "var(--ink)", lineHeight: 1.5,
              width: "100%", border: "none", outline: "none",
              background: "transparent",
              fontFamily: "JetBrains Mono, monospace",
              padding: 0,
            }}/>
        ) : (
          <input
            placeholder="model = 'gpt-4o' AND status = 'error'"
            value={queryText}
            onChange={e => onQueryChange(e.target.value)}
            className="mono"
            spellCheck={false}
            style={{
              fontSize: 12, color: "var(--ink)",
              width: "100%", border: "none", outline: "none",
              background: "transparent",
              fontFamily: "JetBrains Mono, monospace",
              padding: 0,
            }}/>
        )}
      </div>

      {fnOn && (
        <div style={{ padding: "10px 14px 12px", minHeight: 56, position: "relative" }}>
          <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: 6 }}>
            <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
              <span className="mono" style={{ fontSize: 10, color: "var(--muted)" }}>1</span>
              <span style={{ fontSize: 12, color: "var(--ink-2)", fontWeight: 500 }}>VRL Function Editor</span>
            </div>
            <button className="icon-btn" style={{ width: 22, height: 22 }}><IconExpand size={12} /></button>
          </div>
          <div style={{ fontSize: 12, color: "var(--muted-2)", height: 18 }}>
            <span className="mono" style={{ opacity: .45 }}>.severity = downcase(.level)</span>
          </div>
        </div>
      )}
    </div>
  );
}

// ─── Parse a simple WHERE clause into a row predicate
// Supports:  body LIKE '%XYZ%'   |   "body" LIKE '%XYZ%'
//            level = 'INFO'       |   service = 'frontend'
//            agent IS NOT NULL    |   field IS NULL
//            <expr> AND <expr>    (logical AND)
function buildFilter(query) {
  if (!query || !query.trim()) return () => true;

  // Normalize
  let q = query.trim();
  // Extract WHERE clause if it's a full SQL statement
  const wm = /\bWHERE\b\s+(.+?)(?:\bORDER BY\b|\bLIMIT\b|$)/i.exec(q);
  if (wm) q = wm[1].trim();
  // Strip trailing semicolons
  q = q.replace(/;+$/, "").trim();

  // Split on AND (case-insensitive, top-level only)
  const conds = q.split(/\s+AND\s+/i).map(s => s.trim()).filter(Boolean);

  const checks = conds.map(parseCond).filter(Boolean);
  if (checks.length === 0) return () => true;

  return (row) => {
    const src = row.source || {};
    const haystack = JSON.stringify(src);
    return checks.every(check => check(src, haystack));
  };
}

function parseCond(c) {
  // body LIKE '%xyz%' OR "body" LIKE '%xyz%'
  let m = /^"?(\w+)"?\s+LIKE\s+'%([^%]*)%'$/i.exec(c);
  if (m) {
    const [_, field, value] = m;
    const re = new RegExp(escRegex(value), "i");
    return (src, haystack) => {
      const f = src[field];
      if (f != null) return re.test(String(f));
      return re.test(haystack);
    };
  }
  // field = 'value'
  m = /^"?(\w+)"?\s*=\s*'([^']*)'$/i.exec(c);
  if (m) {
    const [_, field, value] = m;
    return (src) => {
      const f = src[field];
      if (f != null) return String(f) === value;
      const haystack = JSON.stringify(src);
      return haystack.includes(value);
    };
  }
  // field != 'value'
  m = /^"?(\w+)"?\s*(!=|<>)\s*'([^']*)'$/i.exec(c);
  if (m) {
    const [_, field, _op, value] = m;
    return (src) => {
      const f = src[field];
      if (f == null) return true;
      return String(f) !== value;
    };
  }
  // field IS NOT NULL
  m = /^"?(\w+)"?\s+IS\s+NOT\s+NULL$/i.exec(c);
  if (m) {
    const [_, field] = m;
    return (src) => src[field] != null;
  }
  // field IS NULL
  m = /^"?(\w+)"?\s+IS\s+NULL$/i.exec(c);
  if (m) {
    const [_, field] = m;
    return (src) => src[field] == null;
  }
  // Fallback: plain free-text against the whole row
  const re = new RegExp(escRegex(c), "i");
  return (src, haystack) => re.test(haystack);
}

function escRegex(s) {
  return String(s).replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}

// ─── Stream selector header
function StreamHeader({ events, ms, scan, mode, patternMode, loading, patternsFound }) {
  if (patternMode && loading) {
    return null; // header is hidden while extracting
  }
  return (
    <div style={{
      height: 36, flexShrink: 0,
      display: "flex", alignItems: "center", gap: 10,
      padding: "0 16px",
      background: "var(--surface)",
      borderBottom: "1px solid var(--border)",
    }}>
      <span style={{ fontSize: 12, color: "var(--ink-2)", whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis", minWidth: 0 }}>
        {patternMode
          ? <>Showing <strong style={{ color: "var(--ink)", fontWeight: 600 }}>1</strong> to <strong style={{ color: "var(--ink)", fontWeight: 600 }}>50</strong> out of <strong className="mono" style={{ color: "var(--ink)", fontWeight: 600 }}>1,547,595</strong> events &amp; <strong style={{ color: "var(--ink)", fontWeight: 600 }}>{patternsFound}</strong> patterns found in <strong className="mono" style={{ color: "var(--ink)", fontWeight: 600 }}>3,233</strong> events in <strong className="mono" style={{ color: "var(--accent-fg)", fontWeight: 600 }}>2,228ms</strong>.</>
          : <>Showing <strong style={{ color: "var(--ink)", fontWeight: 600 }}>1</strong> to <strong style={{ color: "var(--ink)", fontWeight: 600 }}>50</strong> out of <strong className="mono" style={{ color: "var(--ink)", fontWeight: 600 }}>{events}</strong> events in <strong className="mono" style={{ color: "var(--accent-fg)", fontWeight: 600 }}>{ms}ms</strong>. <span style={{ color: "var(--muted)" }}>(Scan size: <span className="mono">{scan}</span>)</span></>
        }
      </span>

      <div style={{ flex: 1 }} />

      {/* Tabs visible on screenshot: Inspect + Insights */}
      <button className="btn-ghost" style={{ height: 22, padding: "0 6px", color: "var(--ink-2)" }}>
        <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round"><circle cx="11" cy="11" r="6.5"/><path d="m16 16 4.5 4.5"/></svg>
        Inspect
      </button>
      <button className="btn-ghost" style={{ height: 22, padding: "0 6px", color: "var(--ink-2)" }}>
        <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round"><path d="M3 12h4l3-7 4 14 3-7h4"/></svg>
        Insights
      </button>
      <button className="icon-btn bordered" title="Column settings" style={{ width: 24, height: 24 }}>
        <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6">
          <rect x="3" y="4" width="6" height="16" rx="1"/><rect x="11" y="4" width="4" height="16" rx="1"/><rect x="17" y="4" width="4" height="16" rx="1"/>
        </svg>
      </button>
    </div>
  );
}

// ─── Field sidebar (otel_demo stream + search + collapsible field list)
function FieldSidebar({ streamName = "ai_inference" }) {
  return (
    <aside style={{
      width: 260, flexShrink: 0,
      borderRight: "1px solid var(--border)",
      display: "flex", flexDirection: "column", minHeight: 0,
      background: "var(--surface)",
    }}>
      {/* Stream selector */}
      <div style={{ padding: "10px 12px" }}>
        <div className="btn" style={{
          width: "100%", justifyContent: "space-between",
          height: 32, background: "var(--canvas)",
        }}>
          <span style={{ fontSize: 12.5 }}>{streamName}</span>
          <IconChevDown size={12} style={{ color: "var(--muted)" }}/>
        </div>
      </div>

      {/* Search */}
      <div style={{
        padding: "0 12px 8px", borderBottom: "1px solid var(--border)",
      }}>
        <div style={{
          display: "flex", alignItems: "center", gap: 8,
          padding: "6px 10px",
          background: "var(--canvas)", border: "1px solid var(--border)", borderRadius: 6,
        }}>
          <IconSearch size={13} style={{ color: "var(--muted)" }} />
          <input placeholder="Search for a field"
            style={{
              border: "none", outline: "none", background: "transparent",
              fontSize: 12, color: "var(--ink)", flex: 1,
              fontFamily: "inherit",
            }}/>
        </div>
      </div>

      {/* Field list */}
      <div style={{ flex: 1, overflowY: "auto" }}>
        {FIELDS.map((f, i) => (
          <div key={f.name} style={{
            display: "flex", alignItems: "center", gap: 6,
            padding: "5px 12px", fontSize: 12, color: "var(--ink-2)",
            cursor: "pointer",
            background: f.name === "body" ? "var(--accent-bg)" : "transparent",
          }}
            onMouseEnter={e => { if (f.name !== "body") e.currentTarget.style.background = "var(--rail)"; }}
            onMouseLeave={e => { if (f.name !== "body") e.currentTarget.style.background = "transparent"; }}>
            {f.expand ? <IconChevRight size={11} style={{ color: "var(--muted-2)" }} /> : <span style={{ width: 11 }}/>}
            <span style={{ fontSize: 9, color: "var(--muted)", fontWeight: 600, width: 14, textAlign: "center" }}>
              {f.type === "num" ? "#" : f.type === "ts" ? "◷" : "Aa"}
            </span>
            <span style={{ flex: 1, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>
              {f.name}
            </span>
          </div>
        ))}
      </div>

      {/* Pagination */}
      <div style={{
        height: 38, borderTop: "1px solid var(--border)",
        display: "flex", alignItems: "center", justifyContent: "center",
        padding: "0 12px", gap: 2,
      }}>
        <button className="icon-btn" style={{ width: 22, height: 22 }}><IconChevsLeft size={11} /></button>
        {[1,2,3].map(n => (
          <button key={n} className={n === 1 ? "icon-btn active bordered" : "icon-btn"}
            style={{ width: 22, height: 22, fontSize: 11, fontWeight: n === 1 ? 600 : 500, borderRadius: 4 }}>
            {n}
          </button>
        ))}
        <button className="icon-btn" style={{ width: 22, height: 22 }}><IconChevsRight size={11} /></button>
        <div style={{ flex: 1 }}/>
        <button className="icon-btn" style={{ width: 22, height: 22 }}><IconRefresh size={11} /></button>
      </div>
    </aside>
  );
}

// ─── Histogram (uses palette tokens, with hover tooltip)
function Histogram() {
  const max = Math.max(...HIST_BARS);
  const [hoverIdx, setHoverIdx] = useStateL(null);
  const total = HIST_BARS.reduce((a, b) => a + b, 0);
  return (
    <div style={{ padding: "12px 16px 8px", borderBottom: "1px solid var(--border)", background: "var(--surface)" }}>
      <div style={{ display: "flex", gap: 12, alignItems: "stretch" }}>
        <div style={{
          width: 36, flexShrink: 0,
          display: "flex", flexDirection: "column", justifyContent: "space-between",
          padding: "2px 0", textAlign: "right",
        }}>
          {[max, Math.round(max/2), 0].map((v, i) => (
            <span key={i} className="mono" style={{ fontSize: 10, color: "var(--muted)" }}>
              {v.toLocaleString()}
            </span>
          ))}
        </div>
        <div style={{ flex: 1, display: "flex", flexDirection: "column", minWidth: 0, position: "relative" }}
             onMouseLeave={() => setHoverIdx(null)}>
          <div style={{
            height: 110, display: "flex", alignItems: "flex-end", gap: 1.5,
            borderBottom: "1px solid var(--border)",
            position: "relative",
          }}>
            {HIST_BARS.map((v, i) => (
              <div key={i} className="hist-bar"
                onMouseEnter={() => setHoverIdx(i)}
                style={{
                  flex: 1, height: `${(v / max) * 100}%`,
                  background: hoverIdx === i ? "var(--accent)" : "var(--hist)",
                  borderRadius: "2px 2px 0 0",
                  opacity: hoverIdx !== null && hoverIdx !== i ? 0.55 : 0.95,
                  cursor: "pointer",
                  transition: "background .12s, opacity .12s",
              }}/>
            ))}
            {hoverIdx !== null && (
              <div style={{
                position: "absolute",
                left: `${(hoverIdx / HIST_BARS.length) * 100}%`,
                bottom: "100%",
                transform: "translate(-50%, -6px)",
                background: "var(--ink)",
                color: "var(--canvas)",
                padding: "6px 10px",
                borderRadius: 6,
                fontSize: 11, fontFamily: "JetBrains Mono",
                pointerEvents: "none",
                whiteSpace: "nowrap",
                boxShadow: "0 4px 12px rgba(0,0,0,0.15)",
                zIndex: 5,
              }}>
                <div style={{ color: "var(--muted-2)", fontSize: 10, marginBottom: 2 }}>
                  {tsForBin(hoverIdx)}
                </div>
                <div style={{ display: "flex", gap: 8, alignItems: "center" }}>
                  <span style={{
                    width: 7, height: 7, borderRadius: 2,
                    background: "var(--accent-2)",
                  }}/>
                  <strong style={{ fontWeight: 600 }}>{HIST_BARS[hoverIdx].toLocaleString()}</strong>
                  <span style={{ color: "var(--muted-2)" }}>events</span>
                </div>
                <div style={{ fontSize: 10, color: "var(--muted-2)", marginTop: 2 }}>
                  {((HIST_BARS[hoverIdx] / total) * 100).toFixed(1)}% of window
                </div>
              </div>
            )}
          </div>
          <div style={{
            display: "flex", justifyContent: "space-between",
            padding: "5px 0 0",
          }}>
            {HIST_TIMES.map(t => (
              <span key={t} className="mono" style={{ fontSize: 10, color: "var(--muted)" }}>{t}</span>
            ))}
          </div>
        </div>
      </div>
    </div>
  );
}

function tsForBin(i) {
  // 74 bars across ~12 minutes (11:44 -> 11:56) → ~10s/bin
  const startMin = 11 * 60 + 44;
  const totalSec = i * 10;
  const m = Math.floor(startMin + totalSec / 60);
  const s = totalSec % 60;
  return `2025-11-14 ${String(Math.floor(m / 60)).padStart(2, "0")}:${String(m % 60).padStart(2, "0")}:${String(s).padStart(2, "0")}`;
}

// ─── Render a pattern template into JSX with variable chips
function renderTemplate(tmpl) {
  // Split on the literal chip markers, preserving them
  const parts = tmpl.split(/(\s%TS%\s|%TS%|\s%ID%\s|%ID%|\s%IP%\s|%IP%|\s%_%\s|%_%)/g);
  return parts.filter(p => p !== "").map((p, i) => {
    const trimmed = p.trim();
    if (trimmed === "%TS%") return <Chip key={i} label="<:TIMESTAMP>" tone="purple" />;
    if (trimmed === "%ID%") return <Chip key={i} label="<:UUID>"      tone="purple" />;
    if (trimmed === "%IP%") return <Chip key={i} label="<:IPV4>"      tone="purple" />;
    if (trimmed === "%_%")  return <Chip key={i} label="<*>"          tone="purple-soft" />;
    return <span key={i}>{p}</span>;
  });
}

function Chip({ label, tone = "purple" }) {
  const palette = {
    "purple":      { bg: "#E6E2FA", fg: "#5640B0", bd: "#C9C0EE" },
    "purple-soft": { bg: "#EDEAF8", fg: "#7165B5", bd: "#D9D2EC" },
  };
  const c = palette[tone] || palette.purple;
  return (
    <span className="mono" style={{
      display: "inline-block", padding: "1px 6px", margin: "0 1px",
      background: c.bg, color: c.fg, border: `1px solid ${c.bd}`,
      borderRadius: 3, fontSize: 11, fontWeight: 500,
      lineHeight: "16px", verticalAlign: "baseline",
    }}>{label}</span>
  );
}

// ─── Pattern table
function PatternTable({ onPick }) {
  return (
    <div style={{ flex: 1, overflow: "auto", background: "var(--surface)" }}>
      {/* column header */}
      <div style={{
        display: "grid", gridTemplateColumns: "1fr 90px 90px 120px",
        padding: "10px 14px",
        background: "var(--canvas)",
        borderBottom: "1px solid var(--border)",
        fontSize: 11, fontWeight: 600, color: "var(--ink-2)",
        position: "sticky", top: 0, zIndex: 1,
      }}>
        <div>Pattern</div>
        <div style={{ textAlign: "right" }}>Count</div>
        <div style={{ textAlign: "right" }}>%</div>
        <div></div>
      </div>
      {PATTERNS.map((p, i) => (
        <div key={p.id} onClick={() => onPick(i)}
          style={{
            display: "grid", gridTemplateColumns: "1fr 90px 90px 120px",
            padding: "10px 14px",
            borderBottom: "1px solid var(--border)",
            cursor: "pointer",
            background: i % 2 === 0 ? "transparent" : "var(--canvas)",
            alignItems: "start",
          }}
          onMouseEnter={e => e.currentTarget.style.background = "var(--accent-bg)"}
          onMouseLeave={e => e.currentTarget.style.background = i % 2 === 0 ? "transparent" : "var(--canvas)"}>
          <div className="mono" style={{
            fontSize: 12, color: "var(--ink)", lineHeight: 1.7,
            wordBreak: "break-word", paddingRight: 10,
          }}>
            {renderTemplate(p.template)}
            {p.rare && (
              <div style={{
                display: "flex", alignItems: "center", gap: 4, marginTop: 4,
                fontSize: 11, color: "var(--warn)", fontWeight: 500,
              }}>
                <IconWarnTri size={11}/> Rare Pattern
              </div>
            )}
          </div>
          <div className="mono" style={{ textAlign: "right", fontSize: 12, color: "var(--ink)", fontWeight: 500 }}>
            {p.count.toLocaleString()}
          </div>
          <div className="mono" style={{ textAlign: "right", fontSize: 12, color: "var(--ink)", fontWeight: 500 }}>
            {p.pct}%
          </div>
          <div style={{ display: "flex", gap: 4, justifyContent: "flex-end", alignItems: "center" }}>
            <button className="icon-btn" title="Filter is" onClick={e => e.stopPropagation()}
                    style={{ width: 22, height: 22, color: "var(--muted)" }}>
              <IconEq size={12}/>
            </button>
            <button className="icon-btn" title="Filter is not" onClick={e => e.stopPropagation()}
                    style={{ width: 22, height: 22, color: "var(--muted)" }}>
              <IconNeq size={12}/>
            </button>
            <button className="icon-btn" title="Details"
                    onClick={e => { e.stopPropagation(); onPick(i); }}
                    style={{ width: 22, height: 22, color: p.rare ? "var(--warn)" : "var(--muted)" }}>
              <IconInfo size={12}/>
            </button>
          </div>
        </div>
      ))}
    </div>
  );
}

// ─── Pattern Details drawer — Statistics / Variables / Template / Examples
function PatternDetails({ index, onClose, onPrev, onNext }) {
  const { Drawer, DrawerHeader } = window;
  const p = index !== null ? PATTERNS[index] : null;
  if (!p) return null;
  const examples = p.examples && p.examples.length > 0 ? p.examples : [];
  return (
    <Drawer open={true} onClose={onClose} width={1120}>
      <DrawerHeader title="Pattern Details" subtitle={`Pattern ${index + 1} of ${PATTERNS.length}`} onClose={onClose}/>

      {/* Body */}
      <div style={{ flex: 1, overflowY: "auto", padding: "16px 24px 24px" }}>
        {/* Statistics */}
        <div style={{ fontSize: 13, fontWeight: 600, color: "var(--ink)", marginBottom: 10 }}>
          Statistics
        </div>
        <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 14 }}>
          <StatBig label="Occurrences" value={p.count.toLocaleString()} />
          <StatBig label="Percentage"  value={`${p.pct}%`} />
        </div>

        {/* Anomaly banner */}
        {p.rare && (
          <div style={{ marginTop: 18 }}>
            <div style={{
              display: "flex", alignItems: "center", gap: 8,
              color: "var(--err)", fontSize: 16, fontWeight: 600,
            }}>
              <IconWarnTri size={18}/> Anomaly Detected
            </div>
            <div style={{ fontSize: 12, color: "var(--ink-2)", marginTop: 2 }}>
              This pattern is detected as a rare pattern ({p.pct}% of logs, {p.count} occurrences)
            </div>
          </div>
        )}

        {/* Variables */}
        <div style={{ fontSize: 13, fontWeight: 600, color: "var(--ink)", marginTop: 18, marginBottom: 6 }}>
          Variables
        </div>
        <div style={{
          padding: "10px 14px",
          background: "var(--canvas)",
          borderLeft: "3px solid var(--accent)",
          borderRadius: 4,
          fontSize: 13, color: "var(--ink-2)",
        }}>
          {p.varCount || 3} variable(s) detected
        </div>

        {/* Pattern Template */}
        <div style={{ fontSize: 13, fontWeight: 600, color: "var(--ink)", marginTop: 18, marginBottom: 6 }}>
          Pattern Template
        </div>
        <div className="mono" style={{
          padding: "10px 14px",
          background: "var(--canvas)", border: "1px solid var(--border)", borderRadius: 4,
          fontSize: 13, lineHeight: 1.8, wordBreak: "break-word",
        }}>
          {renderTemplate(p.template)}
        </div>

        {/* Example Logs */}
        <div style={{ fontSize: 13, fontWeight: 600, color: "var(--ink)", marginTop: 18, marginBottom: 6 }}>
          Example Logs ({examples.length})
        </div>
        {examples.length === 0 && (
          <div style={{
            padding: 18, color: "var(--muted)", fontSize: 12, textAlign: "center",
            border: "1px dashed var(--border)", borderRadius: 4,
          }}>
            No examples cached. Run the query to fetch sample log lines.
          </div>
        )}
        {examples.map((ex, i) => (
          <div key={i} className="mono" style={{
            padding: "10px 14px", marginTop: 8,
            background: "var(--canvas)", border: "1px solid var(--border)", borderRadius: 4,
            fontSize: 12, lineHeight: 1.6, wordBreak: "break-all",
            color: "var(--ink)",
          }}>
            {ex}
          </div>
        ))}
      </div>

      {/* Footer pager */}
      <div style={{
        height: 56, flexShrink: 0,
        borderTop: "1px solid var(--border)",
        display: "flex", alignItems: "center", justifyContent: "space-between",
        padding: "0 24px",
        background: "var(--canvas)",
      }}>
        <button className="btn" disabled={index === 0} onClick={onPrev}
                style={{ opacity: index === 0 ? 0.4 : 1, cursor: index === 0 ? "not-allowed" : "pointer" }}>
          <IconChevLeft size={13}/> Previous
        </button>
        <div className="mono" style={{ fontSize: 12, color: "var(--muted)" }}>
          {index + 1} of {PATTERNS.length}
        </div>
        <button className="btn" disabled={index === PATTERNS.length - 1} onClick={onNext}
                style={{ opacity: index === PATTERNS.length - 1 ? 0.4 : 1 }}>
          Next <IconChevRight size={13}/>
        </button>
      </div>
    </Drawer>
  );
}

function StatBig({ label, value }) {
  return (
    <div style={{
      padding: "14px 16px",
      background: "var(--canvas)", border: "1px solid var(--border)", borderRadius: 6,
    }}>
      <div style={{ fontSize: 11, color: "var(--muted)", marginBottom: 2 }}>{label}</div>
      <div className="mono" style={{ fontSize: 26, fontWeight: 600, color: "var(--accent)", letterSpacing: "-0.01em" }}>
        {value}
      </div>
    </div>
  );
}

// ─── Pattern loading state
function PatternLoading() {
  return (
    <div style={{
      flex: 1, display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center",
      gap: 12, color: "var(--muted)", padding: 40,
    }}>
      <IconHourglass size={36} sw={1.2} />
      <div style={{ fontSize: 13 }}>Extracting patterns from logs...</div>
    </div>
  );
}

// ─── JSON-source coloring for log rows
function highlightSource(obj) {
  const parts = [];
  parts.push(<span key="ob" style={{ color: "var(--muted)" }}>{"{"}</span>);
  const keys = Object.keys(obj);
  keys.forEach((k, i) => {
    const v = obj[k];
    parts.push(<span key={`k${i}`} className="lg-key">"{k}"</span>);
    parts.push(<span key={`c${i}`} style={{ color: "var(--muted)" }}>: </span>);
    if (typeof v === "number") {
      parts.push(<span key={`v${i}`} className="lg-num">{v}</span>);
    } else {
      const sv = String(v);
      parts.push(
        <span key={`v${i}`} className="lg-str">
          "{sv.split(/(\bINFO\b|\bWARN\b|\bERROR\b)/).map((chunk, idx) =>
            /\b(INFO|WARN|ERROR)\b/.test(chunk)
              ? <span key={idx} className={chunk === "INFO" ? "lg-info" : chunk === "WARN" ? "lg-warn" : "lg-err"}>{chunk}</span>
              : <span key={idx}>{chunk}</span>
          )}"
        </span>
      );
    }
    if (i < keys.length - 1) parts.push(<span key={`s${i}`} style={{ color: "var(--muted)" }}>, </span>);
  });
  parts.push(<span key="cb" style={{ color: "var(--muted)" }}>{"}"}</span>);
  return parts;
}

// ─── Expanded log detail — full JSON tree with Copy + View Related actions
function LogRowDetail({ row, onOpenSource }) {
  const [copied, setCopied] = useStateL(false);
  function handleCopy() {
    const json = JSON.stringify(row.source, null, 2);
    if (navigator.clipboard) navigator.clipboard.writeText(json);
    setCopied(true);
    setTimeout(() => setCopied(false), 1400);
  }
  return (
    <div style={{
      borderTop: "1px solid var(--accent-line)",
      borderBottom: "1px solid var(--accent-line)",
      background: "var(--surface)",
      padding: "0 16px 16px 32px",
    }}>
      {/* Action row */}
      <div style={{ display: "flex", gap: 8, padding: "10px 0 12px" }}>
        <button className="btn" style={{ height: 26, padding: "0 10px", fontSize: 12 }}
                onClick={e => { e.stopPropagation(); handleCopy(); }}>
          {copied ? (
            <>
              <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="var(--ok)" strokeWidth="2.4" strokeLinecap="round" strokeLinejoin="round"><path d="M5 13l5 5 9-11"/></svg>
              <span style={{ color: "var(--ok)" }}>Copied</span>
            </>
          ) : (
            <>
              <IconCopy size={11}/>
              <span>Copy to clipboard</span>
            </>
          )}
        </button>
        <button className="btn" style={{ height: 26, padding: "0 10px", fontSize: 12, color: "var(--accent-fg)", borderColor: "var(--accent-line)", background: "var(--accent-bg)" }}
                onClick={e => { e.stopPropagation(); onOpenSource(row.source); }}>
          <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round"><path d="M10 14 6 14 a4 4 0 1 1 4-4M14 10h4a4 4 0 1 1-4 4M8 12h8"/></svg>
          <span>View Related</span>
        </button>
      </div>

      {/* JSON tree */}
      <pre className="mono" style={{
        margin: 0, fontSize: 12, lineHeight: 1.7, color: "var(--ink-2)",
        whiteSpace: "pre-wrap", wordBreak: "break-word",
      }}>
        <span style={{ color: "var(--muted)" }}>{"{"}</span>{"\n"}
        {Object.entries(row.source).map(([k, v], i, arr) => (
          <span key={k}>
            {"  "}<span style={{ color: "var(--ink-2)", display: "inline-block", width: 10 }}>▾</span>{" "}
            <span className="lg-key">{k}</span>
            <span style={{ color: "var(--muted)" }}>: </span>
            <span style={{
              color: typeof v === "number" ? "oklch(0.50 0.11 180)" : "var(--err)",
            }}>{typeof v === "string" ? v : String(v)}</span>
            {i < arr.length - 1 ? "," : ""}{"\n"}
          </span>
        ))}
        <span style={{ color: "var(--muted)" }}>{"}"}</span>
      </pre>
    </div>
  );
}

// ─── Log table — click row expands inline; View Related opens drawer
function LogTable({ rows, onOpenSource }) {
  const [openIdx, setOpenIdx] = useStateL(null);
  return (
    <div style={{ flex: 1, overflow: "auto", background: "var(--surface)" }}>
      <table style={{ width: "100%", borderCollapse: "collapse", tableLayout: "fixed" }}>
        <colgroup>
          <col style={{ width: 30 }} />
          <col style={{ width: 160 }} />
          <col />
        </colgroup>
        <thead>
          <tr style={{ background: "var(--canvas)" }}>
            <th></th>
            <th style={{
              textAlign: "left", padding: "8px 10px",
              fontSize: 11, fontWeight: 600, color: "var(--ink-2)",
              borderBottom: "1px solid var(--border)",
            }}>
              timestamp <span style={{ color: "var(--muted)", fontWeight: 400 }}>(Asia/Calcutta)</span>
            </th>
            <th style={{
              textAlign: "left", padding: "8px 10px",
              fontSize: 11, fontWeight: 600, color: "var(--ink-2)",
              borderBottom: "1px solid var(--border)",
            }}>source</th>
          </tr>
        </thead>
        <tbody>
          {rows.map((row, i) => {
            const isOpen = openIdx === i;
            return (
              <React.Fragment key={i}>
                <tr onClick={() => setOpenIdx(isOpen ? null : i)} style={{
                  background: isOpen ? "var(--accent-bg)" : "transparent",
                  borderBottom: isOpen ? "none" : "1px solid var(--border)",
                  borderLeft: isOpen ? "3px solid var(--accent)" : "3px solid transparent",
                  cursor: "pointer",
                }}
                onMouseEnter={e => { if (!isOpen) e.currentTarget.style.background = "var(--rail)"; }}
                onMouseLeave={e => { if (!isOpen) e.currentTarget.style.background = "transparent"; }}>
                  <td style={{ textAlign: "center", padding: "5px 0", verticalAlign: "top" }}>
                    <span style={{ color: "var(--muted-2)", display: "inline-flex" }}>
                      <IconCaretRight size={11} style={{
                        transform: isOpen ? "rotate(90deg)" : "none",
                        transition: "transform .15s",
                      }}/>
                    </span>
                  </td>
                  <td className="mono" style={{
                    padding: "5px 10px", fontSize: 11.5, color: "var(--ink-2)",
                    whiteSpace: "nowrap", verticalAlign: "top",
                  }}>{row.date} {row.ts}</td>
                  <td className="mono" style={{
                    padding: "5px 10px", fontSize: 11.5, color: "var(--ink)",
                    lineHeight: 1.5, verticalAlign: "top",
                    overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap",
                  }}>
                    {highlightSource(row.source)}
                  </td>
                </tr>
                {isOpen && (
                  <tr style={{ borderBottom: "1px solid var(--border)", borderLeft: "3px solid var(--accent)" }}>
                    <td colSpan="3" style={{ padding: 0 }}>
                      <LogRowDetail row={row} onOpenSource={onOpenSource}/>
                    </td>
                  </tr>
                )}
              </React.Fragment>
            );
          })}
        </tbody>
      </table>
    </div>
  );
}

// ─── Main
function LogsScreen({ sqlOn, onToggleSql }) {
  const [viewMode, setViewMode] = useStateL("list");
  const [histogramOn, setHistogramOn] = useStateL(true);
  const [fnOn, setFnOn] = useStateL(true);
  const [running, setRunning] = useStateL(false);
  const [sourceOpen, setSourceOpen] = useStateL(null);

  // Live-editable query text
  const defaultSql = `SELECT * FROM "ai_inference" WHERE model = 'gpt-4o' ORDER BY _timestamp DESC LIMIT 50`;
  const defaultLog = "";
  const [queryText, setQueryText] = useStateL(sqlOn ? defaultSql : defaultLog);
  useEffectL(() => {
    setQueryText(sqlOn ? defaultSql : defaultLog);
  }, [sqlOn]);

  // Pattern extraction state
  const [patternState, setPatternState] = useStateL("idle");
  const [patternIdx, setPatternIdx] = useStateL(null);

  useEffectL(() => {
    if (viewMode === "pattern") {
      if (patternState !== "ready") {
        setPatternState("loading");
        const t = setTimeout(() => setPatternState("ready"), 1400);
        return () => clearTimeout(t);
      }
    }
  }, [viewMode]);

  const isPattern = viewMode === "pattern";
  const patternLoading = isPattern && patternState !== "ready";

  // Apply the parsed filter to the active dataset
  const baseRows = sqlOn ? LOG_ROWS_SQL : LOG_ROWS_DEFAULT;
  const filter = useMemoL(() => buildFilter(queryText), [queryText]);
  const rows = useMemoL(() => baseRows.filter(filter), [baseRows, filter]);

  const totalEvents = sqlOn ? 847219 : 1547595;
  const matchedScale = baseRows.length === 0 ? 1 : rows.length / baseRows.length;
  const events = Math.round(totalEvents * matchedScale).toLocaleString();
  const ms = queryText.trim() && queryText.trim() !== defaultSql ? Math.round(142 + Math.random() * 280) : (sqlOn ? "218" : "634");
  const scan = sqlOn ? "1.84 GB" : "3.21 GB";

  function handleRun() {
    setRunning(true);
    if (isPattern) {
      setPatternState("loading");
      setTimeout(() => { setPatternState("ready"); setRunning(false); }, 1400);
    } else {
      setTimeout(() => setRunning(false), 700);
    }
  }

  return (
    <div style={{
      flex: 1, display: "flex", flexDirection: "column", minHeight: 0,
      background: "var(--surface)", position: "relative",
    }}>
      <LogsToolbar
        viewMode={viewMode}
        onViewMode={m => { setViewMode(m); }}
        sqlOn={sqlOn} onToggleSql={onToggleSql}
        histogramOn={histogramOn} onToggleHistogram={() => setHistogramOn(v => !v)}
        fnOn={fnOn} onToggleFn={() => setFnOn(v => !v)}
        running={running} onRun={handleRun}
      />
      <EditorRow sqlOn={sqlOn} fnOn={fnOn}
                 queryText={queryText} onQueryChange={setQueryText} />
      <div style={{ flex: 1, display: "flex", minHeight: 0 }}>
        <FieldSidebar />
        <div style={{ flex: 1, display: "flex", flexDirection: "column", minHeight: 0 }}>
          <StreamHeader events={events} ms={ms} scan={scan}
                        patternMode={isPattern} loading={patternLoading}
                        patternsFound={PATTERNS.length} />
          {histogramOn && <Histogram />}
          {isPattern
            ? (patternLoading ? <PatternLoading /> : <PatternTable onPick={setPatternIdx} />)
            : (rows.length === 0
                ? <EmptyResults query={queryText}/>
                : <LogTable rows={rows} onOpenSource={setSourceOpen} />)
          }
        </div>
      </div>

      {/* Source Details drawer (shared) */}
      <SourceDetailsDrawerL open={!!sourceOpen} source={sourceOpen}
                            onClose={() => setSourceOpen(null)} />

      {/* Pattern details drawer */}
      {patternIdx !== null && (
        <PatternDetails index={patternIdx}
          onClose={() => setPatternIdx(null)}
          onPrev={() => setPatternIdx(i => Math.max(0, i - 1))}
          onNext={() => setPatternIdx(i => Math.min(PATTERNS.length - 1, i + 1))}
        />
      )}
    </div>
  );
}

function EmptyResults({ query }) {
  return (
    <div style={{
      flex: 1, display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center",
      gap: 12, color: "var(--muted)", padding: 40,
    }}>
      <IconSearch size={32} sw={1.2} />
      <div style={{ fontSize: 14, color: "var(--ink-2)" }}>No log records match your query.</div>
      <div className="mono" style={{ fontSize: 12, color: "var(--muted)", maxWidth: 600, textAlign: "center", padding: "8px 14px", background: "var(--canvas)", border: "1px solid var(--border)", borderRadius: 4 }}>
        {query}
      </div>
      <div style={{ fontSize: 12, color: "var(--muted)" }}>
        Try widening the time range or removing predicates.
      </div>
    </div>
  );
}

window.LogsScreen = LogsScreen;

// blink + spin animations
(function () {
  const styleEl = document.createElement("style");
  styleEl.textContent = `
    @keyframes blink{50%{opacity:0}}
    @keyframes spin{to{transform:rotate(360deg)}}
  `;
  document.head.appendChild(styleEl);
})();
