/* global React, ReactDOM, NODE_CATALOG, bezierPath */
// =============================================================================
// Nugget Workflow Studio — main app
// =============================================================================

const { useState, useRef, useEffect, useMemo, useCallback } = React;

// ---- Complete loan lifecycle with real-time status updates ---------------
const INITIAL_NODES = [
  { id: 'n_fos_capture', type: 'fos',               x: 60,   y: 180 },
  { id: 'n_lms',         type: 'leadmgmt',          x: 360,  y: 60 },
  { id: 'n_ncm',         type: 'campaign',          x: 360,  y: 300 },
  { id: 'n_call1',       type: 'call_out',          x: 660,  y: 180 },
  { id: 'n_credit',      type: 'loan',              x: 960,  y: 180 },
  { id: 'n_call2',       type: 'call_out_approval', x: 1260, y: 180 },
  { id: 'n_fos_final',   type: 'fos_close',         x: 1560, y: 180 },
];
const INITIAL_EDGES = [
  // Initial flow
  { id: 'e1', from: 'n_fos_capture', to: 'n_lms' },
  { id: 'e2', from: 'n_fos_capture', to: 'n_ncm' },
  { id: 'e3', from: 'n_lms',         to: 'n_call1' },
  { id: 'e4', from: 'n_ncm',         to: 'n_call1' },
  // Main flow
  { id: 'e5', from: 'n_call1',       to: 'n_credit' },
  { id: 'e6', from: 'n_credit',      to: 'n_call2' },
  { id: 'e7', from: 'n_call2',       to: 'n_fos_final' },
  // Status updates back to LMS/NCM (shown as dotted lines in UI)
  { id: 'e8', from: 'n_call1',       to: 'n_lms' },
  { id: 'e9', from: 'n_call1',       to: 'n_ncm' },
  { id: 'e10', from: 'n_credit',     to: 'n_lms' },
  { id: 'e11', from: 'n_credit',     to: 'n_ncm' },
  { id: 'e12', from: 'n_call2',      to: 'n_lms' },
  { id: 'e13', from: 'n_call2',      to: 'n_ncm' },
];
// The run path (which nodes light up during a test run, in order)
const RUN_PATH = ['n_fos_capture', 'n_lms', 'n_ncm', 'n_call1', 'n_credit', 'n_call2', 'n_fos_final'];

// node sizes by kind  (used for port positioning)
function nodeSize(type) {
  const meta = NODE_CATALOG[type];
  if (meta.kind === 'agent') return { w: 240, h: 184 };
  if (meta.kind === 'logic') return { w: 200, h: 96 };
  return { w: 200, h: 96 };
}

// =============================================================================
// Top bar
// =============================================================================
function TopBar({ name, setName, onRun, running, onDeploy, user, onSignOut }) {
  return (
    <div className="topbar">
      <div className="brand">
        <span className="brand-dot" />
        <span>Nugget</span>
      </div>
      <div className="crumb">
        <span style={{ fontSize: 12 }}>Workflows</span>
        <span className="crumb-sep">/</span>
        <input
          className="workflow-name"
          value={name}
          onChange={(e) => setName(e.target.value)}
        />
        <span className="workflow-meta">
          <span className="dot" />
          <span>Live · v12</span>
          <span style={{ color: 'var(--nug-ink-5)' }}>·</span>
          <span>Edited 2m ago</span>
        </span>
      </div>
      <div className="topbar-spacer" />
      <div className="topbar-actions">
        {user && (
          <span style={{ fontSize: '12px', color: '#9CA3AF', marginRight: '12px' }}>
            {user.email}
          </span>
        )}
        <button className="btn btn-ghost btn-sm">
          <i className="--dock-icon-history" />
          History
        </button>
        <button className="btn btn-ghost btn-sm">
          <i className="--dock-icon-share-1" />
          Share
        </button>
        <button className="btn btn-secondary">
          <i className="--dock-icon-save" />
          Save draft
        </button>
        <button className="btn btn-primary" onClick={onRun} disabled={running}>
          <i className={running ? '--dock-icon-pause' : '--dock-icon-play-arrow'} />
          {running ? 'Running…' : 'Test run'}
        </button>
        <button className="btn btn-ink" onClick={onDeploy}>
          <i className="--dock-icon-rocket-launch" />
          Deploy
          <span className="kbd">⌘D</span>
        </button>
        {onSignOut && (
          <button
            className="btn btn-ghost btn-sm"
            onClick={onSignOut}
            style={{ marginLeft: '8px' }}
          >
            Sign Out
          </button>
        )}
        <div className="avatar">PA</div>
      </div>
    </div>
  );
}

