import { useState, useRef, useCallback, useMemo } from "react";
import { T } from "./theme.js";

// ── Split type metadata ────────────────────────────
const SPLIT_TYPES = {
  y:       { label: "Y",        desc: "Split evenly",          icon: "⬡" },
  ab:      { label: "A/B",      desc: "Route all to A or B",   icon: "⇄" },
  cascade: { label: "Cascade",  desc: "A feeds into B",        icon: "⇢" },
  a_to_b:  { label: "A→B",      desc: "Serial path extension", icon: "↷" },
};

// ── Type-to-color mapping ───────────────────────────
const TYPE_COLORS = {
  od: T.amber, overdrive: T.amber, drive: T.amber,
  dist: T.red, distortion: T.red,
  fuzz: "#D060E0",
  mod: T.blue, chorus: T.blue, flange: T.blue, phaser: T.blue,
  tremolo: T.blue, vibrato: T.blue, rotary: T.blue,
  delay: "#60A0E0", echo: "#60A0E0", reverb: "#60C0D0",
  pitch: "#A060E0", comp: T.green, compressor: T.green,
  gate: T.green, filter: "#D0A060", wah: "#D0A060",
  eq: "#80A0B0", ir: T.green, cab: T.green, nam: "#E0A040",
  volume: T.textSec, boost: T.amber,
  split: "#B080C0", merge: "#80B0C0",
};

// ── Type-to-SVG-icon mapping (from pipedal icon set) ──
const TYPE_ICON_MAP = {
  od: "fx_distortion", overdrive: "fx_distortion", drive: "fx_distortion",
  dist: "fx_distortion", distortion: "fx_distortion", gain: "fx_distortion",
  fuzz: "fx_distortion",
  delay: "fx_delay", echo: "fx_delay",
  reverb: "fx_reverb",
  chorus: "fx_chorus", flange: "fx_flanger", flanger: "fx_flanger",
  phaser: "fx_phaser", tremolo: "fx_modulator", vibrato: "fx_modulator",
  rotary: "fx_modulator", modulator: "fx_modulator",
  pitch: "fx_pitch", harmonizer: "fx_pitch", shifter: "fx_pitch",
  comp: "fx_compressor", compressor: "fx_compressor",
  limiter: "fx_limiter",
  gate: "fx_gate", noise_gate: "fx_gate",
  filter: "fx_filter", wah: "fx_filter",
  eq: "fx_eq", graphic_eq: "fx_eq",
  parametric_eq: "fx_parametric_eq", multiband_eq: "fx_multiband_eq",
  ir: "fx_spatial", cab: "fx_spatial", cabinet: "fx_spatial",
  nam: "fx_simulator", capture: "fx_simulator", amp: "fx_amplifier",
  amplifier: "fx_amplifier",
  volume: "fx_constant", level: "fx_constant", boost: "fx_constant",
  split: "fx_split_a", merge: "fx_mixer",
  tuner: "fx_analyzer",
  mixer: "fx_mixer", utility: "fx_utility",
  plugin: "fx_plugin",
  instrument: "fx_instrument",
  reamp: "fx_converter",
  looper: "fx_oscillator",
};

const IMG_PATH = (import.meta.env.BASE_URL || '/ui/') + 'img/';

// ── SVG Block Icon component ─────────────────────────
function BlockIcon({ type, size = 14, style = {} }) {
  const key = (type || '').toLowerCase().trim();
  let icon = 'fx_plugin';
  let found = false;
  for (const [k, v] of Object.entries(TYPE_ICON_MAP)) {
    if (key === k || key.startsWith(k) || key.includes(k)) {
      icon = v;
      found = true;
      break;
    }
  }
  if (!found && key) {
    // Try direct match by replacing spaces/special chars
    const slug = key.replace(/[^a-z0-9]+/g, '_').replace(/^_|_$/g, '');
    if (TYPE_ICON_MAP[slug]) icon = TYPE_ICON_MAP[slug];
  }
  return (
    <img
      src={`${IMG_PATH}${icon}.svg`}
      alt={type || 'fx'}
      style={{
        width: size, height: size, flexShrink: 0,
        filter: 'none',
        objectFit: 'contain',
        ...style,
      }}
      onError={(e) => { e.target.style.display = 'none'; }}
    />
  );
}

