/* ═══════════════════════════════════════════════════════════════════════════
   ═══ ★ Rule Builder — 제어 모드 비즈니스 룰 시각 편집 (드래그앤드롭) ★ ═══
   ═══════════════════════════════════════════════════════════════════════════ */

/* ─── 제어 노드 타입 정의 (16종) ─── */
/* out: 커스텀 출력 포트 배열. 없으면 기본 [{port:'out',label:'→',cls:''}] */
const CTRL_NODE_TYPES = {
  /* ── 트리거 ── */
  'timer':         {icon:'⏱',  label:'타이머',     rgb:'0,206,201',   cat:'트리거'},

  /* ── 조건 / 분기 ── */
  'condition':     {icon:'◇', label:'조건분기',   rgb:'253,203,110', cat:'조건',
    out:[{port:'yes',label:'Y',cls:'port-yes'},{port:'no',label:'N',cls:'port-no'}]},
  'validation':    {icon:'✔',  label:'데이터 검증', rgb:'255,107,129', cat:'조건',
    out:[{port:'pass',label:'✓',cls:'port-yes'},{port:'fail',label:'✗',cls:'port-no'}]},

  /* ── 액션 ── */
  'status-change': {icon:'🔄', label:'상태 변경', rgb:'108,92,231',  cat:'액션'},
  'auto-insert':   {icon:'📝', label:'자동 등록', rgb:'85,239,196',  cat:'액션'},
  'calculation':   {icon:'🧮', label:'계산/수식', rgb:'45,152,218',  cat:'액션'},
  'delete':        {icon:'🗑', label:'삭제/보관',  rgb:'255,71,87',   cat:'액션'},
  'document':      {icon:'📄', label:'문서 생성', rgb:'162,155,254', cat:'액션'},

  /* ── 흐름 제어 ── */
  'approval':      {icon:'✋', label:'승인/결재', rgb:'255,165,2',   cat:'흐름',
    out:[{port:'approved',label:'✓',cls:'port-yes'},{port:'rejected',label:'✗',cls:'port-no'}]},
  'delay':         {icon:'⏳', label:'대기/지연', rgb:'72,219,251',  cat:'흐름'},
  'loop':          {icon:'🔁', label:'반복',      rgb:'223,142,254', cat:'흐름',
    out:[{port:'each',label:'→',cls:''},{port:'done',label:'✓',cls:'port-yes'}]},
  'parallel':      {icon:'🔀', label:'병렬 실행', rgb:'0,206,201',   cat:'흐름'},
  'merge':         {icon:'⤵',  label:'병합/합류', rgb:'149,175,192', cat:'흐름'},

  /* ── 외부 연동 ── */
  'webhook':       {icon:'🌐', label:'외부 호출', rgb:'116,185,255', cat:'연동'},
  'notification':  {icon:'📨', label:'알림 발송', rgb:'253,121,168', cat:'연동'},

  /* ── 기록 ── */
  'log':           {icon:'📜', label:'로그 기록', rgb:'150,150,160', cat:'기록'},
};

/* ─── 상태 ─── */
let _ruleConns=[];
let _ruleIdSeq=0;
let _portDrag=null;
function _rid(p){return p+'-'+(++_ruleIdSeq);}

/* ═══════════════════════════════════════════════════════════════════════════
   1. 초기화 — 캔버스 드롭존
   ═══════════════════════════════════════════════════════════════════════════ */
function initRuleBuilder(){
  const cv=document.getElementById('canvas');
  if(!cv||cv._rbReady)return;
  cv._rbReady=true;

  cv.addEventListener('dragover',e=>{
    if(!_controlMode)return;
    e.preventDefault();
    e.dataTransfer.dropEffect='copy';
  });

  cv.addEventListener('drop',e=>{
    if(!_controlMode)return;
    e.preventDefault();
    let d;
    try{d=JSON.parse(e.dataTransfer.getData('text/plain'));}catch{return;}
    if(!d||!d.kind)return;

    /* 카드 흐름 보기 중이면 정리 */
    if(_activeFlowCardId){
      clearFlow();
      cv.querySelectorAll('.tpl-card').forEach(c=>{
        c.style.transition='opacity .3s';c.style.opacity='.5';
      });
    }

    const r=cv.getBoundingClientRect();
    const x=e.clientX-r.left+cv.scrollLeft;
    const y=e.clientY-r.top+cv.scrollTop;

    if(d.kind==='table') dropTable(d.name,x,y);
    else if(d.kind==='control') dropControl(d.type,x,y);
  });
}

/* ═══════════════════════════════════════════════════════════════════════════
   2. 팔레트 드래그
   ═══════════════════════════════════════════════════════════════════════════ */
