// Grape Elevate — Flow builder (interactive drag-and-drop)
//
// State model: nodes have { id, type, x, y, label, config }; edges have { from, to }.
// Canvas supports pan with middle/right drag or holding space; pinch/wheel zoom.
// Nodes drag on the canvas; each has an output dot (bottom) you can drag from
// to another node's input dot (top) to wire a connection.

const NODE_W = 220;
const NODE_H_DEFAULT = 92;
const PORT_R = 7;

const NODE_TYPES = {
  // triggers
  comment: { cat: 'trigger', color: 'var(--coral)',  icon: Icons.Comment, labelKey: 'flow.node.comment',  defaults: { keyword: 'PROMO', post: 'último post' } },
  dm:      { cat: 'trigger', color: 'var(--cyan)',   icon: Icons.Send,    labelKey: 'flow.node.dm',       defaults: { keyword: 'oi' } },
  story:   { cat: 'trigger', color: 'var(--grape)',  icon: Icons.Story,   labelKey: 'flow.node.story',    defaults: { keyword: '*' } },
  follow:  { cat: 'trigger', color: 'var(--sun)',    icon: Icons.Follow,  labelKey: 'flow.node.follow',   defaults: {} },
  // actions
  sendDm:   { cat: 'action', color: 'var(--cyan)',  icon: Icons.Send, labelKey: 'flow.node.sendDm',   defaults: { text: 'Oi! Aqui está o que você pediu 👇' } },
  sendLink: { cat: 'action', color: 'var(--grape)', icon: Icons.Link, labelKey: 'flow.node.sendLink', defaults: { url: 'https://grape.app/oferta', cta: 'Ver oferta' } },
  tag:      { cat: 'action', color: 'var(--sun)',   icon: Icons.Tag,  labelKey: 'flow.node.tag',      defaults: { tag: 'lead-quente' } },
  // logic
  wait:  { cat: 'logic', color: 'var(--text-mute)', icon: Icons.Clock,  labelKey: 'flow.node.wait',  defaults: { mins: 5 } },
  if:    { cat: 'logic', color: 'var(--green)',     icon: Icons.Branch, labelKey: 'flow.node.if',    defaults: { cond: 'tem tag "vip"' } },
  split: { cat: 'logic', color: 'var(--green)',     icon: Icons.Branch, labelKey: 'flow.node.split', defaults: { ratio: '50/50' } },
};

const initialFlow = () => ({
  nodes: [
    { id: 'n1', type: 'comment',  x: 120, y: 60,  config: { keyword: 'PROMO', post: 'Reel "3 dicas"' } },
    { id: 'n2', type: 'wait',     x: 120, y: 240, config: { mins: 1 } },
    { id: 'n3', type: 'sendDm',   x: 120, y: 380, config: { text: 'Oi! Vi seu comentário 💜 mando aqui em segundos…' } },
    { id: 'n4', type: 'sendLink', x: 120, y: 540, config: { url: 'https://grape.app/promo', cta: 'Aproveitar' } },
    { id: 'n5', type: 'tag',      x: 420, y: 380, config: { tag: 'promo-jun' } },
  ],
  edges: [
    { from: 'n1', to: 'n2' },
    { from: 'n2', to: 'n3' },
    { from: 'n3', to: 'n4' },
    { from: 'n3', to: 'n5' },
  ],
});