// =============================================================================
// Left rail — node library
// =============================================================================
function LeftRail({ onDragStart, query, setQuery }) {
  const groups = [
    {
      title: 'Triggers', size: 'sm',
      items: ['webhook', 'schedule', 'manual'],
    },
    {
      title: 'Nugget Agents',
      items: ['campaign', 'leadmgmt', 'fos', 'loan', 'kyc'],
    },
    {
      title: 'Logic', size: 'sm',
      items: ['branch', 'delay'],
    },
    {
      title: 'Actions', size: 'sm',
      items: ['notify', 'webhook_out', 'store'],
    },
  ];

  const q = query.trim().toLowerCase();
  const filt = (k) => {
    if (!q) return true;
    const n = NODE_CATALOG[k];
    return (n.name + ' ' + (n.sub || '')).toLowerCase().includes(q);
  };

  return (
    <div className="rail">
      <div className="rail-header">
        <div className="rail-title">Library</div>
        <button className="btn btn-icon btn-sm" title="Add custom node">
          <i className="--dock-icon-add" />
        </button>
      </div>
      <div className="rail-search">
        <i className="--dock-icon-search-1" />
        <input
          placeholder="Search nodes"
          value={query}
          onChange={(e) => setQuery(e.target.value)}
        />
        <span className="kbd" style={{ background: 'var(--nug-line)' }}>/</span>
      </div>
      <div className="rail-tabs">
        <button className="rail-tab active">All</button>
        <button className="rail-tab">Mine</button>
        <button className="rail-tab">Templates</button>
      </div>
      <div style={{ overflowY: 'auto', flex: 1, paddingBottom: 16 }}>
        {groups.map((g) => {
          const items = g.items.filter(filt);
          if (!items.length) return null;
          return (
            <div key={g.title}>
              <div className="rail-section">
                <div className="rail-section-title">{g.title}</div>
              </div>
              <div className={`rail-list ${g.size === 'sm' ? 'rail-list-sm' : ''}`}>
                {items.map((k) => {
                  const meta = NODE_CATALOG[k];
                  return (
                    <div
                      key={k}
                      className={`node-card accent-${meta.accent}`}
                      draggable
                      onDragStart={(e) => onDragStart(e, k)}
                    >
                      <span className="node-card-ico">
                        <i className={`--dock-icon-${meta.icon}`} />
                      </span>
                      <div className="node-card-title">{meta.name}</div>
                      <span className="node-card-tag">{meta.tag}</span>
                      <div className="node-card-sub">{meta.sub}</div>
                    </div>
                  );
                })}
              </div>
            </div>
          );
        })}
      </div>
    </div>
  );
}

// =============================================================================
// Canvas node
// =============================================================================
function CNode({ node, meta, selected, running, onMouseDown, onClick }) {
  const sz = nodeSize(node.type);
  return (
    <div
      className={`cnode ${meta.kind} accent-${meta.accent} ${selected ? 'selected' : ''} ${running ? 'running' : ''}`}
      style={{ left: node.x, top: node.y, width: sz.w }}
      onClick={(e) => { e.stopPropagation(); onClick?.(node.id); }}
    >
      <div className="cnode-head" onMouseDown={(e) => onMouseDown(e, node.id)}>
        <span className="cnode-ico">
          <i className={`--dock-icon-${meta.icon}`} />
        </span>
        <div className="cnode-title-wrap">
          <div className="cnode-title">{meta.name}</div>
          <div className="cnode-sub">{meta.sub}</div>
        </div>
        <span className={`cnode-status ${running ? 'run' : 'ok'}`}>
          <span className="dotpulse" />
          {running ? 'ACTIVE' : 'IDLE'}
        </span>
      </div>

      {meta.kind === 'agent' && (
        <>
          <div className="cnode-body">
            {Object.entries(meta.fields).slice(0, 3).map(([k, v]) => (
              <div className="cnode-field" key={k}>
                <span className="cnode-field-label">{k}</span>
                <span className="cnode-field-val">
                  {Array.isArray(v) ? (
                    <span style={{ display: 'inline-flex', gap: 4 }}>
                      {v.slice(0, 3).map((x) => <span className="cnode-chip" key={x}>{x}</span>)}
                    </span>
                  ) : (
                    <span>{v}</span>
                  )}
                </span>
              </div>
            ))}
          </div>
          <div className="cnode-foot">
            <span>
              {meta.inputs?.length || 0} in · {meta.outputs?.length || 0} out
            </span>
          </div>
        </>
      )}

      {meta.kind !== 'agent' && meta.fields && (
        <div className="cnode-foot">
          <span>{Object.entries(meta.fields)[0]?.[1]}</span>
          {meta.tag && <span className="links">{meta.tag}</span>}
        </div>
      )}

      {/* Ports */}
      {meta.kind !== 'trigger' && <span className="port in" />}
      <span className="port out" />
    </div>
  );
}

