// TextCanvas — narrative editor surface with markup chips, headings, prose.
// Renders chips per markupStyle: "pill" | "underline" | "bracket" | "color".

const CHIP_TYPE_LABEL = {
  block: "block",
  property: "property",
  association: "assoc",
  requirement: "req",
};

function Chip({ kind, id, label, markupStyle, onHover, onClick, focused }) {
  const cls = `chip chip-${kind} chip-style-${markupStyle}${focused ? " chip-focus" : ""}`;
  const handlers = {
    onMouseEnter: () => onHover && onHover(id),
    onMouseLeave: () => onHover && onHover(null),
    onClick: () => onClick && onClick(id, kind),
  };
  if (markupStyle === "bracket") {
    return (
      <span className={cls} {...handlers}>
        <span className="chip-bracket">[</span>
        <span className="chip-kind">{CHIP_TYPE_LABEL[kind]}:</span>
        <span className="chip-label">{label}</span>
        <span className="chip-bracket">]</span>
      </span>
    );
  }
  if (markupStyle === "underline") {
    return (
      <span className={cls} {...handlers}>
        <span className="chip-glyph">{kindGlyph(kind)}</span>
        <span className="chip-label">{label}</span>
      </span>
    );
  }
  // pill (default) and color both render as filled chips, color uses kind color, pill is muted.
  return (
    <span className={cls} {...handlers}>
      <span className="chip-glyph">{kindGlyph(kind)}</span>
      <span className="chip-label">{label}</span>
    </span>
  );
}

function kindGlyph(kind) {
  switch (kind) {
    case "block": return "▢";
    case "property": return "·";
    case "association": return "→";
    case "requirement": return "§";
    default: return "·";
  }
}

function TextCanvas({ data, density, markupStyle, focusBlockId, setFocusBlockId, gutter }) {
  const padY = density === "compact" ? 10 : 18;
  return (
    <div className="text-canvas" style={{ padding: `${padY}px ${density === "compact" ? 22 : 36}px` }}>
      {gutter}
      {data.narrative.map((node, i) => {
        if (node.type === "h1") return <h1 key={i} className="t-h1">{node.text}</h1>;
        if (node.type === "h2") return <h2 key={i} className="t-h2">{node.text}</h2>;
        if (node.type === "p") {
          return (
            <p key={i} className="t-p">
              {node.children.map((c, j) => {
                if (c.t === "text") return <span key={j}>{c.v}</span>;
                if (c.t === "chip") return (
                  <Chip key={j} kind={c.kind} id={c.id} label={c.label}
                    markupStyle={markupStyle}
                    focused={focusBlockId === c.id}
                    onHover={setFocusBlockId}
                    onClick={(id) => setFocusBlockId(id)}
                  />
                );
                return null;
              })}
            </p>
          );
        }
        return null;
      })}

      {/* a Socrates inline annotation (margin note) */}
      <div className="margin-note">
        <span className="margin-note-glyph">Σ</span>
        <span>
          <span className="margin-note-who">Socrates · margin</span>
          <span className="margin-note-text">
            "Refuses to produce solutions" is a strong constraint. Have you decided what counts as a "solution" vs. a "scaffold"? This boundary will determine whether the refusal policy is enforceable.
          </span>
        </span>
      </div>
    </div>
  );
}

window.TextCanvas = TextCanvas;
window.Chip = Chip;