function FlowBuilder({ t, lang, automations, onBack, onSaveToast }) {
  const [flow, setFlow] = React.useState(initialFlow);
  const [selected, setSelected] = React.useState('n1');
  const [zoom, setZoom] = React.useState(0.85);
  const [pan, setPan] = React.useState({ x: 80, y: 20 });
  const [dragging, setDragging] = React.useState(null); // { id, dx, dy }
  const [connecting, setConnecting] = React.useState(null); // { from, x, y }
  const canvasRef = React.useRef(null);

  const sel = flow.nodes.find((n) => n.id === selected);

  // Add a new node by clicking a palette tile. Drops near center of viewport.
  const addNode = (type) => {
    const id = 'n' + Date.now();
    const x = (-pan.x + 400) / zoom;
    const y = (-pan.y + 240) / zoom;
    setFlow((f) => ({
      ...f,
      nodes: [...f.nodes, { id, type, x, y, config: { ...(NODE_TYPES[type].defaults || {}) } }],
    }));
    setSelected(id);
  };

  const deleteNode = (id) => setFlow((f) => ({
    nodes: f.nodes.filter((n) => n.id !== id),
    edges: f.edges.filter((e) => e.from !== id && e.to !== id),
  }));
  const duplicateNode = (id) => {
    const n = flow.nodes.find((x) => x.id === id);
    if (!n) return;
    const nid = 'n' + Date.now();
    setFlow((f) => ({ ...f, nodes: [...f.nodes, { ...n, id: nid, x: n.x + 24, y: n.y + 24, config: { ...n.config } }] }));
    setSelected(nid);
  };

  const updateConfig = (id, key, value) => setFlow((f) => ({
    ...f,
    nodes: f.nodes.map((n) => n.id === id ? { ...n, config: { ...n.config, [key]: value } } : n),
  }));

  // ── Canvas pan / zoom ─────────────────────────────────────────────────────
  const onWheel = (e) => {
    if (!e.ctrlKey && !e.metaKey && Math.abs(e.deltaY) < 30) {
      setPan((p) => ({ x: p.x - e.deltaX, y: p.y - e.deltaY }));
      return;
    }
    e.preventDefault();
    const rect = canvasRef.current.getBoundingClientRect();
    const cx = e.clientX - rect.left, cy = e.clientY - rect.top;
    const next = Math.max(0.4, Math.min(1.6, zoom - e.deltaY * 0.001));
    const k = next / zoom;
    setPan((p) => ({ x: cx - (cx - p.x) * k, y: cy - (cy - p.y) * k }));
    setZoom(next);
  };
  const startPan = (e) => {
    if (e.target !== canvasRef.current && !e.target.classList.contains('fb-grid')) return;
    setSelected(null);
    const sx = e.clientX, sy = e.clientY, p0 = { ...pan };
    const move = (ev) => setPan({ x: p0.x + (ev.clientX - sx), y: p0.y + (ev.clientY - sy) });
    const up = () => { window.removeEventListener('mousemove', move); window.removeEventListener('mouseup', up); };
    window.addEventListener('mousemove', move);
    window.addEventListener('mouseup', up);
  };

  // ── Node drag ─────────────────────────────────────────────────────────────
  const startNodeDrag = (e, id) => {
    e.stopPropagation();
    setSelected(id);
    const n = flow.nodes.find((x) => x.id === id);
    const sx = e.clientX, sy = e.clientY, x0 = n.x, y0 = n.y;
    const move = (ev) => {
      const nx = x0 + (ev.clientX - sx) / zoom;
      const ny = y0 + (ev.clientY - sy) / zoom;
      setFlow((f) => ({ ...f, nodes: f.nodes.map((m) => m.id === id ? { ...m, x: nx, y: ny } : m) }));
    };
    const up = () => { window.removeEventListener('mousemove', move); window.removeEventListener('mouseup', up); };
    window.addEventListener('mousemove', move);
    window.addEventListener('mouseup', up);
  };

  // ── Wire dragging ─────────────────────────────────────────────────────────
  const startWire = (e, fromId) => {
    e.stopPropagation();
    const rect = canvasRef.current.getBoundingClientRect();
    setConnecting({ from: fromId, x: (e.clientX - rect.left - pan.x) / zoom, y: (e.clientY - rect.top - pan.y) / zoom });
    const move = (ev) => {
      const rr = canvasRef.current.getBoundingClientRect();
      setConnecting((c) => c && ({ ...c, x: (ev.clientX - rr.left - pan.x) / zoom, y: (ev.clientY - rr.top - pan.y) / zoom }));
    };
    const up = (ev) => {
      window.removeEventListener('mousemove', move);
      window.removeEventListener('mouseup', up);
      // Drop on a node input?
      const targets = document.elementsFromPoint(ev.clientX, ev.clientY);
      const portEl = targets.find((el) => el?.dataset && el.dataset.inputFor);
      if (portEl) {
        const toId = portEl.dataset.inputFor;
        if (toId !== fromId) {
          setFlow((f) => {
            // Replace any existing edge from same source if you like; here we just append unless duplicate.
            if (f.edges.some((e) => e.from === fromId && e.to === toId)) return f;
            return { ...f, edges: [...f.edges, { from: fromId, to: toId }] };
          });
        }
      }
      setConnecting(null);
    };
    window.addEventListener('mousemove', move);
    window.addEventListener('mouseup', up);
  };

  // ── Edge path (bezier) ────────────────────────────────────────────────────
  const edgePath = (a, b) => {
    const x1 = a.x + NODE_W / 2, y1 = a.y + NODE_H_DEFAULT;
    const x2 = b.x + NODE_W / 2, y2 = b.y;
    const dy = Math.max(40, (y2 - y1) / 2);
    return `M ${x1},${y1} C ${x1},${y1 + dy} ${x2},${y2 - dy} ${x2},${y2}`;
  };

  // Palette grouped by category
  const palette = {
    triggers: ['comment', 'dm', 'story', 'follow'],
    actions: ['sendDm', 'sendLink', 'tag'],
    logic: ['wait', 'if', 'split'],
  };

  return (
    <>
      <style>{flowStyles}</style>
      <div className="fb-bar">
        <button className="btn btn-ghost" onClick={onBack}><Icons.Chevron size={14} style={{ transform: 'rotate(180deg)' }} /> {t('flow.back')}</button>
        <div className="fb-title">
          <span className="eyebrow">{t('flow.title')}</span>
          <input className="fb-name" defaultValue="Comentou PROMO → DM com link" />
        </div>
        <div className="row" style={{ gap: 6 }}>
          <div className="seg" style={{ padding: 3 }}>
            <button onClick={() => setZoom((z) => Math.max(0.4, z - 0.1))} title={t('flow.zoom.out')}><Icons.Minus size={14} /></button>
            <button onClick={() => { setZoom(1); setPan({ x: 80, y: 20 }); }} title={t('flow.fit')}>{Math.round(zoom * 100)}%</button>
            <button onClick={() => setZoom((z) => Math.min(1.6, z + 0.1))} title={t('flow.zoom.in')}><Icons.Plus size={14} /></button>
          </div>
          <button className="btn"><Icons.Play size={14} /> {t('flow.test')}</button>
          <button className="btn" onClick={() => onSaveToast('Fluxo salvo')}>{t('flow.save')}</button>
          <button className="btn btn-primary" onClick={() => onSaveToast('Fluxo publicado 🎉')}>{t('flow.publish')}</button>
        </div>
      </div>

      <div className="fb-shell">
        {/* Palette */}
        <aside className="fb-palette">
          <div className="eyebrow" style={{ padding: '4px 4px 8px' }}>{t('flow.palette')}</div>
          {Object.entries(palette).map(([cat, items]) => (
            <div key={cat} className="fb-cat">
              <div className="fb-cat-label">{t(`flow.cat.${cat}`)}</div>
              <div className="fb-pal-grid">
                {items.map((type) => {
                  const T = NODE_TYPES[type];
                  return (
                    <button key={type} className="fb-pal-item" onClick={() => addNode(type)}
                            style={{ borderColor: 'var(--line)' }}>
                      <span className="fb-pal-ic" style={{ background: `color-mix(in oklch, ${T.color} 18%, transparent)`, color: T.color }}>
                        <T.icon size={16} />
                      </span>
                      <span className="fb-pal-name">{t(T.labelKey)}</span>
                      <Icons.Plus size={12} />
                    </button>
                  );
                })}
              </div>
            </div>
          ))}
          <div className="fb-tip">{t('flow.tip')}</div>
        </aside>

        {/* Canvas */}
        <div className="fb-canvas-wrap" ref={canvasRef} onMouseDown={startPan} onWheel={onWheel}>
          <div className="fb-grid" />
          <div className="fb-world" style={{ transform: `translate(${pan.x}px, ${pan.y}px) scale(${zoom})` }}>
            {/* Edges */}
            <svg className="fb-edges" width="3000" height="3000">
              <defs>
                <marker id="arrow" viewBox="0 0 10 10" refX="8" refY="5" markerWidth="8" markerHeight="8" orient="auto">
                  <path d="M0 0 L10 5 L0 10 z" fill="var(--text-mute)" />
                </marker>
              </defs>
              {flow.edges.map((e, i) => {
                const a = flow.nodes.find((n) => n.id === e.from);
                const b = flow.nodes.find((n) => n.id === e.to);
                if (!a || !b) return null;
                return <path key={i} d={edgePath(a, b)} stroke="var(--text-mute)" strokeWidth="2"
                              fill="none" markerEnd="url(#arrow)" opacity={0.65} />;
              })}
              {connecting && (() => {
                const a = flow.nodes.find((n) => n.id === connecting.from);
                if (!a) return null;
                const x1 = a.x + NODE_W / 2, y1 = a.y + NODE_H_DEFAULT;
                const dy = Math.max(40, (connecting.y - y1) / 2);
                return <path d={`M ${x1},${y1} C ${x1},${y1+dy} ${connecting.x},${connecting.y-dy} ${connecting.x},${connecting.y}`}
                             stroke="var(--grape)" strokeWidth="2.5" strokeDasharray="6 4" fill="none" />;
              })()}
            </svg>
            {/* Nodes */}
            {flow.nodes.map((n) => {
              const T = NODE_TYPES[n.type];
              if (!T) return null;
              const isSel = selected === n.id;
              return (
                <div key={n.id} className={`fb-node ${T.cat} ${isSel ? 'sel' : ''}`}
                     style={{ left: n.x, top: n.y, width: NODE_W }}
                     onMouseDown={(e) => startNodeDrag(e, n.id)}>
                  <div className="fb-node-head" style={{ background: `color-mix(in oklch, ${T.color} 16%, transparent)` }}>
                    <span className="fb-node-ic" style={{ background: T.color, color: '#fff' }}><T.icon size={14} /></span>
                    <span className="fb-node-title">{t(T.labelKey)}</span>
                    <span className="fb-node-cat">{t(`flow.cat.${T.cat === 'trigger' ? 'triggers' : T.cat === 'action' ? 'actions' : 'logic'}`).slice(0, 3).toUpperCase()}</span>
                  </div>
                  <div className="fb-node-body">
                    <NodeBody type={n.type} config={n.config} />
                  </div>
                  {T.cat !== 'trigger' && (
                    <div className="fb-port fb-port-in" data-input-for={n.id} />
                  )}
                  <div className="fb-port fb-port-out" onMouseDown={(e) => startWire(e, n.id)} />
                </div>
              );
            })}
          </div>
        </div>

        {/* Inspector */}
        <aside className="fb-inspector">
          {!sel ? (
            <div className="empty" style={{ padding: 24 }}>{t('flow.inspect.empty')}</div>
          ) : (
            <Inspector sel={sel} t={t} onUpdate={updateConfig} onDelete={() => deleteNode(sel.id)} onDup={() => duplicateNode(sel.id)} />
          )}
        </aside>
      </div>
    </>
  );
}