function getBlockColor(type) {
  const key = (type || "").toLowerCase().trim();
  for (const [k, v] of Object.entries(TYPE_COLORS)) {
    if (key === k || key.startsWith(k) || key.includes(k)) return v;
  }
  return T.amber;
}

// ── Chain Arrow SVG ──────────────────────────────
function ChainArrow({ color = T.border, narrow = false }) {
  const w = narrow ? 14 : 18;
  return (
    <svg width={w} height="24" viewBox={`0 0 ${w} 24`} fill="none" style={{ flexShrink: 0 }}>
      <line x1="0" y1="12" x2={w - 6} y2="12" stroke={color} strokeWidth="2" strokeLinecap="round" />
      <polyline points={`${w-10},7 ${w-4},12 ${w-10},17`} fill="none" stroke={color} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
    </svg>
  );
}

// ── IN / OUT Terminator ─────────────────────────
function Terminator({ label, isLeft }) {
  return (
    <div style={{
      display: "flex", alignItems: "center", gap: 6, flexShrink: 0,
      flexDirection: isLeft ? "row" : "row-reverse",
    }}>
      {!isLeft && <ChainArrow />}
      <div style={{
        padding: "7px 12px", borderRadius: 6, fontSize: 10, fontWeight: 700,
        letterSpacing: ".12em", background: T.blueDim, color: T.blue,
        border: `1px solid ${T.blue}60`, textTransform: "uppercase", whiteSpace: "nowrap",
      }}>
        {label}
      </div>
      {isLeft && <ChainArrow />}
    </div>
  );
}

// ── Vertical Connection Bracket ───────────────────
function VertBracket({ height, direction }) {
  // direction: 'down' (split) or 'up' (merge)
  const dh = Math.max(height, 18);
  return (
    <svg width="20" height={dh} viewBox={`0 0 20 ${dh}`} fill="none" style={{ flexShrink: 0 }}>
      <line x1="10" y1="0" x2="10" y2={dh} stroke={T.border} strokeWidth="1.5" />
      <line x1="10" y1={direction === "down" ? 0 : dh - 6}
            x2={direction === "down" ? 16 : 16}
            y2={direction === "down" ? 0 : dh - 6}
            stroke={T.border} strokeWidth="1.5" />
      <polyline points={direction === "down"
        ? "14,4 18,0 14,-4"
        : `14,${dh-2} 18,${dh-6} 14,${dh-10}`}
        fill="none" stroke={T.border} strokeWidth="1.5" />
    </svg>
  );
}