function makePaletteItemDraggable(el,data){
  el.draggable=true;
  el.style.cursor='grab';
  el.addEventListener('dragstart',e=>{
    e.dataTransfer.setData('text/plain',JSON.stringify(data));
    e.dataTransfer.effectAllowed='copy';
    el.style.opacity='.5';
    setTimeout(()=>{el.style.opacity='';},50);
  });
}

/* ═══════════════════════════════════════════════════════════════════════════
   3. 드롭 → 노드 생성
   ═══════════════════════════════════════════════════════════════════════════ */
function dropTable(name,x,y){
  const cv=document.getElementById('canvas');
  if(!cv||!DB_TABLES[name])return;
  if(cv.querySelector(`.tbl-node[data-table="${name}"][data-rule]`)){
    toast(name+' 이미 캔버스에 있음','warn');return;
  }
  ensureRuleSvg();
  const node=buildTableNode(name,DB_TABLES[name],{x:x-100,y:y-40},redrawRuleConnections);
  node.dataset.rule='1';
  addIOPorts(node,name);
  _animateIn(node,cv);
  toast(name+' 추가','success');
}

function dropControl(type,x,y){
  const cv=document.getElementById('canvas');
  if(!cv||!CTRL_NODE_TYPES[type])return;
  ensureRuleSvg();
  const id=_rid('ctrl');
  const node=buildCtrlNode(id,type,{x:x-80,y:y-30});
  _animateIn(node,cv);
  toast(CTRL_NODE_TYPES[type].label+' 추가','success');
}

function _animateIn(node,cv){
  node.style.opacity='0';node.style.transform='scale(.5)';
  cv.appendChild(node);
  requestAnimationFrame(()=>{
    node.style.transition='opacity .25s,transform .25s cubic-bezier(.16,1,.3,1)';
    node.style.opacity='1';node.style.transform='scale(1)';
    setTimeout(()=>{node.style.transition='';},300);
  });
}

/* ═══════════════════════════════════════════════════════════════════════════
   4. 제어 노드 DOM 빌더
   ═══════════════════════════════════════════════════════════════════════════ */
function buildCtrlNode(id,type,pos){
  const def=CTRL_NODE_TYPES[type];
  const node=document.createElement('div');
  node.className='ctrl-action-node';
  node.dataset.nodeId=id;
  node.dataset.nodeType=type;
  node.style.left=pos.x+'px';
  node.style.top=pos.y+'px';
  node.style.setProperty('--na-rgb',def.rgb);

  const outDef=def.out||[{port:'out',label:'→',cls:''}];
  const outPorts=outDef.map(p=>
    `<div class="ctrl-io-port port-out ${p.cls}" data-port="${p.port}" data-node="${id}"><span class="port-label">${p.label}</span></div>`
  ).join('\n       ');

  node.innerHTML=`
    <div class="ctrl-io-port port-in" data-port="in" data-node="${id}"></div>
    <div class="ctrl-an-head">
      <div class="ctrl-an-icon">${def.icon}</div>
      <span class="ctrl-an-name">${def.label}</span>
      <button class="ctrl-an-del" onclick="event.stopPropagation();removeRuleNode('${id}')">✕</button>
    </div>
    <div class="ctrl-an-body" onclick="showNodeConfig('${id}')">
      <div class="ctrl-an-summary">클릭하여 설정</div>
    </div>
    <div class="ctrl-an-ports-out">${outPorts}</div>`;

  makeRuleNodeDraggable(node,node.querySelector('.ctrl-an-head'));
  initPortEvents(node);
  return node;
}

/* ─── 테이블 노드에 I/O 포트 추가 ─── */
function addIOPorts(node,name){
  const id='tbl-'+name;
  node.dataset.nodeId=id;

  const pi=document.createElement('div');
  pi.className='ctrl-io-port port-in tbl-io';
  pi.dataset.port='in';pi.dataset.node=id;
  node.appendChild(pi);

  const po=document.createElement('div');
  po.className='ctrl-io-port port-out tbl-io';
  po.dataset.port='out';po.dataset.node=id;
  po.innerHTML='<span class="port-label">→</span>';
  node.appendChild(po);

  initPortEvents(node);
}

/* ═══════════════════════════════════════════════════════════════════════════
   5. 노드 드래그
   ═══════════════════════════════════════════════════════════════════════════ */
function makeRuleNodeDraggable(node,handle){
  handle.addEventListener('mousedown',e=>{
    if(!_controlMode)return;
    e.preventDefault();e.stopPropagation();
    const sx=e.clientX,sy=e.clientY;
    const sl=node.offsetLeft,st=node.offsetTop;
    node.style.zIndex='30';
    function mv(ev){
      node.style.left=(sl+ev.clientX-sx)+'px';
      node.style.top=(st+ev.clientY-sy)+'px';
      redrawRuleConnections();
    }
    function up(){
      node.style.zIndex='20';
      document.removeEventListener('mousemove',mv);
      document.removeEventListener('mouseup',up);
    }
    document.addEventListener('mousemove',mv);
    document.addEventListener('mouseup',up);
  });
}