const NodeBody = ({ type, config }) => {
  const c = config || {};
  if (type === 'comment') return <div>quando comentar <code className="trigger-key">"{c.keyword}"</code> em <i>{c.post}</i></div>;
  if (type === 'dm')      return <div>quando alguém mandar DM com <code className="trigger-key">"{c.keyword}"</code></div>;
  if (type === 'story')   return <div>quando responder ao story</div>;
  if (type === 'follow')  return <div>quando começar a seguir</div>;
  if (type === 'sendDm')  return <div className="mock-bubble">{c.text}</div>;
  if (type === 'sendLink') return <div><div className="mock-link">🔗 {c.cta || 'Abrir'}</div><div className="muted mono" style={{ fontSize: 11, marginTop: 4 }}>{c.url}</div></div>;
  if (type === 'tag')     return <div>adicionar tag <span className="pill pill-pop">#{c.tag}</span></div>;
  if (type === 'wait')    return <div>aguardar <b>{c.mins}</b> min</div>;
  if (type === 'if')      return <div>se <i>{c.cond}</i></div>;
  if (type === 'split')   return <div>dividir tráfego <b>{c.ratio}</b></div>;
  return null;
};

function Inspector({ sel, t, onUpdate, onDelete, onDup }) {
  const T = NODE_TYPES[sel.type];
  const fields = (() => {
    if (sel.type === 'comment') return [{ k: 'keyword', label: 'Palavra-chave' }, { k: 'post', label: 'Em qual post' }];
    if (sel.type === 'dm') return [{ k: 'keyword', label: 'Palavra-chave' }];
    if (sel.type === 'story') return [{ k: 'keyword', label: 'Resposta contém', placeholder: '* = qualquer' }];
    if (sel.type === 'sendDm') return [{ k: 'text', label: 'Mensagem', area: true }];
    if (sel.type === 'sendLink') return [{ k: 'cta', label: 'Texto do botão' }, { k: 'url', label: 'URL' }];
    if (sel.type === 'tag') return [{ k: 'tag', label: 'Tag' }];
    if (sel.type === 'wait') return [{ k: 'mins', label: 'Minutos', type: 'number' }];
    if (sel.type === 'if') return [{ k: 'cond', label: 'Condição' }];
    if (sel.type === 'split') return [{ k: 'ratio', label: 'Distribuição' }];
    return [];
  })();
  return (
    <div className="insp">
      <div className="insp-head">
        <span className="fb-node-ic" style={{ background: T.color, color: '#fff' }}><T.icon size={14} /></span>
        <div style={{ flex: 1 }}>
          <div className="eyebrow">{t('flow.inspect')}</div>
          <div style={{ fontWeight: 700 }}>{t(T.labelKey)}</div>
        </div>
      </div>
      {fields.map((f) => (
        <div className="insp-field" key={f.k}>
          <label>{f.label}</label>
          {f.area ? (
            <textarea className="input" rows="3" value={sel.config[f.k] || ''} style={{ height: 'auto', padding: 10 }}
              onChange={(e) => onUpdate(sel.id, f.k, e.target.value)} />
          ) : (
            <input className="input" type={f.type || 'text'} value={sel.config[f.k] || ''} placeholder={f.placeholder || ''}
              onChange={(e) => onUpdate(sel.id, f.k, f.type === 'number' ? Number(e.target.value) : e.target.value)} />
          )}
        </div>
      ))}
      <div className="row" style={{ gap: 6, marginTop: 10 }}>
        <button className="btn btn-sm" onClick={onDup}><Icons.Copy size={14} /> {t('flow.duplicate')}</button>
        <button className="btn btn-sm" onClick={onDelete} style={{ color: 'var(--coral)' }}><Icons.Trash size={14} /> {t('flow.delete')}</button>
      </div>
    </div>
  );
}