// ── Split Block Tile ─────────────────────────────
function SplitBlockTile({ block, selected, onSelect, onToggle, onModelBrowser }) {
  const splitParams = block.params || {};
  const splitType = splitParams.splitType || "y";
  const st = SPLIT_TYPES[splitType] || SPLIT_TYPES.y;
  const enabled = !block.bypassed;
  const color = getBlockColor("split");
  const longPressRef = useRef(null);

  const handleTouchStart = useCallback(() => {
    longPressRef.current = setTimeout(() => {
      longPressRef.current = null;
      onModelBrowser?.(block.id);
    }, 500);
  }, [block.id, onModelBrowser]);

  const handleTouchEnd = useCallback(() => {
    if (longPressRef.current) {
      clearTimeout(longPressRef.current);
      longPressRef.current = null;
    }
  }, []);

  return (
    <div
      draggable
      onClick={() => onSelect(block.id)}
      onTouchStart={handleTouchStart}
      onTouchEnd={handleTouchEnd}
      onTouchMove={handleTouchEnd}
      onMouseDown={handleTouchEnd}
      onMouseUp={handleTouchEnd}
      style={{
        minWidth: 130, width: 130, height: 76, borderRadius: 8,
        background: `linear-gradient(135deg, ${T.panel}, #1A1520)`,
        border: `2px solid ${selected ? T.amber : color}60`,
        opacity: enabled ? 1 : 0.35, cursor: "pointer",
        display: "flex", flexDirection: "column", position: "relative",
        overflow: "hidden", transition: "all .15s ease", flexShrink: 0,
        boxShadow: selected ? `0 0 16px ${T.amber}44, inset 0 0 0 1px ${T.amber}22` : "none",
        transform: selected ? "scale(1.05)" : "scale(1)",
      }}
    >
      {/* Gradient accent */}
      <div style={{
        position: "absolute", top: 0, left: 0, right: 0, height: 3,
        background: `linear-gradient(90deg, #B080C0, #80B0C0)`,
      }} />
      {/* BYPASS LED */}
      <div onClick={(e) => { e.stopPropagation(); onToggle(block.id); }}
        style={{
          position: "absolute", top: 6, right: 6, width: 10, height: 10,
          borderRadius: "50%", background: enabled ? T.green : T.textDim,
          boxShadow: enabled ? `0 0 8px ${T.green}` : "none",
          transition: "all .15s", cursor: "pointer", zIndex: 2,
          border: `1px solid ${enabled ? `${T.green}88` : T.border}`,
        }} />
      {/* Content */}
      <div style={{ flex: 1, padding: "14px 10px 6px", display: "flex", flexDirection: "column", justifyContent: "center" }}>
        <div style={{
          fontSize: 12, fontWeight: 700, color: color,
          whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis",
          lineHeight: 1.3, display: "flex", alignItems: "center", gap: 6,
        }}>
          <BlockIcon type="split" size={16} />
          <span>SPLIT {st.label}</span>
        </div>
        <div style={{ fontSize: 9, color: T.textSec, marginTop: 2 }}>
          {st.desc}
        </div>
      </div>
      {/* Split path indicators */}
      <div style={{
        display: "flex", borderTop: `1px solid ${T.border}44`,
      }}>
        <div style={{
          flex: 1, fontSize: 8, fontWeight: 700, textAlign: "center",
          padding: "1px 0", color: "#B080C0",
          letterSpacing: ".1em", borderRight: `1px solid ${T.border}44`,
        }}>
          A {splitType === "ab" && (splitParams.activePath === "B" ? "—" : "✓")}
        </div>
        <div style={{
          flex: 1, fontSize: 8, fontWeight: 700, textAlign: "center",
          padding: "1px 0", color: "#80B0C0",
          letterSpacing: ".1em",
        }}>
          B {splitType === "ab" && splitParams.activePath === "B" ? "✓" : "—"}
        </div>
      </div>
    </div>
  );
}

// ── Merge Block Tile ──────────────────────────────
function MergeBlockTile({ block, selected, onSelect, onToggle, onModelBrowser }) {
  const mergeParams = block.params || {};
  const enabled = !block.bypassed;
  const longPressRef = useRef(null);

  const handleTouchStart = useCallback(() => {
    longPressRef.current = setTimeout(() => {
      longPressRef.current = null;
      onModelBrowser?.(block.id);
    }, 500);
  }, [block.id, onModelBrowser]);

  const handleTouchEnd = useCallback(() => {
    if (longPressRef.current) {
      clearTimeout(longPressRef.current);
      longPressRef.current = null;
    }
  }, []);

  return (
    <div
      draggable
      onClick={() => onSelect(block.id)}
      onTouchStart={handleTouchStart}
      onTouchEnd={handleTouchEnd}
      onTouchMove={handleTouchEnd}
      onMouseDown={handleTouchEnd}
      onMouseUp={handleTouchEnd}
      style={{
        minWidth: 130, width: 130, height: 76, borderRadius: 8,
        background: `linear-gradient(135deg, #15201A, ${T.panel})`,
        border: `2px solid ${selected ? T.amber : "#80B0C0"}60`,
        opacity: enabled ? 1 : 0.35, cursor: "pointer",
        display: "flex", flexDirection: "column", position: "relative",
        overflow: "hidden", transition: "all .15s ease", flexShrink: 0,
        boxShadow: selected ? `0 0 16px ${T.amber}44, inset 0 0 0 1px ${T.amber}22` : "none",
        transform: selected ? "scale(1.05)" : "scale(1)",
      }}
    >
      <div style={{
        position: "absolute", top: 0, left: 0, right: 0, height: 3,
        background: `linear-gradient(90deg, #80B0C0, #60A080)`,
      }} />
      <div onClick={(e) => { e.stopPropagation(); onToggle(block.id); }}
        style={{
          position: "absolute", top: 6, right: 6, width: 10, height: 10,
          borderRadius: "50%", background: enabled ? T.green : T.textDim,
          boxShadow: enabled ? `0 0 8px ${T.green}` : "none",
          transition: "all .15s", cursor: "pointer", zIndex: 2,
          border: `1px solid ${enabled ? `${T.green}88` : T.border}`,
        }} />
      <div style={{ flex: 1, padding: "14px 10px 6px", display: "flex", flexDirection: "column", justifyContent: "center" }}>
        <div style={{
          fontSize: 12, fontWeight: 700, color: "#80B0C0",
          whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis",
          lineHeight: 1.3, display: "flex", alignItems: "center", gap: 6,
        }}>
          <BlockIcon type="merge" size={16} />
          <span>MERGE</span>
        </div>
        <div style={{ fontSize: 9, color: T.textSec, marginTop: 2 }}>
          Blend {mergeParams.blend ?? 100}%
        </div>
      </div>
      <div style={{
        display: "flex", borderTop: `1px solid ${T.border}44`,
      }}>
        <div style={{
          flex: 1, fontSize: 8, fontWeight: 700, textAlign: "center",
          padding: "1px 0", color: "#B080C0",
          letterSpacing: ".1em", borderRight: `1px solid ${T.border}44`,
        }}>
          Lv {mergeParams.levelA ?? 100}
        </div>
        <div style={{
          flex: 1, fontSize: 8, fontWeight: 700, textAlign: "center",
          padding: "1px 0", color: "#80B0C0",
          letterSpacing: ".1em",
        }}>
          Lv {mergeParams.levelB ?? 100}
        </div>
      </div>
    </div>
  );
}