function removeRuleNode(nid){
  _ruleConns=_ruleConns.filter(c=>c.fid!==nid&&c.tid!==nid);
  const el=document.querySelector(`[data-node-id="${nid}"]`);
  if(el){
    el.style.transition='opacity .2s,transform .2s';
    el.style.opacity='0';el.style.transform='scale(.5)';
    setTimeout(()=>el.remove(),200);
  }
  setTimeout(redrawRuleConnections,250);
  toast('노드 삭제','info');
}

/* ═══════════════════════════════════════════════════════════════════════════
   6. 포트 연결 (output port → input port 드래그)
   ═══════════════════════════════════════════════════════════════════════════ */
function initPortEvents(node){
  /* output 포트: mousedown → 연결선 드래그 시작 */
  node.querySelectorAll('.ctrl-io-port.port-out').forEach(p=>{
    p.addEventListener('mousedown',e=>{
      if(!_controlMode)return;
      e.preventDefault();e.stopPropagation();
      startPortDrag(p,e);
    });
  });
  /* input 포트: mouseup → 연결 완료 / hover 표시 */
  node.querySelectorAll('.ctrl-io-port.port-in').forEach(p=>{
    p.addEventListener('mouseup',e=>{
      if(!_portDrag)return;
      e.stopPropagation();
      finishPortDrag(p);
    });
    p.addEventListener('mouseenter',()=>{if(_portDrag)p.classList.add('port-hover');});
    p.addEventListener('mouseleave',()=>p.classList.remove('port-hover'));
  });
}

function startPortDrag(el,e){
  const cv=document.getElementById('canvas');
  const svg=ensureRuleSvg();
  const cr=cv.getBoundingClientRect();
  const pr=el.getBoundingClientRect();
  const x1=pr.left+pr.width/2-cr.left+cv.scrollLeft;
  const y1=pr.top+pr.height/2-cr.top+cv.scrollTop;

  const line=document.createElementNS('http://www.w3.org/2000/svg','path');
  line.classList.add('rule-temp-line');
  line.setAttribute('d',`M${x1},${y1} L${x1},${y1}`);
  svg.appendChild(line);

  _portDrag={fromNode:el.dataset.node,fromPort:el.dataset.port,fromEl:el,line,x1,y1,cv,cr};
  cv.classList.add('port-dragging');
  el.classList.add('port-active');
  document.addEventListener('mousemove',_onPDMove);
  document.addEventListener('mouseup',_onPDEnd);
}

function _onPDMove(e){
  if(!_portDrag)return;
  const{cv,cr,x1,y1,line}=_portDrag;
  const x2=e.clientX-cr.left+cv.scrollLeft;
  const y2=e.clientY-cr.top+cv.scrollTop;
  const dx=x2-x1;
  line.setAttribute('d',`M${x1},${y1} C${x1+dx*.5},${y1} ${x1+dx*.5},${y2} ${x2},${y2}`);
}

function _onPDEnd(){_cleanPD();}

function finishPortDrag(toEl){
  if(!_portDrag)return;
  const fid=_portDrag.fromNode,fp=_portDrag.fromPort;
  const tid=toEl.dataset.node,tp=toEl.dataset.port;
  _cleanPD();
  if(fid===tid)return;
  if(_ruleConns.find(c=>c.fid===fid&&c.fp===fp&&c.tid===tid)){
    toast('이미 연결됨','warn');return;
  }
  addRuleConnection(fid,fp,tid,tp);
  toast('연결됨','success');
}

function _cleanPD(){
  if(!_portDrag)return;
  _portDrag.line.remove();
  _portDrag.cv.classList.remove('port-dragging');
  _portDrag.fromEl.classList.remove('port-active');
  document.removeEventListener('mousemove',_onPDMove);
  document.removeEventListener('mouseup',_onPDEnd);
  document.querySelectorAll('.port-hover').forEach(p=>p.classList.remove('port-hover'));
  _portDrag=null;
}

/* ═══════════════════════════════════════════════════════════════════════════
   7. 연결 관리
   ═══════════════════════════════════════════════════════════════════════════ */
function addRuleConnection(fid,fp,tid,tp){
  _ruleConns.push({id:_rid('conn'),fid,fp,tid,tp});
  redrawRuleConnections();
}

function removeRuleConnection(cid){
  _ruleConns=_ruleConns.filter(c=>c.id!==cid);
  redrawRuleConnections();
  toast('연결 삭제','info');
}