// =============================================================================
// Canvas
// =============================================================================
function Canvas({
  nodes, edges, selectedId, runningId, runActive,
  onSelect, onMove, onDropNew, zoom, setZoom, pan, setPan,
}) {
  const wrapRef = useRef(null);
  const [dropHint, setDropHint] = useState(null);
  const [isPanning, setIsPanning] = useState(false);
  const dragState = useRef(null);

  // ---- node drag (move existing) ----
  const onNodeMouseDown = useCallback((e, id) => {
    if (e.button !== 0) return;
    e.stopPropagation();
    const node = nodes.find((n) => n.id === id);
    dragState.current = {
      mode: 'node',
      id, startX: e.clientX, startY: e.clientY,
      origX: node.x, origY: node.y,
    };
    onSelect(id);
  }, [nodes, onSelect]);

  // ---- canvas pan ----
  const onCanvasMouseDown = useCallback((e) => {
    if (e.target !== wrapRef.current && !e.target.classList?.contains('canvas-bg')) return;
    if (e.button !== 0) return;
    setIsPanning(true);
    dragState.current = {
      mode: 'pan',
      startX: e.clientX, startY: e.clientY,
      origX: pan.x, origY: pan.y,
    };
    onSelect(null);
  }, [pan, onSelect]);

  // ---- global mouse handlers ----
  useEffect(() => {
    function onMove(e) {
      const d = dragState.current;
      if (!d) return;
      const dx = (e.clientX - d.startX) / zoom;
      const dy = (e.clientY - d.startY) / zoom;
      if (d.mode === 'node') {
        onMoveNode(d.id, d.origX + dx, d.origY + dy);
      } else if (d.mode === 'pan') {
        setPan({ x: d.origX + (e.clientX - d.startX), y: d.origY + (e.clientY - d.startY) });
      }
    }
    function onUp() {
      dragState.current = null;
      setIsPanning(false);
    }
    window.addEventListener('mousemove', onMove);
    window.addEventListener('mouseup', onUp);
    return () => {
      window.removeEventListener('mousemove', onMove);
      window.removeEventListener('mouseup', onUp);
    };
  });

  function onMoveNode(id, x, y) {
    onMove(id, x, y);
  }

  // ---- drop from sidebar ----
  function onDragOver(e) {
    if (e.dataTransfer.types.includes('application/x-nugget-node')) {
      e.preventDefault();
      const rect = wrapRef.current.getBoundingClientRect();
      const x = (e.clientX - rect.left - pan.x) / zoom - 120;
      const y = (e.clientY - rect.top - pan.y) / zoom - 40;
      setDropHint({ x, y });
    }
  }
  function onDragLeave() { setDropHint(null); }
  function onDrop(e) {
    const type = e.dataTransfer.getData('application/x-nugget-node');
    if (!type) return;
    const rect = wrapRef.current.getBoundingClientRect();
    const x = (e.clientX - rect.left - pan.x) / zoom - 120;
    const y = (e.clientY - rect.top - pan.y) / zoom - 40;
    onDropNew(type, x, y);
    setDropHint(null);
  }

  // ---- wheel zoom ----
  function onWheel(e) {
    if (e.ctrlKey || e.metaKey) {
      e.preventDefault();
      const dz = e.deltaY > 0 ? 0.93 : 1.07;
      setZoom(Math.max(0.4, Math.min(2, zoom * dz)));
    }
  }

  // ---- edges ----
  const positionOf = useMemo(() => {
    const m = {};
    for (const n of nodes) {
      const s = nodeSize(n.type);
      m[n.id] = {
        outX: n.x + s.w, outY: n.y + 38,
        inX: n.x, inY: n.y + 38,
      };
    }
    return m;
  }, [nodes]);

  return (
    <div
      ref={wrapRef}
      className="canvas-wrap canvas-bg"
      onMouseDown={onCanvasMouseDown}
      onDragOver={onDragOver}
      onDragLeave={onDragLeave}
      onDrop={onDrop}
      onWheel={onWheel}
      style={{ cursor: isPanning ? 'grabbing' : 'default' }}
    >
      <div
        className="canvas"
        style={{ transform: `translate(${pan.x}px, ${pan.y}px) scale(${zoom})` }}
      >
        <svg className={`edges-svg ${runActive ? 'running' : ''}`} style={{ width: 4000, height: 2000 }}>
          {edges.map((e) => {
            const a = positionOf[e.from];
            const b = positionOf[e.to];
            if (!a || !b) return null;
            const d = bezierPath(a.outX, a.outY, b.inX, b.inY);
            const isOnPath =
              runActive &&
              RUN_PATH.indexOf(e.from) >= 0 &&
              RUN_PATH.indexOf(e.to) === RUN_PATH.indexOf(e.from) + 1;
            return (
              <g key={e.id}>
                <path className={`edge-path ${isOnPath ? 'is-active' : ''}`} d={d} />
                {isOnPath && <path className="edge-flow" d={d} />}
                <path className="edge-hit" d={d} />
              </g>
            );
          })}
        </svg>

        {nodes.map((n) => {
          const meta = NODE_CATALOG[n.type];
          return (
            <CNode
              key={n.id}
              node={n}
              meta={meta}
              selected={selectedId === n.id}
              running={runActive && runningId === n.id}
              onMouseDown={onNodeMouseDown}
              onClick={onSelect}
            />
          );
        })}

        {dropHint && (
          <div className="drop-hint" style={{ left: dropHint.x, top: dropHint.y }} />
        )}
      </div>

      {/* Zoom + fit controls */}
      <div className="canvas-controls">
        <button className="btn btn-ghost" onClick={() => setZoom(Math.min(2, zoom * 1.1))}>
          <i className="--dock-icon-add" />
        </button>
        <div className="zoom-readout">{Math.round(zoom * 100)}%</div>
        <button className="btn btn-ghost" onClick={() => setZoom(Math.max(0.4, zoom * 0.9))}>
          <i className="--dock-icon-remove" />
        </button>
        <div style={{ height: 1, background: 'var(--nug-line)', margin: '2px 4px' }} />
        <button className="btn btn-ghost" onClick={() => { setZoom(1); setPan({ x: 0, y: 0 }); }} title="Fit">
          <i className="--dock-icon-crop-free" />
        </button>
      </div>
    </div>
  );
}