// ── Regular Block Tile ────────────────────────────
function BlockTile({ block, selected, onSelect, onToggle, pathLabel, onModelBrowser }) {
  const color = getBlockColor(block.type);
  const enabled = !block.bypassed;
  const longPressRef = useRef(null);

  const handleTouchStart = useCallback(() => {
    longPressRef.current = setTimeout(() => {
      longPressRef.current = null;
      onModelBrowser?.(block.id);
    }, 500);
  }, [block.id, onModelBrowser]);

  const handleTouchEnd = useCallback(() => {
    if (longPressRef.current) {
      clearTimeout(longPressRef.current);
      longPressRef.current = null;
    }
  }, []);

  return (
    <div
      draggable
      onClick={() => onSelect(block.id)}
      onTouchStart={handleTouchStart}
      onTouchEnd={handleTouchEnd}
      onTouchMove={handleTouchEnd}
      onMouseDown={handleTouchEnd}
      onMouseUp={handleTouchEnd}
      style={{
        minWidth: 120, width: 120, height: 76, borderRadius: 8,
        background: pathLabel === "B" ? "#1A1820" : T.panel,
        border: `2px solid ${selected ? T.amber : T.border}`,
        opacity: enabled ? 1 : 0.35, cursor: "pointer",
        display: "flex", flexDirection: "column", position: "relative",
        overflow: "hidden", transition: "all .15s ease", flexShrink: 0,
        boxShadow: selected
          ? `0 0 16px ${T.amber}44, inset 0 0 0 1px ${T.amber}22`
          : pathLabel === "B" ? "inset 0 0 0 1px rgba(128,176,192,0.15)" : "none",
        transform: selected ? "scale(1.05)" : "scale(1)",
      }}
    >
      {/* Color accent strip */}
      <div style={{
        position: "absolute", top: 0, left: 0, right: 0, height: 3,
        background: color,
        boxShadow: enabled ? `0 0 6px ${color}` : "none",
      }} />
      {/* Drag handle */}
      <div style={{
        position: "absolute", top: 5, left: 5, fontSize: 9, color: T.textDim,
        letterSpacing: 1.5, lineHeight: 1, cursor: "grab", opacity: 0.5,
      }}>
        ⋮⋮
      </div>
      {/* BYPASS LED */}
      <div onClick={(e) => { e.stopPropagation(); onToggle(block.id); }}
        style={{
          position: "absolute", top: 6, right: 6, width: 10, height: 10,
          borderRadius: "50%", background: enabled ? T.green : T.textDim,
          boxShadow: enabled ? `0 0 8px ${T.green}` : "none",
          transition: "all .15s", cursor: "pointer", zIndex: 2,
          border: `1px solid ${enabled ? `${T.green}88` : T.border}`,
        }}
        title={enabled ? "Active — tap to bypass" : "Bypassed — tap to enable"}
      />
      {/* Scribble strip */}
      <div style={{
        flex: 1, padding: "14px 10px 6px",
        display: "flex", flexDirection: "column", justifyContent: "center",
      }}>
        {pathLabel && (
          <div style={{
            position: "absolute", top: 5, right: 20, fontSize: 7,
            fontWeight: 700, color: pathLabel === "A" ? "#B080C0" : "#80B0C0",
            letterSpacing: ".08em", background: `${T.bg}88`,
            padding: "0 4px", borderRadius: 2, lineHeight: 1.4,
          }}>
            {pathLabel === "A" ? "A" : "B"}
          </div>
        )}
        <div style={{
          fontSize: 12, fontWeight: 600, color: T.textPrimary,
          whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis",
          lineHeight: 1.3, paddingRight: 16,
        }}>
          {block.name || block.type || "FX"}
        </div>
        <div style={{ display: "flex", alignItems: "center", gap: 5, marginTop: 3 }}>
          <BlockIcon type={block.type} size={14} />
          <span style={{
            fontSize: 9, fontWeight: 700, color, letterSpacing: ".08em",
            textTransform: "uppercase", background: `${color}18`,
            padding: "1px 5px", borderRadius: 3,
          }}>
            {(block.type || "fx").replace(/_/g, " ").toUpperCase()}
          </span>
        </div>
      </div>
    </div>
  );
}