/* ═══════════════════════════════════════════════════════════════════════════
   8. 연결선 렌더링 (SVG bezier + delete badge)
   ═══════════════════════════════════════════════════════════════════════════ */
function ensureRuleSvg(){
  const cv=document.getElementById('canvas');
  let svg=document.getElementById('rule-svg');
  if(!svg){
    svg=document.createElementNS('http://www.w3.org/2000/svg','svg');
    svg.id='rule-svg';svg.classList.add('ctrl-svg');
    svg.setAttribute('width','100%');svg.setAttribute('height','100%');
    svg.style.overflow='visible';
    svg.innerHTML=`<defs>
      <marker id="arr-rule" markerWidth="8" markerHeight="6" refX="8" refY="3" orient="auto">
        <polygon points="0 0,8 3,0 6" fill="var(--cyan)" opacity=".8"/></marker>
      <marker id="arr-yes" markerWidth="8" markerHeight="6" refX="8" refY="3" orient="auto">
        <polygon points="0 0,8 3,0 6" fill="var(--green)" opacity=".8"/></marker>
      <marker id="arr-no" markerWidth="8" markerHeight="6" refX="8" refY="3" orient="auto">
        <polygon points="0 0,8 3,0 6" fill="var(--text-muted)" opacity=".5"/></marker>
    </defs>`;
    cv.appendChild(svg);
  }
  return svg;
}

function portPos(nid,pname){
  const cv=document.getElementById('canvas');
  const el=cv.querySelector(`[data-node="${nid}"][data-port="${pname}"]`);
  if(!el)return null;
  const pr=el.getBoundingClientRect();
  const cr=cv.getBoundingClientRect();
  return{
    x:pr.left+pr.width/2-cr.left+cv.scrollLeft,
    y:pr.top+pr.height/2-cr.top+cv.scrollTop
  };
}

function redrawRuleConnections(){
  const svg=document.getElementById('rule-svg');
  const cv=document.getElementById('canvas');
  if(!svg||!cv)return;

  svg.querySelectorAll('.rule-conn-path').forEach(p=>p.remove());
  cv.querySelectorAll('.rule-conn-badge').forEach(b=>b.remove());

  _ruleConns.forEach(c=>{
    const f=portPos(c.fid,c.fp);
    const t=portPos(c.tid,c.tp);
    if(!f||!t)return;

    /* bezier 곡선 */
    const dx=t.x-f.x;
    const path=document.createElementNS('http://www.w3.org/2000/svg','path');
    path.setAttribute('d',`M${f.x},${f.y} C${f.x+dx*.5},${f.y} ${f.x+dx*.5},${t.y} ${t.x},${t.y}`);
    path.classList.add('rule-conn-path');
    if(c.fp==='yes') path.classList.add('conn-yes');
    else if(c.fp==='no') path.classList.add('conn-no');
    path.dataset.conn=c.id;
    path.setAttribute('marker-end',
      c.fp==='yes'?'url(#arr-yes)':c.fp==='no'?'url(#arr-no)':'url(#arr-rule)');
    svg.appendChild(path);

    /* 삭제 뱃지 (중간점) */
    const mx=(f.x+t.x)/2, my=(f.y+t.y)/2;
    const b=document.createElement('div');
    b.className='rule-conn-badge';
    b.style.left=mx+'px';b.style.top=my+'px';
    b.innerHTML=`<span class="conn-x" onclick="event.stopPropagation();removeRuleConnection('${c.id}')">✕</span>`;
    cv.appendChild(b);
  });
}

/* ═══════════════════════════════════════════════════════════════════════════
   9. 설정 팝오버 (노드 클릭 → 상세 설정 폼)
   ═══════════════════════════════════════════════════════════════════════════ */
function showNodeConfig(nid){
  hideNodeConfig();
  const cv=document.getElementById('canvas');
  const node=cv.querySelector(`[data-node-id="${nid}"]`);
  if(!node)return;
  const type=node.dataset.nodeType;
  if(!CTRL_NODE_TYPES[type])return;

  const pop=document.createElement('div');
  pop.className='ctrl-cfg-pop';
  pop.id='node-cfg-pop';
  pop.dataset.nodeId=nid;
  pop.style.left=(node.offsetLeft+node.offsetWidth+12)+'px';
  pop.style.top=node.offsetTop+'px';
  pop.innerHTML=_buildCfgForm(type,nid);
  cv.appendChild(pop);
  requestAnimationFrame(()=>pop.classList.add('open'));
}

function hideNodeConfig(){
  document.getElementById('node-cfg-pop')?.remove();
}