// =============================================================================
// Inspector
// =============================================================================
function Inspector({ node, onClose }) {
  const [tab, setTab] = useState('setup');
  if (!node) return null;
  const meta = NODE_CATALOG[node.type];

  return (
    <div className="inspector">
      <div className="insp-head">
        <span className={`cnode-ico accent-${meta.accent}`}>
          <i className={`--dock-icon-${meta.icon}`} />
        </span>
        <div>
          <div className="title">{meta.name}</div>
          <div className="sub">{meta.description}</div>
        </div>
        <button className="btn btn-icon btn-sm insp-close" onClick={onClose}>
          <i className="--dock-icon-close" />
        </button>
      </div>
      <div className="insp-tabs">
        {['setup', 'data', 'metrics', 'logs'].map((t) => (
          <button
            key={t}
            className={`insp-tab ${tab === t ? 'active' : ''}`}
            onClick={() => setTab(t)}
          >
            {t[0].toUpperCase() + t.slice(1)}
          </button>
        ))}
      </div>

      <div className="insp-body">
        {tab === 'setup' && <SetupTab meta={meta} />}
        {tab === 'data' && <DataTab meta={meta} />}
        {tab === 'metrics' && <MetricsTab meta={meta} />}
        {tab === 'logs' && <LogsTab meta={meta} />}
      </div>
    </div>
  );
}