// ── Empty state placeholder block ──────────────────
function EmptyBlock({ label }) {
  return (
    <div style={{
      minWidth: 120, width: 120, height: 76, borderRadius: 8,
      border: `1px dashed ${T.border}44`, flexShrink: 0,
      display: "flex", alignItems: "center", justifyContent: "center",
      fontSize: 9, color: T.textDim, letterSpacing: ".06em",
    }}>
      {label || "+"}
    </div>
  );
}

// ── Chain model builder ──────────────────────────
function buildChainModel(blocks) {
  const splitIdx = blocks.findIndex(b => b.type === "split");
  const mergeIdx = blocks.findIndex(b => b.type === "merge");

  // No split/merge — simple serial chain
  if (splitIdx === -1 || mergeIdx === -1) {
    return { type: "serial", blocks };
  }

  // Split/merge present — parallel routing
  const beforeSplit = blocks.slice(0, splitIdx);
  const splitBlock = blocks[splitIdx];
  const parallelBlocks = blocks.slice(splitIdx + 1, mergeIdx);
  const mergeBlock = blocks[mergeIdx];
  const afterMerge = blocks.slice(mergeIdx + 1);

  const pathABlocks = parallelBlocks.filter(b => !b.path || b.path === "A");
  const pathBBlocks = parallelBlocks.filter(b => b.path === "B");

  return {
    type: "parallel",
    beforeSplit,
    splitBlock,
    pathABlocks,
    pathBBlocks,
    mergeBlock,
    afterMerge,
    parallelBlockCount: Math.max(pathABlocks.length, pathBBlocks.length),
  };
}