function _buildCfgForm(type,nid){
  const def=CTRL_NODE_TYPES[type];
  const tables=Object.entries(DB_TABLES)
    .map(([n,m])=>`<option value="${n}">${n} (${m.label})</option>`).join('');
  let h=`<div class="cfg-hd">${def.icon} ${def.label} 설정</div>`;

  switch(type){
    case 'condition':
      h+=`<div class="cfg-sec"><label class="cfg-lb">필드</label>
        <select class="cfg-sel"><option value="">선택...</option>
        <option value="STATUS">STATUS (상태)</option>
        <option value="ORDER_DATE">ORDER_DATE (수주일)</option>
        <option value="AMOUNT">AMOUNT (금액)</option>
        <option value="USER_TYPE">USER_TYPE (유형)</option></select></div>
        <div class="cfg-sec"><label class="cfg-lb">연산자</label>
        <select class="cfg-sel"><option>=</option><option>≠</option>
        <option>></option><option>&lt;</option>
        <option>기한 경과</option><option>포함</option></select></div>
        <div class="cfg-sec"><label class="cfg-lb">값</label>
        <input class="cfg-inp" value="진행중" placeholder="비교값"></div>`;
      break;

    case 'status-change':
      h+=`<div class="cfg-sec"><label class="cfg-lb">대상 테이블</label>
        <select class="cfg-sel"><option value="">선택...</option>${tables}</select></div>
        <div class="cfg-sec"><label class="cfg-lb">변경 필드</label>
        <select class="cfg-sel"><option>STATUS</option><option>USER_TYPE</option>
        <option>ORDER_TYPE</option></select></div>
        <div class="cfg-sec"><label class="cfg-lb">변경값</label>
        <input class="cfg-inp" value="실패" placeholder="새 값"></div>`;
      break;

    case 'timer':
      h+=`<div class="cfg-sec"><label class="cfg-lb">트리거</label>
        <select class="cfg-sel"><option>필드 날짜 경과</option>
        <option>반복 일정 (Cron)</option><option>지연 실행</option></select></div>
        <div class="cfg-sec"><label class="cfg-lb">기준 필드</label>
        <select class="cfg-sel"><option>ORDER_DATE</option>
        <option>CREATED_DATE</option></select></div>
        <div class="cfg-sec"><label class="cfg-lb">경과 기준</label>
        <div style="display:flex;gap:.3rem">
        <input class="cfg-inp" type="number" value="0" style="width:50px">
        <select class="cfg-sel" style="flex:1"><option>일</option>
        <option>시간</option><option>주</option></select></div></div>`;
      break;

    case 'notification':
      h+=`<div class="cfg-sec"><label class="cfg-lb">채널</label>
        <select class="cfg-sel"><option>이메일</option><option>SMS</option>
        <option>푸시</option><option>Slack</option></select></div>
        <div class="cfg-sec"><label class="cfg-lb">수신자</label>
        <select class="cfg-sel"><option>담당자</option><option>관리자</option>
        <option>전체</option></select></div>
        <div class="cfg-sec"><label class="cfg-lb">메시지</label>
        <textarea class="cfg-ta" rows="2">수주 #{ORDER_ID} 실패 처리됨</textarea></div>`;
      break;

    case 'auto-insert':
      h+=`<div class="cfg-sec"><label class="cfg-lb">대상 테이블</label>
        <select class="cfg-sel"><option value="">선택...</option>${tables}</select></div>
        <div class="cfg-sec"><label class="cfg-lb">필드 매핑</label>
        <div class="cfg-map"><div class="cfg-map-r">소스 → 대상</div></div>
        <button class="cfg-add-btn" onclick="toast('매핑 추가 (mockup)','info')">+ 매핑 추가</button></div>`;
      break;

    case 'log':
      h+=`<div class="cfg-sec"><label class="cfg-lb">대상</label>
        <select class="cfg-sel"><option>AUDIT_LOG</option></select></div>
        <div class="cfg-sec"><label class="cfg-lb">내용</label>
        <input class="cfg-inp" value="상태 변경" placeholder="액션 설명"></div>`;
      break;

    case 'calculation':
      h+=`<div class="cfg-sec"><label class="cfg-lb">대상 테이블</label>
        <select class="cfg-sel"><option value="">선택...</option>${tables}</select></div>
        <div class="cfg-sec"><label class="cfg-lb">결과 필드</label>
        <select class="cfg-sel"><option>AMOUNT</option><option>BUDGET</option>
        <option>QTY</option></select></div>
        <div class="cfg-sec"><label class="cfg-lb">수식</label>
        <input class="cfg-inp" value="QTY * UNIT_PRICE" placeholder="예: QTY * UNIT_PRICE"></div>`;
      break;

    case 'approval':
      h+=`<div class="cfg-sec"><label class="cfg-lb">승인자</label>
        <select class="cfg-sel"><option>팀장</option><option>부서장</option>
        <option>관리자</option><option>지정 사용자</option></select></div>
        <div class="cfg-sec"><label class="cfg-lb">승인 조건</label>
        <input class="cfg-inp" value="AMOUNT > 1000만" placeholder="조건식"></div>
        <div class="cfg-sec"><label class="cfg-lb">타임아웃</label>
        <div style="display:flex;gap:.3rem">
        <input class="cfg-inp" type="number" value="3" style="width:50px">
        <select class="cfg-sel" style="flex:1"><option>일</option>
        <option>시간</option><option>주</option></select></div></div>
        <div class="cfg-sec"><label class="cfg-lb">타임아웃 시</label>
        <select class="cfg-sel"><option>자동 승인</option><option>자동 거부</option>
        <option>에스컬레이션</option></select></div>`;
      break;

    case 'webhook':
      h+=`<div class="cfg-sec"><label class="cfg-lb">URL</label>
        <input class="cfg-inp" value="https://api.example.com/hook" placeholder="https://..."></div>
        <div class="cfg-sec"><label class="cfg-lb">메서드</label>
        <select class="cfg-sel"><option>POST</option><option>GET</option>
        <option>PUT</option><option>DELETE</option></select></div>
        <div class="cfg-sec"><label class="cfg-lb">헤더</label>
        <input class="cfg-inp" value="Authorization: Bearer ..." placeholder="Key: Value"></div>
        <div class="cfg-sec"><label class="cfg-lb">페이로드</label>
        <textarea class="cfg-ta" rows="2">{"order_id": "#{ORDER_ID}", "status": "#{STATUS}"}</textarea></div>`;
      break;

    case 'validation':
      h+=`<div class="cfg-sec"><label class="cfg-lb">대상 필드</label>
        <select class="cfg-sel"><option>AMOUNT</option><option>STATUS</option>
        <option>USER_NAME</option><option>ORDER_DATE</option></select></div>
        <div class="cfg-sec"><label class="cfg-lb">검증 규칙</label>
        <select class="cfg-sel"><option>필수값 (NOT NULL)</option><option>범위 체크</option>
        <option>정규식 매칭</option><option>참조 무결성</option>
        <option>커스텀 조건</option></select></div>
        <div class="cfg-sec"><label class="cfg-lb">조건/패턴</label>
        <input class="cfg-inp" value="> 0" placeholder="조건식 또는 패턴"></div>`;
      break;

    case 'delete':
      h+=`<div class="cfg-sec"><label class="cfg-lb">대상 테이블</label>
        <select class="cfg-sel"><option value="">선택...</option>${tables}</select></div>
        <div class="cfg-sec"><label class="cfg-lb">삭제 방식</label>
        <select class="cfg-sel"><option>소프트 삭제 (STATUS→삭제)</option>
        <option>보관 (아카이브 이동)</option><option>영구 삭제</option></select></div>
        <div class="cfg-sec"><label class="cfg-lb">조건</label>
        <input class="cfg-inp" placeholder="WHERE 조건" value="STATUS = '만료'"></div>`;
      break;

    case 'document':
      h+=`<div class="cfg-sec"><label class="cfg-lb">문서 유형</label>
        <select class="cfg-sel"><option>견적서</option><option>발주서</option>
        <option>세금계산서</option><option>보고서</option>
        <option>커스텀 템플릿</option></select></div>
        <div class="cfg-sec"><label class="cfg-lb">출력 형식</label>
        <select class="cfg-sel"><option>PDF</option><option>Excel</option>
        <option>HTML</option></select></div>
        <div class="cfg-sec"><label class="cfg-lb">수신자</label>
        <select class="cfg-sel"><option>담당자</option><option>관리자</option>
        <option>고객</option><option>지정 이메일</option></select></div>`;
      break;

    case 'delay':
      h+=`<div class="cfg-sec"><label class="cfg-lb">대기 시간</label>
        <div style="display:flex;gap:.3rem">
        <input class="cfg-inp" type="number" value="30" style="width:60px">
        <select class="cfg-sel" style="flex:1"><option>분</option>
        <option>시간</option><option>일</option><option>초</option></select></div></div>
        <div class="cfg-sec"><label class="cfg-lb">대기 조건</label>
        <select class="cfg-sel"><option>무조건 대기</option>
        <option>조건 충족 시 즉시 진행</option>
        <option>외부 이벤트 수신 시</option></select></div>`;
      break;

    case 'loop':
      h+=`<div class="cfg-sec"><label class="cfg-lb">대상 테이블</label>
        <select class="cfg-sel"><option value="">선택...</option>${tables}</select></div>
        <div class="cfg-sec"><label class="cfg-lb">필터</label>
        <input class="cfg-inp" placeholder="WHERE 조건" value="STATUS = '진행중'"></div>
        <div class="cfg-sec"><label class="cfg-lb">최대 반복</label>
        <input class="cfg-inp" type="number" value="100" style="width:70px"></div>`;
      break;

    case 'merge':
      h+=`<div class="cfg-sec"><label class="cfg-lb">합류 조건</label>
        <select class="cfg-sel"><option>모든 분기 완료 (AND)</option>
        <option>하나만 완료 (OR)</option>
        <option>N개 이상 완료</option></select></div>
        <div class="cfg-sec"><label class="cfg-lb">타임아웃</label>
        <div style="display:flex;gap:.3rem">
        <input class="cfg-inp" type="number" value="60" style="width:60px">
        <select class="cfg-sel" style="flex:1"><option>분</option>
        <option>시간</option></select></div></div>`;
      break;

    case 'parallel':
      h+=`<div class="cfg-sec"><label class="cfg-lb">분기 수</label>
        <input class="cfg-inp" type="number" value="2" style="width:60px" min="2" max="10"></div>
        <div class="cfg-sec"><label class="cfg-lb">실행 방식</label>
        <select class="cfg-sel"><option>동시 실행</option>
        <option>순차 실행 (우선순위)</option></select></div>`;
      break;

    default:
      h+='<div class="cfg-sec" style="color:var(--text-muted);font-size:.55rem">설정 없음</div>';
  }

  h+=`<div class="cfg-ft">
    <button class="cfg-btn save" onclick="saveCfg('${nid}')">저장</button>
    <button class="cfg-btn" onclick="hideNodeConfig()">닫기</button></div>`;
  return h;
}

