// <Header> — the agent page's identity strip: icon, glyphic title, the
// "swarm / hive" label row, and a slot for the status row
// (`<StatusChips>` — ../status-chips/, kept separate so this component
// has no opinion on what badges exist). Same three-column shape as the
// old `#agent-header` markup (icon · main · pills) — see the `pills`
// prop doc below for what moved into that third column and why.
// Reuses `agent.css`'s existing `.agent-header*`/`.agent-icon` rules
// (loaded globally by index.html) rather than a component-scoped
// stylesheet — no new visual language needed for the chrome itself.

// Measures its own rendered height via ResizeObserver, writes it to
// `--agent-header-real-h` (agent.css's downstream consumers —
// `.agent-status-overlay`, `.agent-main`'s scroll padding — prefer
// this over the static `--agent-header-h` guess). A static guess was
// the root cause of two "login card behind the header" reports on
// this PR (mara, live): any header content that can wrap an extra
// line breaks the guess at whatever width triggers it, and no width
// can be promised safe. Deliberately a SEPARATE var, not an overwrite
// of `--agent-header-h` in place: `.agent-header`'s own `min-height`
// also reads that var — overwriting it in place would make the
// header's own size react to its own just-measured height every
// tick, a real ResizeObserver feedback loop (confirmed live on the
// first pass of this fix). `--agent-header-h` stays the static floor;
// `--agent-header-real-h` is output-only.
import { useEffect, useRef } from 'preact/hooks';
import type { ComponentChildren } from 'preact';

// Icon 404s when the agent has no `hyperhive.icon` override (no
// bundled server-side default any more — see
// `hive_agent::web_ui::screen::serve_icon`). Ports app.js's
// `bindHeaderIconFallback` exactly: fire-and-forget load, swap to
// `/favicon.svg` on failure, `dataset.fallback` guards against a
// 404-on-the-fallback-itself loop.
function handleIconError(e: Event) {
  const img = e.currentTarget as HTMLImageElement;
  if (img.dataset.fallback) return;
  img.dataset.fallback = '1';
  img.src = '/favicon.svg';
}

export interface HeaderProps {
  label: string;
  hiveLabel?: string | null;
  /** The status/badge row (`<StatusChips>`) — lives in the
   * `.agent-header-pills` cluster now, alongside `pills` (see below),
   * not stacked as its own row under the title. */
  children?: ComponentChildren;
  /** Flyout triggers (inbox/todos/links pills, the overflow menu
   * button) — and, since this round, `children` (the status badges)
   * too, both in `.agent-header-pills`, the SAME header-level column
   * the old markup used for pills alone. First pass of this ask
   * nested pills into a row inside `.agent-header-main` instead —
   * backwards, mara corrected live: "i meant move badges to where the
   * dropdowns are, not the other way around. this way the height does
   * not change even on widescreen" — `.agent-header-main` now only
   * ever holds the title + hive-label rows, which don't wrap in
   * practice, so it stays a stable height; only this pills-cluster
   * column (already used to absorbing a variable pill count) grows to
   * fit badges+pills together. Meta-nav (`<MetaNav>`) lives in here
   * too, as a fixed-size trigger — not the old markup's inline list in
   * the title row (`<nav id="meta-links">`, docs/web-ui/agent.md). */
  pills?: ComponentChildren;
}

export function Header({ label, hiveLabel, children, pills }: HeaderProps) {
  const ref = useRef<HTMLElement>(null);

  useEffect(() => {
    const el = ref.current;
    if (!el || typeof ResizeObserver === 'undefined') return;
    // getBoundingClientRect() (not ResizeObserver's own contentRect) —
    // we want the full visual box padding+border included, the thing
    // content below the fixed header actually needs to clear, not the
    // content-box-only measurement ResizeObserver's entry defaults to.
    const ro = new ResizeObserver(() => {
      document.documentElement.style.setProperty('--agent-header-real-h', `${el.getBoundingClientRect().height}px`);
    });
    ro.observe(el);
    return () => ro.disconnect();
  }, []);

  return (
    <header class="agent-header" ref={ref}>
      <img class="agent-icon" src="icon" alt="" onError={handleIconError} />
      <div class="agent-header-main">
        <div class="agent-header-row agent-header-title-row">
          <h2 class="agent-header-title">◆ {label} ◆</h2>
        </div>
        {hiveLabel ? <div class="agent-header-row agent-hive-row">{hiveLabel}</div> : null}
      </div>
      {children || pills ? (
        <div class="agent-header-pills">
          {children}
          {pills}
        </div>
      ) : null}
    </header>
  );
}