// ── Block Chain (exported) ─────────────────────────
export default function BlockChain({
  blocks, selectedBlockId, onSelectBlock, onToggleBlock,
  onReorder, onAddBlock, onRemoveBlock, onModelBrowser,
}) {
  const scrollRef = useRef(null);
  const scrollBRef = useRef(null);
  const [dragIdx, setDragIdx] = useState(null);
  const [scrollPos, setScrollPos] = useState(0);

  const model = useMemo(() => buildChainModel(blocks), [blocks]);

  // ── HTML5 drag-to-reorder ──
  const handleDragStart = useCallback((e, idx) => {
    setDragIdx(idx);
    e.dataTransfer.effectAllowed = "move";
    e.dataTransfer.setData("text/plain", String(idx));
  }, []);

  const handleDragOver = useCallback((e) => {
    e.preventDefault();
    e.dataTransfer.dropEffect = "move";
  }, []);

  const handleDrop = useCallback((e, dropIdx) => {
    e.preventDefault();
    if (dragIdx !== null && dragIdx !== dropIdx && onReorder) {
      onReorder(dragIdx, dropIdx);
    }
    setDragIdx(null);
  }, [dragIdx, onReorder]);

  const handleDragEnd = useCallback(() => {
    setDragIdx(null);
  }, []);

  // ── Auto-scroll selected block into view ──
  const scrollToSelected = useCallback(() => {
    if (!scrollRef.current || !selectedBlockId) return;
    const chainBlocks = model.type === "serial" ? blocks : [
      ...model.beforeSplit,
      model.splitBlock,
      ...model.pathABlocks,
      model.mergeBlock,
      ...model.afterMerge,
    ].filter(Boolean);
    const idx = chainBlocks.findIndex(b => b.id === selectedBlockId);
    if (idx < 0) return;
    const child = scrollRef.current.children[idx + (model.type === "parallel" ? 1 : 1)];
    if (child) child.scrollIntoView({ behavior: "smooth", block: "nearest", inline: "center" });
  }, [selectedBlockId, model, blocks]);

  const prevSelected = useRef(selectedBlockId);
  if (selectedBlockId !== prevSelected.current) {
    prevSelected.current = selectedBlockId;
    setTimeout(scrollToSelected, 50);
  }

  // ── Sync scroll between rows in parallel mode ──
  const handleScrollMain = useCallback((e) => {
    setScrollPos(e.target.scrollLeft);
    if (scrollBRef.current) {
      scrollBRef.current.scrollLeft = e.target.scrollLeft;
    }
  }, []);

  const selectedBlock = blocks.find(b => b.id === selectedBlockId);

  // ── Serial Chain Renderer ──
  const renderSerialChain = () => (
    <div
      ref={scrollRef}
      onScroll={handleScrollMain}
      style={{
        display: "flex", alignItems: "center", gap: 4,
        padding: "10px 12px", overflowX: "auto", overflowY: "hidden",
        minHeight: 96, background: T.bg,
        borderBottom: `1px solid ${T.border}`,
        scrollBehavior: "smooth", WebkitOverflowScrolling: "touch",
      }}
    >
      <Terminator label="IN" isLeft />
      {blocks.map((block, idx) => (
        <div key={block.id} draggable
          onDragStart={(e) => handleDragStart(e, idx)}
          onDragOver={handleDragOver}
          onDrop={(e) => handleDrop(e, idx)}
          onDragEnd={handleDragEnd}
          style={{ display: "flex", alignItems: "center", gap: 4, flexShrink: 0 }}
        >
          <BlockTile
            block={block}
            selected={block.id === selectedBlockId}
            index={idx}
            onSelect={onSelectBlock}
            onToggle={onToggleBlock}
            onModelBrowser={onModelBrowser}
          />
          <ChainArrow />
        </div>
      ))}
      {blocks.length === 0 && (
        <div style={{
          flexShrink: 0, padding: "22px 20px", color: T.textDim, fontSize: 12,
          textAlign: "center", border: `1px dashed ${T.border}`, borderRadius: 8, minWidth: 140,
        }}>
          No blocks in chain
        </div>
      )}
      <Terminator label="OUT" isLeft={false} />
    </div>
  );

  // ── Parallel Chain Renderer ──
  const renderParallelChain = () => {
    const {
      beforeSplit, splitBlock, pathABlocks, pathBBlocks,
      mergeBlock, afterMerge, parallelBlockCount,
    } = model;

    // Build a paired layout for the parallel section
    const pairs = [];
    const maxLen = Math.max(pathABlocks.length, pathBBlocks.length);
    for (let i = 0; i < maxLen; i++) {
      pairs.push({
        a: pathABlocks[i] || null,
        b: pathBBlocks[i] || null,
      });
    }

    return (
      <div style={{ background: T.bg, borderBottom: `1px solid ${T.border}`, position: "relative" }}>
        {/* Row 1: Main path + Path A */}
        <div
          ref={scrollRef}
          onScroll={handleScrollMain}
          style={{
            display: "flex", alignItems: "center", gap: 4,
            padding: "8px 12px 0", overflowX: "auto", overflowY: "hidden",
            minHeight: 76, scrollBehavior: "smooth",
            WebkitOverflowScrolling: "touch",
          }}
        >
          <Terminator label="IN" isLeft />

          {/* Pre-split blocks */}
          {beforeSplit.map((block, idx) => (
            <div key={block.id} style={{ display: "flex", alignItems: "center", gap: 4, flexShrink: 0 }}>
              <BlockTile
                block={block}
                selected={block.id === selectedBlockId}
                index={idx}
                onSelect={onSelectBlock}
                onToggle={onToggleBlock}
                onModelBrowser={onModelBrowser}
              />
              <ChainArrow />
            </div>
          ))}

          {/* Split block */}
          <div style={{ display: "flex", alignItems: "center", gap: 4, flexShrink: 0 }}>
            <SplitBlockTile
              block={splitBlock}
              selected={splitBlock.id === selectedBlockId}
              onSelect={onSelectBlock}
              onToggle={onToggleBlock}
              onModelBrowser={onModelBrowser}
            />
            <ChainArrow />
          </div>

          {/* Path A blocks (parallel section) */}
          {pathABlocks.map((block, idx) => (
            <div key={block.id} style={{ display: "flex", alignItems: "center", gap: 4, flexShrink: 0 }}>
              <BlockTile
                block={block}
                selected={block.id === selectedBlockId}
                index={idx}
                onSelect={onSelectBlock}
                onToggle={onToggleBlock}
                pathLabel="A"
                onModelBrowser={onModelBrowser}
              />
              <ChainArrow />
            </div>
          ))}

          {/* Merge block */}
          {pathABlocks.length > 0 && (
            <ChainArrow />
          )}
          <div style={{ display: "flex", alignItems: "center", gap: 4, flexShrink: 0 }}>
            <MergeBlockTile
              block={mergeBlock}
              selected={mergeBlock.id === selectedBlockId}
              onSelect={onSelectBlock}
              onToggle={onToggleBlock}
              onModelBrowser={onModelBrowser}
            />
            <ChainArrow />
          </div>

          {/* Post-merge blocks */}
          {afterMerge.map((block, idx) => (
            <div key={block.id} style={{ display: "flex", alignItems: "center", gap: 4, flexShrink: 0 }}>
              <BlockTile
                block={block}
                selected={block.id === selectedBlockId}
                index={idx}
                onSelect={onSelectBlock}
                onToggle={onToggleBlock}
                onModelBrowser={onModelBrowser}
              />
              <ChainArrow />
            </div>
          ))}

          <Terminator label="OUT" isLeft={false} />
        </div>

        {/* Vertical connector zone */}
        <div style={{
          display: "flex", alignItems: "stretch",
          padding: "0 12px", position: "relative",
        }}>
          {/* Spacer area before split */}
          <div style={{ display: "flex", alignItems: "center", gap: 4, flexShrink: 0, minHeight: 24 }}>
            {/* IN terminator + pre-split blocks + split-blocks width as spacer */}
            <div style={{ width: "calc(100%)", position: "relative" }}>
              {/* We use absolute positioning relative to the row width */}
            </div>
          </div>
        </div>

        {/* Row 2: Path B */}
        <div
          ref={scrollBRef}
          style={{
            display: "flex", alignItems: "center", gap: 4,
            padding: "2px 12px 8px", overflowX: "auto", overflowY: "hidden",
            minHeight: 76, scrollBehavior: "smooth",
            WebkitOverflowScrolling: "touch",
            borderTop: `1px solid ${T.border}33`,
          }}
        >
          {/* Align spacer for IN + before split + split block */}
          <div style={{
            display: "flex", alignItems: "center", gap: 4, flexShrink: 0,
            paddingRight: 4, opacity: 0.3, pointerEvents: "none",
          }}>
            {/* Estimate: IN label (40px) + arrows per pre block + block widths + split block + arrows */}
            {beforeSplit.length > 0 && (
              <div style={{ display: "flex", alignItems: "center", gap: 4 }}>
                {beforeSplit.map((b, i) => (
                  <div key={b.id} style={{
                    minWidth: 124, height: 20, fontSize: 8, color: T.textDim,
                    display: "flex", alignItems: "center", gap: 4,
                  }}>
                    <span>──</span>
                  </div>
                ))}
              </div>
            )}
            {/* Show bracket connected from split block */}
          </div>

          {/* Downward arrow indicator */}
          <div style={{
            display: "flex", alignItems: "center", gap: 4, flexShrink: 0, opacity: 0.6,
          }}>
            <svg width="22" height="24" viewBox="0 0 22 24" fill="none" style={{ flexShrink: 0 }}>
              <line x1="8" y1="0" x2="8" y2="18" stroke={T.blue} strokeWidth="1.5" strokeDasharray="3,2" />
              <line x1="2" y1="18" x2="18" y2="18" stroke={T.blue} strokeWidth="1.5" />
              <polyline points="14,14 18,18 14,22" fill="none" stroke={T.blue} strokeWidth="1.5" />
            </svg>
          </div>

          {/* Path B blocks */}
          {pathBBlocks.length === 0 && (
            <div style={{
              flexShrink: 0, padding: "16px 16px", color: T.textDim, fontSize: 10,
              border: `1px dashed ${T.border}44`, borderRadius: 6,
              display: "flex", alignItems: "center", gap: 8,
            }}>
              <span style={{ color: "#80B0C0", fontSize: 8, fontWeight: 700, letterSpacing: ".1em" }}>PATH B</span>
              <span>Add blocks to Path B</span>
            </div>
          )}
          {pathBBlocks.map((block, idx) => (
            <div key={block.id} style={{ display: "flex", alignItems: "center", gap: 4, flexShrink: 0 }}>
              <BlockTile
                block={block}
                selected={block.id === selectedBlockId}
                index={idx + beforeSplit.length + 1}
                onSelect={onSelectBlock}
                onToggle={onToggleBlock}
                pathLabel="B"
              />
              <ChainArrow narrow />
            </div>
          ))}

          {/* Upward arrow to merge */}
          {pathBBlocks.length > 0 && (
            <div style={{ display: "flex", alignItems: "center", gap: 4, flexShrink: 0, opacity: 0.6 }}>
              <svg width="22" height="24" viewBox="0 0 22 24" fill="none" style={{ flexShrink: 0 }}>
                <line x1="14" y1="24" x2="14" y2="6" stroke={T.blue} strokeWidth="1.5" strokeDasharray="3,2" />
                <line x1="4" y1="6" x2="20" y2="6" stroke={T.blue} strokeWidth="1.5" />
                <polyline points="8,10 4,6 8,2" fill="none" stroke={T.blue} strokeWidth="1.5" />
              </svg>
            </div>
          )}

          {/* Gap spacer for merge + after-merge + OUT terminator - we add a flexible spacer */}
          <div style={{ flex: 1, minWidth: 20 }} />

          {/* Path B label at end */}
          {pathBBlocks.length > 0 && (
            <div style={{
              flexShrink: 0, fontSize: 7, fontWeight: 700, color: "#80B0C0",
              letterSpacing: ".12em", textTransform: "uppercase",
              padding: "0 8px", opacity: 0.5,
            }}>
              Path B
            </div>
          )}
        </div>

        {/* Path labels */}
        <div style={{
          position: "absolute", left: 0, top: 0, bottom: 0,
          width: 20, display: "flex", flexDirection: "column",
          pointerEvents: "none", opacity: 0.4,
        }}>
          <div style={{
            flex: 1, display: "flex", alignItems: "center", justifyContent: "center",
            fontSize: 8, fontWeight: 700, color: "#B080C0", writingMode: "vertical-rl",
            letterSpacing: ".2em",
          }}>
            A
          </div>
          <div style={{
            flex: 1, display: "flex", alignItems: "center", justifyContent: "center",
            fontSize: 8, fontWeight: 700, color: "#80B0C0", writingMode: "vertical-rl",
            letterSpacing: ".2em",
          }}>
            B
          </div>
        </div>
      </div>
    );
  };

  // ── Render ──
  return (
    <div style={{ display: "flex", flexDirection: "column" }}>
      {model.type === "parallel" ? renderParallelChain() : renderSerialChain()}

      {/* ── Add/Remove bar ── */}
      <div style={{
        display: "flex", gap: 8, padding: "8px 12px",
        borderBottom: `1px solid ${T.border}`, background: T.panel,
      }}>
        <button onClick={onAddBlock} style={{
          flex: 1, padding: "10px", borderRadius: 7, background: T.surface,
          border: `1px dashed ${T.border}`, color: T.textSec, fontSize: 12,
          fontWeight: 600, cursor: "pointer", letterSpacing: ".04em", transition: "all .12s",
        }}>
          + Add Block
        </button>
        {selectedBlockId && (
          <button onClick={() => onRemoveBlock(selectedBlockId)} style={{
            padding: "10px 14px", borderRadius: 7, background: "rgba(224,96,96,.15)",
            border: `1px solid rgba(224,96,96,.3)`, color: T.red, fontSize: 12,
            fontWeight: 600, cursor: "pointer", transition: "all .12s",
          }}>
            ✕ Remove
          </button>
        )}
      </div>
    </div>
  );
}
