/* ELEV8 ATS - Workflow editor: a node-graph automation builder, built natively
   (dotted-grid canvas, pointer-drag nodes, bezier SVG edges, pan/zoom, live test run).
   Modeled on React Flow / n8n, themed with the product tokens - no external deps. */

const DSw = window.Stand8DesignSystem_b5c975;

const NODE_W = 188, NODE_H = 66;

/* Node type identity: accent color + what it does. */
const NODE_TYPES = {
  trigger:   { label: 'Trigger',  color: 'var(--ui-warning-text)',  tint: 'var(--ui-warning-tint)' },
  agent:     { label: 'AI agent', color: 'var(--ui-daybreak-text)', tint: 'var(--ui-daybreak-wash)' },
  condition: { label: 'Condition',color: 'var(--ui-info-text)',     tint: 'var(--ui-info-tint)' },
  approval:  { label: 'Approval', color: 'var(--ui-success-text)',  tint: 'var(--ui-success-tint)' },
  action:    { label: 'Action',   color: 'var(--ui-text-secondary)',tint: 'var(--ui-fill)' },
  end:       { label: 'Output',   color: 'var(--ui-text-tertiary)', tint: 'var(--ui-fill)' },
};
const PALETTE = ['trigger', 'agent', 'condition', 'approval', 'action', 'end'];