function SetupTab({ meta }) {
  // Build form fields based on meta.fields
  return (
    <>
      <div className="section-title">Configuration</div>
      {Object.entries(meta.fields || {}).map(([k, v]) => (
        <div className="form-row" key={k}>
          <div className="form-label">
            <span>{k}</span>
            <span className="hint">required</span>
          </div>
          {Array.isArray(v) ? (
            <div className="chips">
              {v.map((x) => (
                <span className="chip" key={x}>{x} <span className="chip-x">×</span></span>
              ))}
              <span className="chip" style={{ borderStyle: 'dashed', color: 'var(--nug-ink-4)' }}>+ add</span>
            </div>
          ) : (
            <input className="input" defaultValue={v} />
          )}
        </div>
      ))}

      {meta.inputs && (
        <div className="section">
          <div className="section-title">Inputs</div>
          <div className="chips">
            {meta.inputs.map((x) => <span className="chip" key={x}><i className="--dock-icon-arrow-right" style={{ fontSize: 12 }} />{x}</span>)}
          </div>
        </div>
      )}
      {meta.outputs && (
        <div className="section">
          <div className="section-title">Outputs</div>
          <div className="chips">
            {meta.outputs.map((x) => <span className="chip" key={x}>{x}<i className="--dock-icon-arrow-right" style={{ fontSize: 12 }} /></span>)}
          </div>
        </div>
      )}

      <div className="section">
        <div className="section-title">Execution</div>
        <div className="form-row">
          <label className="toggle">
            <input type="checkbox" defaultChecked />
            <span className="switch" />
            <span style={{ fontSize: 13 }}>Run on every payload</span>
          </label>
        </div>
        <div className="form-row">
          <label className="toggle">
            <input type="checkbox" />
            <span className="switch" />
            <span style={{ fontSize: 13 }}>Retry on failure (3×)</span>
          </label>
        </div>
      </div>
    </>
  );
}

function DataTab({ meta }) {
  const sample = {
    lead_id: 'LD_028412',
    name: 'Aarti Sharma',
    phone: '+91 98••• ••••3',
    city: 'Pune',
    score: 0.74,
    source: 'meta_ads',
    intent: 'personal_loan_50k',
  };
  return (
    <>
      <div className="section-title">Sample payload</div>
      <pre className="log" style={{ maxHeight: 'unset' }}>
{JSON.stringify(sample, null, 2)}
      </pre>
      <div className="section">
        <div className="section-title">Field mapping</div>
        <dl className="kv">
          <dt>{Object.keys(sample)[0]}</dt><dd>→ payload.id</dd>
          <dt>name</dt><dd>→ payload.contact.name</dd>
          <dt>phone</dt><dd>→ payload.contact.phone</dd>
          <dt>score</dt><dd>→ payload.ranking</dd>
        </dl>
      </div>
    </>
  );
}

function MetricsTab({ meta }) {
  const m = meta.metrics || { sent: '—', replyRate: '—', cost: '—' };
  return (
    <>
      <div className="section-title">Last 24 hours</div>
      <div className="metric">
        {Object.entries(m).map(([k, v], i) => (
          <div key={k} className={`metric-cell ${i === 0 ? 'accent-green' : i === 1 ? 'accent-blue' : ''}`}>
            <div className="v">{v}</div>
            <div className="l">{k.replace(/([A-Z])/g, ' $1').trim()}</div>
          </div>
        ))}
      </div>

      <svg className="spark" viewBox="0 0 200 40" preserveAspectRatio="none">
        <path className="area" d="M0,30 L10,28 L20,25 L30,29 L40,20 L50,22 L60,18 L70,16 L80,20 L90,14 L100,12 L110,16 L120,10 L130,14 L140,8 L150,12 L160,9 L170,6 L180,10 L190,4 L200,8 L200,40 L0,40 Z" />
        <path d="M0,30 L10,28 L20,25 L30,29 L40,20 L50,22 L60,18 L70,16 L80,20 L90,14 L100,12 L110,16 L120,10 L130,14 L140,8 L150,12 L160,9 L170,6 L180,10 L190,4 L200,8" />
      </svg>

      <div className="section">
        <div className="section-title">Health</div>
        <div className="form-row" style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
          <span style={{ fontSize: 13 }}>p95 latency</span>
          <span className="cnode-chip">214 ms</span>
        </div>
        <div className="form-row" style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
          <span style={{ fontSize: 13 }}>Error rate (24h)</span>
          <span className="cnode-chip" style={{ background: 'var(--nug-green-100)', color: 'var(--nug-green-700)' }}>0.4%</span>
        </div>
        <div className="form-row" style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
          <span style={{ fontSize: 13 }}>Concurrent runs</span>
          <span className="cnode-chip">14 / 50</span>
        </div>
      </div>
    </>
  );
}