function saveCfg(nid){
  const pop=document.getElementById('node-cfg-pop');
  const node=document.querySelector(`[data-node-id="${nid}"]`);
  if(!pop||!node)return;

  const sels=[...pop.querySelectorAll('.cfg-sel')];
  const inps=[...pop.querySelectorAll('.cfg-inp')];
  const sm=node.querySelector('.ctrl-an-summary');
  const type=node.dataset.nodeType;

  if(type==='condition'&&sels[0]&&sels[1]&&inps[0]){
    const f=sels[0].value||'?',o=sels[1].value||'=',v=inps[0].value||'?';
    if(sm) sm.textContent=`${f} ${o} "${v}"`;
  } else if(type==='status-change'&&sels[0]&&sels[1]&&inps[0]){
    const t=sels[0].value||'?',fd=sels[1].value||'STATUS',v=inps[0].value||'?';
    if(sm) sm.textContent=`${t}.${fd} → "${v}"`;
  } else if(type==='timer'&&sels.length>=3&&inps[0]){
    const fd=sels[1]?.value||'?',n=inps[0].value||'0';
    const u=sels[2]?.options?.[sels[2].selectedIndex]?.text||'일';
    if(sm) sm.textContent=`${fd} +${n}${u} 경과`;
  } else if(type==='notification'&&sels[0]&&sels[1]){
    const ch=sels[0].options[sels[0].selectedIndex]?.text||'?';
    const to=sels[1].options[sels[1].selectedIndex]?.text||'?';
    if(sm) sm.textContent=`${ch} → ${to}`;
  } else if(type==='auto-insert'&&sels[0]){
    if(sm) sm.textContent=`→ ${sels[0].value||'?'} INSERT`;
  } else if(type==='log'&&inps[0]){
    if(sm) sm.textContent=`로그: ${inps[0].value||'?'}`;
  } else if(type==='calculation'&&sels[0]&&sels[1]&&inps[0]){
    if(sm) sm.textContent=`${sels[0].value}.${sels[1].value} = ${inps[0].value}`;
  } else if(type==='approval'&&sels[0]&&inps[0]){
    if(sm) sm.textContent=`${sels[0].value} 승인 (${inps[0].value})`;
  } else if(type==='webhook'&&inps[0]){
    const method=sels[0]?.value||'POST';
    const url=(inps[0].value||'').replace(/^https?:\/\//,'').slice(0,25);
    if(sm) sm.textContent=`${method} ${url}...`;
  } else if(type==='validation'&&sels[0]&&sels[1]){
    if(sm) sm.textContent=`${sels[0].value} ${sels[1].value}`;
  } else if(type==='delete'&&sels[0]&&sels[1]){
    if(sm) sm.textContent=`${sels[0].value} ${sels[1].value}`;
  } else if(type==='document'&&sels[0]&&sels[1]){
    if(sm) sm.textContent=`${sels[0].value} → ${sels[1].value}`;
  } else if(type==='delay'&&inps[0]&&sels[0]){
    if(sm) sm.textContent=`${inps[0].value}${sels[0].value} 대기`;
  } else if(type==='loop'&&sels[0]){
    const filter=inps[0]?.value||'전체';
    if(sm) sm.textContent=`${sels[0].value} 반복 (${filter})`;
  } else if(type==='merge'&&sels[0]){
    if(sm) sm.textContent=sels[0].value;
  } else if(type==='parallel'&&inps[0]){
    if(sm) sm.textContent=`${inps[0].value||2}개 분기 동시`;
  }

  hideNodeConfig();
  toast('설정 저장','success');
}

/* ═══════════════════════════════════════════════════════════════════════════
   10. 데모 시나리오: 수주 자동 실패 → 재고 연쇄 실패
   ═══════════════════════════════════════════════════════════════════════════ */
function loadDemoScenario(){
  const cv=document.getElementById('canvas');
  if(!cv)return;

  /* 기존 규칙 노드 정리 */
  cv.querySelectorAll('.ctrl-action-node,.tbl-node[data-rule]').forEach(n=>n.remove());
  cv.querySelectorAll('.rule-conn-badge').forEach(b=>b.remove());
  document.getElementById('rule-svg')?.remove();
  _ruleConns=[];_ruleIdSeq=0;

  /* 카드 흐름 보기 중이면 정리 */
  if(_activeFlowCardId){
    clearFlow();
    cv.querySelectorAll('.tpl-card').forEach(c=>{
      c.style.transition='opacity .3s';c.style.opacity='.5';
    });
  }

  ensureRuleSvg();
  const ch=cv.clientHeight||700;
  const my=Math.round(ch/2);

  /* 1. ORDER_MASTER 테이블 */
  const om=buildTableNode('ORDER_MASTER',DB_TABLES['ORDER_MASTER'],
    {x:30,y:my-100},redrawRuleConnections);
  om.dataset.rule='1';
  addIOPorts(om,'ORDER_MASTER');
  cv.appendChild(om);

  /* 2. 타이머 노드 */
  const tm=buildCtrlNode(_rid('ctrl'),'timer',{x:280,y:my-60});
  tm.querySelector('.ctrl-an-summary').textContent='ORDER_DATE 경과 시';
  cv.appendChild(tm);

  /* 3. 조건분기 노드 */
  const cd=buildCtrlNode(_rid('ctrl'),'condition',{x:490,y:my-60});
  cd.querySelector('.ctrl-an-summary').textContent='STATUS = "진행중"';
  cv.appendChild(cd);

  /* 4. 상태 변경 — ORDER_MASTER */
  const s1=buildCtrlNode(_rid('ctrl'),'status-change',{x:710,y:my-140});
  s1.querySelector('.ctrl-an-summary').textContent='ORDER_MASTER.STATUS → "실패"';
  cv.appendChild(s1);

  /* 5. 상태 변경 — INVENTORY (연쇄) */
  const s2=buildCtrlNode(_rid('ctrl'),'status-change',{x:710,y:my+30});
  s2.querySelector('.ctrl-an-summary').textContent='INVENTORY.STATUS → "실패"';
  cv.appendChild(s2);

  /* 연결 (DOM 레이아웃 후) */
  setTimeout(()=>{
    addRuleConnection('tbl-ORDER_MASTER','out', tm.dataset.nodeId,'in');
    addRuleConnection(tm.dataset.nodeId,'out',  cd.dataset.nodeId,'in');
    addRuleConnection(cd.dataset.nodeId,'yes',  s1.dataset.nodeId,'in');
    addRuleConnection(s1.dataset.nodeId,'out',  s2.dataset.nodeId,'in');
    toast('데모: 수주일 경과 → 수주 실패 → 재고 연쇄 실패','success');
  },80);
}

/* ═══════════════════════════════════════════════════════════════════════════
   11. 정리 (제어 모드 종료 시)
   ═══════════════════════════════════════════════════════════════════════════ */
function cleanupRuleBuilder(){
  const cv=document.getElementById('canvas');
  if(!cv)return;
  cv.querySelectorAll('.ctrl-action-node,.tbl-node[data-rule],.rule-conn-badge').forEach(n=>n.remove());
  document.getElementById('rule-svg')?.remove();
  hideNodeConfig();
  _ruleConns=[];
  _ruleIdSeq=0;
  _portDrag=null;
}

/* ─── 외부 클릭 → 팝오버 닫기 ─── */
document.addEventListener('click',e=>{
  if(!document.getElementById('node-cfg-pop'))return;
  if(e.target.closest('.ctrl-cfg-pop'))return;
  if(e.target.closest('.ctrl-an-body'))return;
  hideNodeConfig();
});