const flowStyles = `
.fb-bar { display: flex; align-items: center; gap: 12px; padding: 0 4px; }
.fb-title { display: flex; flex-direction: column; flex: 1; min-width: 0; }
.fb-name { border: 0; background: transparent; font-family: inherit; font-size: 18px; font-weight: 700; color: var(--text); padding: 2px 0; outline: none; letter-spacing: -0.01em; }
.fb-name:focus { border-bottom: 1px dashed var(--grape); }

.fb-shell {
  display: grid;
  grid-template-columns: 240px 1fr 280px;
  gap: 0;
  height: calc(100vh - 100px);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  background: var(--surface);
  overflow: hidden;
  box-shadow: var(--shadow-card);
}
.fb-palette, .fb-inspector { padding: 14px; overflow-y: auto; background: var(--surface-2); }
.fb-palette { border-right: 1px solid var(--line); display: flex; flex-direction: column; gap: 12px; }
.fb-inspector { border-left: 1px solid var(--line); }

.fb-cat-label { font-size: 11px; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; color: var(--text-mute); margin-bottom: 6px; padding: 0 4px; }
.fb-pal-grid { display: flex; flex-direction: column; gap: 6px; }
.fb-pal-item {
  display: flex; align-items: center; gap: 10px;
  width: 100%;
  padding: 8px 10px;
  border-radius: 10px;
  background: var(--surface);
  border: 1px solid var(--line);
  cursor: pointer;
  font: inherit;
  font-size: 13px;
  font-weight: 500;
  color: var(--text);
  text-align: left;
  transition: transform 80ms, border-color 120ms, background 120ms;
}
.fb-pal-item:hover { transform: translateY(-1px); border-color: var(--line-strong); background: var(--surface); }
.fb-pal-item:hover svg:last-child { color: var(--grape); }
.fb-pal-item svg:last-child { color: var(--text-mute); margin-left: auto; }
.fb-pal-ic { width: 26px; height: 26px; border-radius: 8px; display: inline-flex; align-items: center; justify-content: center; }
.fb-pal-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fb-tip { margin-top: auto; padding: 10px; border-radius: 10px; background: color-mix(in oklch, var(--grape) 10%, var(--surface)); color: var(--text-soft); font-size: 11.5px; line-height: 1.45; }

.fb-canvas-wrap {
  position: relative;
  overflow: hidden;
  background: var(--surface-2);
  cursor: grab;
}
.fb-canvas-wrap:active { cursor: grabbing; }
.fb-grid {
  position: absolute; inset: 0;
  background-image:
    radial-gradient(color-mix(in oklch, var(--text-mute) 30%, transparent) 1px, transparent 1px);
  background-size: 22px 22px;
  background-position: 0 0;
  opacity: 0.5;
  pointer-events: none;
}
.fb-world { position: absolute; top: 0; left: 0; transform-origin: 0 0; }
.fb-edges { position: absolute; top: 0; left: 0; pointer-events: none; overflow: visible; }

.fb-node {
  position: absolute;
  background: var(--surface);
  border-radius: 14px;
  border: 1.5px solid var(--line);
  box-shadow: 0 1px 0 rgba(255,255,255,.04) inset, 0 4px 14px -6px rgba(20,18,40,.18);
  font-size: 12.5px;
  cursor: grab;
  user-select: none;
}
.fb-node:active { cursor: grabbing; }
.fb-node.sel { border-color: var(--grape); box-shadow: 0 0 0 4px color-mix(in oklch, var(--grape) 22%, transparent), 0 8px 24px -6px rgba(20,18,40,.25); }
.fb-node-head { display: flex; align-items: center; gap: 8px; padding: 8px 12px; border-radius: 12px 12px 0 0; }
.fb-node-ic { width: 22px; height: 22px; border-radius: 7px; display: inline-flex; align-items: center; justify-content: center; }
.fb-node-title { font-weight: 700; flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fb-node-cat { font-size: 10px; font-weight: 700; letter-spacing: 0.08em; color: var(--text-mute); }
.fb-node-body { padding: 10px 12px 14px; color: var(--text-soft); line-height: 1.4; word-break: break-word; }
.fb-node-body code, .fb-node-body .trigger-key { font-family: var(--font-mono); font-size: 11.5px; }
.fb-port { position: absolute; left: 50%; transform: translateX(-50%); width: 14px; height: 14px; border-radius: 50%; background: var(--surface); border: 2px solid var(--text-mute); cursor: crosshair; }
.fb-port:hover { background: var(--grape); border-color: var(--grape); }
.fb-port-in  { top: -8px; }
.fb-port-out { bottom: -8px; background: var(--text-mute); border-color: var(--surface); }
.fb-port-out:hover { background: var(--grape); }

.mock-bubble { background: linear-gradient(135deg, color-mix(in oklch, var(--cyan) 12%, var(--surface)), color-mix(in oklch, var(--grape) 10%, var(--surface))); padding: 8px 10px; border-radius: 12px 12px 12px 4px; color: var(--text); font-size: 12px; }
.mock-link { background: var(--surface-3); padding: 6px 10px; border-radius: 999px; display: inline-block; font-weight: 600; font-size: 12px; }

.insp-head { display: flex; align-items: center; gap: 10px; margin-bottom: 12px; }
.insp-field { display: flex; flex-direction: column; gap: 4px; margin-bottom: 10px; }
.insp-field label { font-size: 11.5px; font-weight: 600; color: var(--text-soft); }
.insp-field .input, .insp-field textarea { width: 100%; font-family: inherit; }
.insp-field textarea { border: 1px solid var(--line); border-radius: 10px; background: var(--surface); color: var(--text); font-size: 13px; outline: none; resize: vertical; }
.insp-field textarea:focus { border-color: var(--grape); box-shadow: 0 0 0 3px color-mix(in oklch, var(--grape) 22%, transparent); }
`;

window.FlowBuilder = FlowBuilder;