function LogsTab({ meta }) {
  return (
    <>
      <div className="section-title">Recent runs</div>
      <pre className="log">
<span className="ts">14:02:11.342</span>  <span className="ok">OK</span>     run #28411 · 184ms · lead LD_028412{'\n'}
<span className="ts">14:02:08.110</span>  <span className="ok">OK</span>     run #28410 · 156ms · lead LD_028411{'\n'}
<span className="ts">14:02:01.821</span>  <span className="info">INFO</span>  retrying provider · attempt 2 of 3{'\n'}
<span className="ts">14:01:59.044</span>  <span className="warn">WARN</span>  rate limit warning (95% of quota){'\n'}
<span className="ts">14:01:55.733</span>  <span className="ok">OK</span>     run #28409 · 209ms · lead LD_028410{'\n'}
<span className="ts">14:01:48.502</span>  <span className="ok">OK</span>     run #28408 · 162ms · lead LD_028409{'\n'}
<span className="ts">14:01:40.117</span>  <span className="ok">OK</span>     run #28407 · 175ms · lead LD_028408{'\n'}
<span className="ts">14:01:32.099</span>  <span className="ok">OK</span>     run #28406 · 198ms · lead LD_028407{'\n'}
<span className="ts">14:01:24.080</span>  <span className="ok">OK</span>     run #28405 · 191ms · lead LD_028406
      </pre>
    </>
  );
}

// =============================================================================
// Minimap
// =============================================================================
function Minimap({ nodes, edges, selectedId, pan, zoom }) {
  // bounding box
  const pad = 60;
  let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
  for (const n of nodes) {
    const s = nodeSize(n.type);
    minX = Math.min(minX, n.x); minY = Math.min(minY, n.y);
    maxX = Math.max(maxX, n.x + s.w); maxY = Math.max(maxY, n.y + s.h);
  }
  minX -= pad; minY -= pad; maxX += pad; maxY += pad;
  const w = Math.max(1, maxX - minX);
  const h = Math.max(1, maxY - minY);
  return (
    <div className="minimap">
      <div className="minimap-title">Map</div>
      <svg viewBox={`${minX} ${minY} ${w} ${h}`} preserveAspectRatio="xMidYMid meet">
        {edges.map((e) => {
          const a = nodes.find(n => n.id === e.from);
          const b = nodes.find(n => n.id === e.to);
          if (!a || !b) return null;
          const sa = nodeSize(a.type), sb = nodeSize(b.type);
          return <line key={e.id} className="mm-edge"
            x1={a.x + sa.w} y1={a.y + 40}
            x2={b.x} y2={b.y + 40} />;
        })}
        {nodes.map((n) => {
          const s = nodeSize(n.type);
          return <rect key={n.id} className={`mm-node ${n.id === selectedId ? 'sel' : ''}`}
            x={n.x} y={n.y} width={s.w} height={s.h} rx="14" />;
        })}
      </svg>
    </div>
  );
}

// =============================================================================
// Run bar (shows during test run)
// =============================================================================
function RunBar({ step, total, currentNode }) {
  const meta = currentNode ? NODE_CATALOG[currentNode.type] : null;
  return (
    <div className="runbar">
      <span className="pulse" />
      <span>Run #28412</span>
      <span style={{ color: 'rgba(255,255,255,0.4)' }}>|</span>
      <span className="step active">{meta ? meta.name : '—'}</span>
      <span style={{ color: 'rgba(255,255,255,0.4)' }}>·</span>
      <span style={{ color: 'rgba(255,255,255,0.65)' }}>{step + 1} / {total}</span>
      <button className="btn btn-sm" style={{ background: 'rgba(255,255,255,0.10)', color: '#fff' }}>
        <i className="--dock-icon-pause" />
        Pause
      </button>
    </div>
  );
}