function WorkflowEditorScreen() {
  const D = window.E8DATA;
  const { showToast } = React.useContext(window.E8Ctx);

  // Empty-data safe: a brand-new org has no workflows yet (guarded below, after the hooks).
  const wf0 = D.workflows[0] || null;
  const [wfId, setWfId] = React.useState(wf0 ? wf0.id : null);
  const wf = D.workflows.find((w) => w.id === wfId) || wf0;

  // working copy of the active workflow's graph (resets when you switch workflows)
  const [graph, setGraph] = React.useState({ nodes: (wf && wf.nodes) || [], edges: (wf && wf.edges) || [] });
  const [name, setName] = React.useState((wf && wf.name) || '');
  const [active, setActive] = React.useState(!!(wf && wf.active));
  const [selected, setSelected] = React.useState(null);
  const [pan, setPan] = React.useState({ x: 20, y: 10 });
  const [zoom, setZoom] = React.useState(0.9);
  const [running, setRunning] = React.useState({});      // nodeId -> 'run' | 'done'
  const runTimers = React.useRef([]);
  const nextId = React.useRef(100);

  React.useEffect(() => {
    if (!wf) return () => runTimers.current.forEach(clearTimeout);
    setGraph({ nodes: wf.nodes, edges: wf.edges });
    setName(wf.name); setActive(wf.active); setSelected(null); setRunning({});
    setPan({ x: 20, y: 10 }); setZoom(0.9);
    return () => runTimers.current.forEach(clearTimeout);
  }, [wfId]);

  if (!wf) {
    return (
      <React.Fragment>
        <Topbar crumbs={[{ label: 'Workflows' }]} />
        <div className="e8-content"><div className="e8-page">
          <div style={{ maxWidth: 460, margin: '48px auto' }}>
            <DSw.EmptyState icon="account_tree" title="No workflows yet" body="Automations you build - triggers, AI agents, approvals and actions on a canvas - appear here. Start one from a template to get going." />
          </div>
        </div></div>
      </React.Fragment>
    );
  }

  const nodeById = Object.fromEntries(graph.nodes.map((n) => [n.id, n]));

  /* ---- node drag (pointer) ---- */
  const onNodePointerDown = (e, id) => {
    e.stopPropagation();
    setSelected(id);
    const sx = e.clientX, sy = e.clientY, z = zoom;
    const n = nodeById[id], ox = n.x, oy = n.y;
    const move = (ev) => {
      const nx = ox + (ev.clientX - sx) / z, ny = oy + (ev.clientY - sy) / z;
      setGraph((g) => ({ ...g, nodes: g.nodes.map((m) => (m.id === id ? { ...m, x: nx, y: ny } : m)) }));
    };
    const up = () => { window.removeEventListener('pointermove', move); window.removeEventListener('pointerup', up); };
    window.addEventListener('pointermove', move); window.addEventListener('pointerup', up);
  };

  /* ---- canvas pan (drag empty space) ---- */
  const onCanvasPointerDown = (e) => {
    if (e.target.closest('.e8-wf-node')) return;
    setSelected(null);
    const sx = e.clientX, sy = e.clientY, ox = pan.x, oy = pan.y;
    const move = (ev) => setPan({ x: ox + (ev.clientX - sx), y: oy + (ev.clientY - sy) });
    const up = () => { window.removeEventListener('pointermove', move); window.removeEventListener('pointerup', up); };
    window.addEventListener('pointermove', move); window.addEventListener('pointerup', up);
  };

  const zoomBy = (d) => setZoom((z) => Math.max(0.5, Math.min(1.5, +(z + d).toFixed(2))));

  /* ---- add / delete nodes ---- */
  const addNode = (type) => {
    const id = 'x' + (nextId.current++);
    const t = NODE_TYPES[type];
    const n = { id, type, icon: { trigger: 'bolt', agent: 'smart_toy', condition: 'fork_right', approval: 'fact_check', action: 'play_arrow', end: 'flag' }[type], title: t.label, sub: 'Configure…', x: (-pan.x + 360) / zoom, y: (-pan.y + 240) / zoom };
    setGraph((g) => ({ ...g, nodes: [...g.nodes, n] }));
    setSelected(id);
    showToast(t.label + ' node added - drag to position, edit on the right');
  };
  const deleteNode = (id) => {
    setGraph((g) => ({ nodes: g.nodes.filter((n) => n.id !== id), edges: g.edges.filter((e) => e[0] !== id && e[1] !== id) }));
    setSelected(null);
  };
  const patchNode = (id, patch) => setGraph((g) => ({ ...g, nodes: g.nodes.map((n) => (n.id === id ? { ...n, ...patch } : n)) }));

  /* ---- test run: light up nodes along the graph in BFS order ---- */
  const testRun = () => {
    runTimers.current.forEach(clearTimeout); runTimers.current = [];
    setRunning({});
    const order = [];
    const starts = graph.nodes.filter((n) => n.type === 'trigger').map((n) => n.id);
    const seen = new Set(); let frontier = starts.length ? starts : (graph.nodes[0] ? [graph.nodes[0].id] : []);
    while (frontier.length) {
      const next = [];
      frontier.forEach((id) => { if (!seen.has(id)) { seen.add(id); order.push(id); graph.edges.filter((e) => e[0] === id).forEach((e) => next.push(e[1])); } });
      frontier = next;
    }
    order.forEach((id, i) => {
      runTimers.current.push(setTimeout(() => setRunning((r) => ({ ...r, [id]: 'run' })), i * 520));
      runTimers.current.push(setTimeout(() => setRunning((r) => ({ ...r, [id]: 'done' })), i * 520 + 480));
    });
    runTimers.current.push(setTimeout(() => { showToast('Test run complete - ' + order.length + ' steps, no errors'); setTimeout(() => setRunning({}), 1400); }, order.length * 520 + 200));
  };

  const sel = selected ? nodeById[selected] : null;

  /* ---- edges as bezier paths ---- */
  const edgePath = (a, b) => {
    const x1 = a.x + NODE_W, y1 = a.y + NODE_H / 2, x2 = b.x, y2 = b.y + NODE_H / 2;
    const dx = Math.max(40, Math.abs(x2 - x1) / 2);
    return 'M' + x1 + ',' + y1 + ' C' + (x1 + dx) + ',' + y1 + ' ' + (x2 - dx) + ',' + y2 + ' ' + x2 + ',' + y2;
  };

  return (
    <React.Fragment>
      <Topbar
        crumbs={[{ label: 'Workflows', to: 'workfloweditor' }, { label: name }]}
        actions={
          <React.Fragment>
            <span style={{ display: 'inline-flex', alignItems: 'center', gap: 7, marginRight: 4 }}>
              <span style={{ fontSize: 'var(--ui-text-sm)', color: 'var(--ui-text-secondary)' }}>{active ? 'Active' : 'Paused'}</span>
              <DSw.Toggle checked={active} onChange={() => { setActive(!active); showToast('Workflow ' + (active ? 'paused' : 'activated')); }} />
            </span>
            <DSw.Button variant="secondary" size="sm" icon="play_arrow" onClick={testRun}>Test run</DSw.Button>
            <DSw.Button variant="primary" size="sm" icon="check" onClick={() => showToast('Workflow saved')}>Save</DSw.Button>
          </React.Fragment>
        }
      />
      <div className="e8-wf">
        {/* Left: workflows + palette */}
        <div className="e8-wf-side">
          <div className="e8-wf-side-sec">
            <div className="e8-rail-title" style={{ display: 'flex', alignItems: 'center' }}>Workflows
              <span style={{ marginLeft: 'auto' }}><DSw.Button variant="ghost" size="sm" icon="add" iconOnly title="New workflow" onClick={() => showToast('Start from blank or a template')}></DSw.Button></span>
            </div>
            {D.workflows.map((w) => (
              <button key={w.id} type="button" className={'e8-wf-item' + (w.id === wfId ? ' active' : '')} onClick={() => setWfId(w.id)}>
                <span className={'e8-wf-dot ' + (w.active ? 'on' : '')}></span>
                <span style={{ minWidth: 0, flex: 1 }}>
                  <span style={{ display: 'block', fontSize: 'var(--ui-text-sm)', fontWeight: 500, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{w.name}</span>
                  <span style={{ display: 'block', fontSize: 'var(--ui-text-xs)', color: 'var(--ui-text-tertiary)' }}>{w.runs} runs · {w.lastRun}</span>
                </span>
              </button>
            ))}
          </div>
          <div className="e8-wf-side-sec">
            <div className="e8-rail-title">Add a step</div>
            {PALETTE.map((t) => (
              <button key={t} type="button" className="e8-wf-palette" onClick={() => addNode(t)}>
                <span className="e8-wf-pal-dot" style={{ background: NODE_TYPES[t].tint, color: NODE_TYPES[t].color }}>
                  <span className="material-symbols-outlined" style={{ fontSize: 14 }}>{ { trigger: 'bolt', agent: 'smart_toy', condition: 'fork_right', approval: 'fact_check', action: 'play_arrow', end: 'flag' }[t] }</span>
                </span>
                {NODE_TYPES[t].label}
                <span className="material-symbols-outlined" style={{ marginLeft: 'auto', fontSize: 15, color: 'var(--ui-text-tertiary)' }}>add</span>
              </button>
            ))}
            <div style={{ fontSize: 'var(--ui-text-xs)', color: 'var(--ui-text-tertiary)', marginTop: 8, lineHeight: 1.45 }}>
              Drag nodes to arrange. Every AI step still respects its agent’s autonomy and guardrails.
            </div>
          </div>
        </div>

        {/* Center: canvas */}
        <div className="e8-wf-canvas" onPointerDown={onCanvasPointerDown}>
          <div className="e8-wf-world" style={{ transform: 'translate(' + pan.x + 'px,' + pan.y + 'px) scale(' + zoom + ')' }}>
            <svg className="e8-wf-edges" width="2400" height="1400">
              <defs>
                <marker id="wfarrow" markerWidth="8" markerHeight="8" refX="6" refY="4" orient="auto">
                  <path d="M0,0 L6,4 L0,8 Z" fill="var(--ui-border-strong)" />
                </marker>
              </defs>
              {graph.edges.map((e, i) => {
                const a = nodeById[e[0]], b = nodeById[e[1]];
                if (!a || !b) return null;
                const lit = running[e[0]] === 'done' && running[e[1]];
                return <path key={i} d={edgePath(a, b)} fill="none"
                  style={{ stroke: lit ? 'var(--ui-accent)' : 'var(--ui-border-strong)', strokeWidth: lit ? 2.5 : 1.75, transition: 'stroke 200ms' }}
                  markerEnd="url(#wfarrow)" strokeDasharray={lit ? '6 4' : 'none'} />;
              })}
            </svg>
            {graph.nodes.map((n) => {
              const t = NODE_TYPES[n.type];
              const rs = running[n.id];
              return (
                <div key={n.id}
                  className={'e8-wf-node' + (selected === n.id ? ' sel' : '') + (rs ? ' ' + rs : '')}
                  style={{ left: n.x, top: n.y, width: NODE_W, '--nc': t.color, '--nt': t.tint }}
                  onPointerDown={(e) => onNodePointerDown(e, n.id)}>
                  {n.type !== 'trigger' ? <span className="e8-wf-handle in"></span> : null}
                  {n.type !== 'end' ? <span className="e8-wf-handle out"></span> : null}
                  <span className="e8-wf-node-icon"><span className="material-symbols-outlined" style={{ fontSize: 16 }}>{n.icon}</span></span>
                  <span style={{ minWidth: 0, flex: 1 }}>
                    <span style={{ display: 'block', fontSize: 'var(--ui-text-xs)', fontWeight: 600, textTransform: 'uppercase', letterSpacing: '0.04em', color: t.color }}>{t.label}</span>
                    <span style={{ display: 'block', fontSize: 'var(--ui-text-sm)', fontWeight: 500, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{n.title}</span>
                    <span style={{ display: 'block', fontSize: 'var(--ui-text-xs)', color: 'var(--ui-text-tertiary)', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{n.sub}</span>
                  </span>
                </div>
              );
            })}
          </div>

          {/* zoom controls */}
          <div className="e8-wf-zoom">
            <button type="button" onClick={() => zoomBy(0.1)} title="Zoom in"><span className="material-symbols-outlined">add</span></button>
            <span className="tnum">{Math.round(zoom * 100)}%</span>
            <button type="button" onClick={() => zoomBy(-0.1)} title="Zoom out"><span className="material-symbols-outlined">remove</span></button>
            <button type="button" onClick={() => { setPan({ x: 20, y: 10 }); setZoom(0.9); }} title="Reset view"><span className="material-symbols-outlined">fit_screen</span></button>
          </div>
        </div>

        {/* Right: inspector */}
        <div className="e8-wf-inspect">
          {sel ? (
            <React.Fragment>
              <div className="e8-rail-title" style={{ display: 'flex', alignItems: 'center', gap: 7 }}>
                <span className="e8-wf-pal-dot" style={{ background: NODE_TYPES[sel.type].tint, color: NODE_TYPES[sel.type].color, width: 20, height: 20 }}>
                  <span className="material-symbols-outlined" style={{ fontSize: 13 }}>{sel.icon}</span>
                </span>
                {NODE_TYPES[sel.type].label} step
              </div>
              <label className="e8-wf-field">Title<input value={sel.title} onChange={(e) => patchNode(sel.id, { title: e.target.value })} /></label>
              <label className="e8-wf-field">Detail<input value={sel.sub} onChange={(e) => patchNode(sel.id, { sub: e.target.value })} /></label>

              {sel.type === 'agent' ? (
                <div style={{ marginTop: 4 }}>
                  <div className="e8-wf-field-lbl">Agent</div>
                  <DSw.Select options={D.agents.map((a) => ({ value: a.id, label: a.name }))} />
                  <div style={{ fontSize: 'var(--ui-text-xs)', color: 'var(--ui-text-tertiary)', marginTop: 6, display: 'flex', gap: 6, alignItems: 'center' }}>
                    <span className="material-symbols-outlined" style={{ fontSize: 13 }}>shield</span>
                    Runs at the agent’s set autonomy. Client-facing steps wait for approval.
                  </div>
                </div>
              ) : null}
              {sel.type === 'condition' ? (
                <div style={{ fontSize: 'var(--ui-text-sm)', color: 'var(--ui-text-secondary)', marginTop: 4 }}>
                  Branches the flow. Connect the <b>true</b> path to the next step and the <b>false</b> path elsewhere.
                </div>
              ) : null}
              {sel.type === 'approval' ? (
                <div style={{ fontSize: 'var(--ui-text-sm)', color: 'var(--ui-text-secondary)', marginTop: 4 }}>
                  Pauses the run and drops the item in <a className="e8-link" tabIndex={0} onKeyDown={window.keyActivate} onClick={() => navigate('approvals')}>Approvals</a> until a human signs off.
                </div>
              ) : null}

              <div style={{ marginTop: 'auto', paddingTop: 12, borderTop: '1px solid var(--ui-border)' }}>
                <DSw.Button variant="ghost" size="sm" icon="delete" onClick={() => deleteNode(sel.id)}>Delete step</DSw.Button>
              </div>
            </React.Fragment>
          ) : (
            <React.Fragment>
              <div className="e8-rail-title">Workflow</div>
              <input className="e8-wf-name" value={name} onChange={(e) => setName(e.target.value)} />
              <p style={{ fontSize: 'var(--ui-text-sm)', color: 'var(--ui-text-secondary)', lineHeight: 1.5, margin: '2px 0 12px' }}>{wf.desc}</p>
              <div className="e8-kv"><span className="e8-kv-k">Status</span><span className="e8-kv-v"><DSw.Badge tone={active ? 'success' : 'neutral'} dot>{active ? 'Active' : 'Paused'}</DSw.Badge></span></div>
              <div className="e8-kv"><span className="e8-kv-k">Runs</span><span className="e8-kv-v tnum">{wf.runs}</span></div>
              <div className="e8-kv"><span className="e8-kv-k">Last run</span><span className="e8-kv-v">{wf.lastRun}</span></div>
              <div className="e8-kv"><span className="e8-kv-k">Steps</span><span className="e8-kv-v tnum">{graph.nodes.length}</span></div>
              <div className="e8-kv"><span className="e8-kv-k">Saved</span><span className="e8-kv-v">{wf.saved}</span></div>

              <div className="e8-rail-title" style={{ marginTop: 16 }}>Start from a template</div>
              {D.workflowTemplates.map((tp) => (
                <button key={tp.id} type="button" className="e8-wf-tmpl" onClick={() => showToast('Template “' + tp.name + '” added to the canvas')}>
                  <span className="material-symbols-outlined" style={{ fontSize: 16, color: 'var(--ui-daybreak-text)' }}>{tp.icon}</span>
                  <span style={{ minWidth: 0 }}>
                    <span style={{ display: 'block', fontSize: 'var(--ui-text-sm)', fontWeight: 500 }}>{tp.name}</span>
                    <span style={{ display: 'block', fontSize: 'var(--ui-text-xs)', color: 'var(--ui-text-tertiary)' }}>{tp.desc}</span>
                  </span>
                </button>
              ))}
            </React.Fragment>
          )}
        </div>
      </div>
    </React.Fragment>
  );
}

Object.assign(window, { WorkflowEditorScreen });