// =============================================================================
// App root
// =============================================================================
function App({ user, onSignOut }) {
  const [nodes, setNodes] = useState(INITIAL_NODES);
  const [edges] = useState(INITIAL_EDGES);
  const [selectedId, setSelectedId] = useState(null);
  const [query, setQuery] = useState('');
  const [pan, setPan] = useState({ x: 24, y: 16 });
  const [zoom, setZoom] = useState(0.62);
  const [name, setName] = useState('Complete Loan Lifecycle - FOS to Approval');

  // run state - Start with first node (Dushyant's FOS node) as ACTIVE
  const [runActive, setRunActive] = useState(true);
  const [runStep, setRunStep] = useState(0);

  // auto-fit on mount: compute bounds and fit to canvas-host viewport
  useEffect(() => {
    const host = document.querySelector('.canvas-host');
    if (!host) return;
    const r = host.getBoundingClientRect();
    // bounds of initial nodes
    let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
    for (const n of INITIAL_NODES) {
      const s = nodeSize(n.type);
      minX = Math.min(minX, n.x); minY = Math.min(minY, n.y);
      maxX = Math.max(maxX, n.x + s.w); maxY = Math.max(maxY, n.y + s.h);
    }
    const pad = 60;
    const w = (maxX - minX) + pad * 2;
    const h = (maxY - minY) + pad * 2;
    const z = Math.min(1, Math.min(r.width / w, r.height / h));
    const z2 = Math.max(0.45, Math.min(0.95, z));
    const cx = (minX + maxX) / 2;
    const cy = (minY + maxY) / 2;
    setZoom(z2);
    setPan({
      x: r.width / 2 - cx * z2,
      y: r.height / 2 - cy * z2,
    });
  }, []);

  // tweak state — accent/density already applied by NuggetTweaks panel via CSS overrides
  // (the panel mounts separately, so we don't need to thread state through here)

  // ----- drag from rail -----
  function onDragStart(e, type) {
    e.dataTransfer.setData('application/x-nugget-node', type);
    e.dataTransfer.effectAllowed = 'copy';
  }
  function onDropNew(type, x, y) {
    const id = 'n_' + Math.random().toString(36).slice(2, 8);
    setNodes((ns) => [...ns, { id, type, x, y }]);
    setSelectedId(id);
  }
  function onMoveNode(id, x, y) {
    setNodes((ns) => ns.map((n) => (n.id === id ? { ...n, x, y } : n)));
  }

  // ----- run animation -----
  useEffect(() => {
    if (!runActive) return;
    setRunStep(0);
    const total = RUN_PATH.length;
    const t = setInterval(() => {
      setRunStep((s) => {
        if (s + 1 >= total) {
          clearInterval(t);
          setTimeout(() => setRunActive(false), 800);
          return s;
        }
        return s + 1;
      });
    }, 950);
    return () => clearInterval(t);
  }, [runActive]);

  function startRun() {
    setRunActive(true);
    setSelectedId(null);
  }

  const selectedNode = nodes.find((n) => n.id === selectedId);
  const runningId = runActive ? RUN_PATH[runStep] : null;
  if (runActive) {
    // focus on running node by ensuring it's in view (no-op since static)
  }

  const showInspector = !!selectedNode && !runActive;

  return (
    <div className="app">
      <TopBar name={name} setName={setName} onRun={startRun} running={runActive} user={user} onSignOut={onSignOut} />
      <div className={`workspace ${showInspector ? 'has-inspector' : ''}`}>
        <LeftRail onDragStart={onDragStart} query={query} setQuery={setQuery} />
        <div className="canvas-host">
          <Canvas
            nodes={nodes}
            edges={edges}
            selectedId={selectedId}
            runningId={runningId}
            runActive={runActive}
            onSelect={setSelectedId}
            onMove={onMoveNode}
            onDropNew={onDropNew}
            zoom={zoom} setZoom={setZoom}
            pan={pan} setPan={setPan}
          />
          {runActive && (
            <RunBar
              step={runStep}
              total={RUN_PATH.length}
              currentNode={nodes.find((n) => n.id === runningId)}
            />
          )}
          <Minimap nodes={nodes} edges={edges} selectedId={selectedId} pan={pan} zoom={zoom} />
        </div>
        {showInspector && <Inspector node={selectedNode} onClose={() => setSelectedId(null)} />}
      </div>
    </div>
  );
}

// mount with auth wrapper
ReactDOM.createRoot(document.getElementById('root')).render(
  <window.SimpleAuthWrapper>
    <App />
  </window.SimpleAuthWrapper>
);
