// ─── تشخیص نوع رویداد از متن پیام ───────────────────────
function detectEventType(text) {
  const t = text.toLowerCase();
  if (/سلام|هلو|درود|خوندم|دیدم|اومدم/.test(t))            return { type: 'script',   reason: 'پیام اولیه — اسکریپت جواب می‌ده' };
  if (/پرداخت|کارت|بانک|واریز|رها|نیمه|ناقص/.test(t))       return { type: 'trigger',  reason: 'سیگنال پرداخت رها شده — تریگر فوری فعال' };
  if (/مشاوره|جلسه|قرار|وقت|زمان|ساعت/.test(t))             return { type: 'followup', reason: 'درخواست زمان‌بندی — فالوآپ مدیریت می‌کنه' };
  if (/قیمت|هزینه|تخفیف|اقساط|چقدر|کمپین/.test(t))          return { type: 'campaign', reason: 'سوال قیمت — کمپین مناسب پیدا می‌کنه' };
  if (/خریدم|پرداخت کردم|ثبت‌نام|خرید|گرفتم/.test(t))       return { type: 'campaign', reason: 'تأیید خرید — کمپین Upsell فعال' };
  if (/نیستم|بعداً|فردا|بعد|بیشتر فکر|شاید/.test(t))        return { type: 'followup', reason: 'تعلل — فالوآپ زمان‌بندی می‌کنه' };
  if (/چطور|چی|چرا|توضیح|بگو|بیشتر/.test(t))                return { type: 'script',   reason: 'سوال عمومی — اسکریپت هدایت می‌کنه' };
  return { type: 'bot', reason: 'پیام نامشخص — بات نگه می‌داره' };
}

// ─── پاسخ شبیه‌سازی‌شده برای هر handler ──────────────────
function simulateReply(ownerType, msgText) {
  const t = msgText;
  const replies = {
    trigger: [
      'متوجه شدیم پرداختت ناتمام موند 🙏 الان یه لینک امن برات می‌فرستیم.',
      'یه اتفاق افتاده که نیاز به پیگیری فوری داره. یه لحظه صبر کن.',
    ],
    followup: [
      'وقت مشاوره‌ات ثبت شد. قبل از جلسه یادآوری می‌فرستیم.',
      'باشه، یه زمان مناسب هماهنگ می‌کنیم. چه ساعتی بهتره؟',
    ],
    campaign: [
      'بذار مشاورمون قیمت دقیق رو باهاتون در میان بذاره. شماره داری؟',
      'ممنون از خریدت! یه پیشنهاد ویژه برات داریم 🎁',
      'این کمپین دقیقاً برای این موقعیت طراحی شده. بیشتر بگو.',
    ],
    script: [
      'سلام! در خدمتتم 🙏 بفرمایید.',
      'چطور می‌تونم کمکتون کنم؟',
      'هدفتون از برنامه‌نویسی چیه؟',
    ],
    bot: [
      'پیامتون دریافت شد. به زودی پاسخ می‌دیم.',
      'ممنون از تماستون. یه لحظه صبر کنید.',
    ],
  };
  const list = replies[ownerType] || replies.bot;
  return list[Math.floor(Math.random() * list.length)];
}

// ─── کامپوننت چت شبیه‌ساز ────────────────────────────────
const ChatSimulator = ({ priorityOrder, colors, handlerLabels, entities }) => {
  const [messages, setMessages]       = useState([]);
  const [input, setInput]             = useState('');
  const [activeOwner, setActiveOwner] = useState(null);
  const [viewMode, setViewMode]       = useState('chat'); // chat | admin
  const bottomRef = useRef(null);

  useEffect(() => { bottomRef.current?.scrollIntoView({ behavior: 'smooth' }); }, [messages]);

  const send = () => {
    const txt = input.trim();
    if (!txt) return;
    const { type, reason } = detectEventType(txt);

    const inIdx    = priorityOrder.indexOf(type);
    const curIdx   = activeOwner ? priorityOrder.indexOf(activeOwner) : 999;
    const wins     = inIdx <= curIdx;
    const newOwner = wins ? type : activeOwner;
    const prevOwner = activeOwner;

    // موجودیت فعال برای log
    const activeEntForLog = ((entities && entities[newOwner]) || [])[0];

    // log سیستمی
    const logParts = [
      `تشخیص: ${handlerLabels[type]} (اولویت #${inIdx + 1})`,
      wins && prevOwner && prevOwner !== type
        ? `${handlerLabels[prevOwner]} pause شد`
        : !wins
        ? `${handlerLabels[newOwner]} همچنان در کنترل (اولویت بالاتر)`
        : null,
      activeEntForLog ? `← ${activeEntForLog.name}` : null,
    ].filter(Boolean);

    // موجودیت فعال برای نمایش
    const ents = (entities && entities[newOwner]) || [];
    const activeEnt = ents[0];
    const entLabel = newOwner === 'campaign' ? 'کمپین فعال'
                   : newOwner === 'script'   ? 'اسکریپت فعال'
                   : newOwner === 'followup' ? 'الگوی فالوآپ'
                   : newOwner === 'trigger'  ? 'تریگر'
                   : 'بات';

    // داده ادمین
    const adminData = {
      'handler فعال': handlerLabels[newOwner],
      'اولویت': `#${priorityOrder.indexOf(newOwner) + 1}`,
      ...(activeEnt ? { [entLabel]: activeEnt.name } : {}),
      'تغییر': wins && prevOwner && prevOwner !== type ? `${handlerLabels[prevOwner]} → ${handlerLabels[newOwner]}` : 'بدون تغییر',
      'دلیل': reason,
      'action': newOwner === 'trigger' ? 'ارسال پیام فوری' : newOwner === 'followup' ? 'زمان‌بندی تماس' : newOwner === 'campaign' ? 'اجرای flow کمپین' : newOwner === 'script' ? 'اجرای اسکریپت' : 'نگه‌داری لید',
    };

    setMessages(prev => [...prev,
      { kind: 'user',   text: txt },
      { kind: 'log',    parts: logParts, owner: newOwner, changed: wins && prevOwner !== newOwner },
      { kind: 'reply',  text: simulateReply(newOwner, txt), adminData, owner: newOwner },
    ]);
    setActiveOwner(newOwner);
    setInput('');
  };

  const reset = () => { setMessages([]); setActiveOwner(null); };

  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>

      {/* نوار بالا */}
      <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
        {/* مالک فعلی */}
        <div style={{
          flex: 1, display: 'flex', alignItems: 'center', gap: 8,
          padding: '7px 12px', borderRadius: 9,
          background: activeOwner ? colors[activeOwner] + '10' : 'rgba(255,255,255,0.03)',
          border: `1px solid ${activeOwner ? colors[activeOwner] + '30' : 'rgba(255,255,255,0.07)'}`,
          fontSize: 11,
        }}>
          <div style={{ width: 7, height: 7, borderRadius: '50%', background: activeOwner ? colors[activeOwner] : '#334155' }} />
          <span style={{ color: '#475569' }}>مالک فعلی:</span>
          <span style={{ color: activeOwner ? colors[activeOwner] : '#334155', fontWeight: 700 }}>
            {activeOwner ? handlerLabels[activeOwner] : 'هنوز پیامی نیست'}
          </span>
        </div>
        {/* سوئیچ نمایش */}
        <div style={{ display: 'flex', background: 'rgba(255,255,255,0.04)', borderRadius: 8, padding: 3, gap: 2 }}>
          {[['chat','چت'],['admin','ادمین']].map(([v, l]) => (
            <button key={v} onClick={() => setViewMode(v)} style={{
              padding: '4px 12px', borderRadius: 6, border: 'none', cursor: 'pointer', fontSize: 11,
              background: viewMode === v ? 'rgba(255,255,255,0.1)' : 'transparent',
              color: viewMode === v ? '#e2e8f0' : '#475569', fontWeight: viewMode === v ? 600 : 400,
            }}>{l}</button>
          ))}
        </div>
        {messages.length > 0 && (
          <button onClick={reset} style={{ fontSize: 10, color: '#334155', background: 'none', border: 'none', cursor: 'pointer', padding: '4px 8px' }}>ریست</button>
        )}
      </div>

      {/* پیام‌ها */}
      <div style={{ height: 340, overflowY: 'auto', display: 'flex', flexDirection: 'column', gap: 6, padding: '4px 2px' }}>
        {messages.length === 0 && (
          <div style={{ textAlign: 'center', color: '#334155', fontSize: 12, marginTop: 60 }}>
            یه پیام بفرست تا ببینیم چی فعال می‌شه 👇
          </div>
        )}
        {messages.map((m, i) => {
          if (m.kind === 'user') return (
            <div key={i} style={{ display: 'flex', justifyContent: 'flex-start' }}>
              <div style={{ maxWidth: '72%', padding: '8px 12px', borderRadius: '12px 12px 12px 4px', fontSize: 12, lineHeight: 1.6, background: 'rgba(59,130,246,0.12)', border: '1px solid rgba(59,130,246,0.2)', color: '#93C5FD' }}>
                {m.text}
              </div>
            </div>
          );

          if (m.kind === 'log') return (
            <div key={i} style={{ display: 'flex', justifyContent: 'center' }}>
              <div style={{
                padding: '5px 12px', borderRadius: 20, fontSize: 10, lineHeight: 1.7,
                background: m.changed ? colors[m.owner] + '12' : 'rgba(255,255,255,0.04)',
                border: `1px solid ${m.changed ? colors[m.owner] + '30' : 'rgba(255,255,255,0.06)'}`,
                color: m.changed ? colors[m.owner] : '#475569',
                display: 'flex', gap: 8, flexWrap: 'wrap', justifyContent: 'center',
              }}>
                {m.parts.map((p, pi) => (
                  <span key={pi}>
                    {pi > 0 && <span style={{ opacity: 0.3, marginLeft: 8 }}>·</span>}
                    {p}
                  </span>
                ))}
              </div>
            </div>
          );

          if (m.kind === 'reply') return (
            <div key={i} style={{ display: 'flex', justifyContent: 'flex-end' }}>
              <div style={{
                maxWidth: '78%', borderRadius: '12px 12px 4px 12px', overflow: 'hidden',
                border: `1px solid ${colors[m.owner]}30`,
              }}>
                {/* هدر handler */}
                <div style={{ padding: '5px 12px', background: colors[m.owner] + '20', fontSize: 10, fontWeight: 700, color: colors[m.owner], display: 'flex', alignItems: 'center', gap: 6 }}>
                  <div style={{ width: 6, height: 6, borderRadius: '50%', background: colors[m.owner] }} />
                  {handlerLabels[m.owner]}
                </div>
                {/* محتوا */}
                <div style={{ padding: '8px 12px', background: 'rgba(255,255,255,0.04)', fontSize: 12, lineHeight: 1.7 }}>
                  {viewMode === 'chat' ? (
                    <span style={{ color: '#cbd5e1' }}>{m.text}</span>
                  ) : (
                    <div style={{ display: 'flex', flexDirection: 'column', gap: 4 }}>
                      {Object.entries(m.adminData).map(([k, v]) => (
                        <div key={k} style={{ display: 'flex', gap: 8, alignItems: 'baseline' }}>
                          <span style={{ color: '#475569', minWidth: 80, fontSize: 10 }}>{k}</span>
                          <span style={{ color: '#94a3b8', fontFamily: 'JetBrains Mono', fontSize: 11 }}>{v}</span>
                        </div>
                      ))}
                    </div>
                  )}
                </div>
              </div>
            </div>
          );
          return null;
        })}
        <div ref={bottomRef} />
      </div>

      {/* input */}
      <div style={{ display: 'flex', gap: 8 }}>
        <input
          value={input}
          onChange={e => setInput(e.target.value)}
          onKeyDown={e => e.key === 'Enter' && send()}
          placeholder="پیام بفرست... مثلاً: سلام / مشاوره می‌خوام / قیمت چنده؟"
          style={{ flex: 1, padding: '9px 14px', borderRadius: 10, fontSize: 12, background: 'rgba(255,255,255,0.05)', border: '1px solid rgba(255,255,255,0.1)', color: '#e2e8f0', outline: 'none' }}
        />
        <button onClick={send} style={{ padding: '9px 16px', borderRadius: 10, border: 'none', background: '#3B82F6', color: '#fff', fontSize: 12, fontWeight: 600, cursor: 'pointer', flexShrink: 0 }}>
          ارسال
        </button>
      </div>

      {/* نمونه‌ها */}
      <div style={{ display: 'flex', gap: 6, flexWrap: 'wrap' }}>
        {['سلام','قیمت چنده؟','مشاوره می‌خوام','پرداختم رها شد','بعداً بهتون زنگ می‌زنم','خریدم','نمی‌دونم'].map(s => (
          <button key={s} onClick={() => setInput(s)} style={{ padding: '3px 10px', borderRadius: 20, fontSize: 10, cursor: 'pointer', border: '1px solid rgba(255,255,255,0.08)', background: 'rgba(255,255,255,0.03)', color: '#475569' }}>
            {s}
          </button>
        ))}
      </div>
    </div>
  );
};

// ─── engine: شبیه‌ساز اولویت ─────────────────────────────
// هر رویداد یه handler_type داره. engine بر اساس ترتیب فعلی
// تعیین می‌کنه کی کنترل رو می‌گیره.
function runSimulation(events, priorityOrder) {
  let activeType = null;
  return events.map(ev => {
    const inIdx  = priorityOrder.indexOf(ev.type);
    const curIdx = activeType ? priorityOrder.indexOf(activeType) : 999;
    const wins   = inIdx <= curIdx; // عدد کوچکتر = اولویت بالاتر
    const prev   = activeType;
    if (wins) activeType = ev.type;
    return { ...ev, owner: wins ? ev.type : activeType, changed: wins && prev !== ev.type, from: wins && prev ? prev : null };
  });
}

// ─── سناریوهای واقعی سیستم ────────────────────────────────
const SCENARIOS = [
  {
    id: 's1', name: 'علی — لید جدید', emoji: '👤',
    desc: 'لید تازه وارد می‌شه، اسکریپت شروع می‌کنه، بعد لینک پرداخت رو رها می‌کنه',
    events: [
      { t:0,  icon:'👤', label:'وارد شد',             type:'script'   },
      { t:10, icon:'💬', label:'پیام اول فرستاد',      type:'script'   },
      { t:25, icon:'📢', label:'کمپین خوش‌آمدگویی',   type:'campaign' },
      { t:45, icon:'🔗', label:'لینک پرداخت باز کرد', type:'trigger'  },
      { t:70, icon:'⏰', label:'۲۴ ساعت بی‌جواب',      type:'campaign' },
      { t:90, icon:'✅', label:'پرداخت کرد',           type:'campaign' },
    ],
  },
  {
    id: 's2', name: 'سارا — No-Show', emoji: '📅',
    desc: 'مشاوره رزرو کرد ولی نیومد — تریگر فوری فعال می‌شه',
    events: [
      { t:0,  icon:'👤', label:'وارد شد',             type:'script'   },
      { t:15, icon:'📢', label:'کمپین فعال شد',        type:'campaign' },
      { t:30, icon:'📅', label:'مشاوره رزرو کرد',     type:'followup' },
      { t:50, icon:'❌', label:'No-Show مشاوره',       type:'trigger'  },
      { t:65, icon:'📞', label:'فالوآپ پیگیری',        type:'followup' },
      { t:85, icon:'💰', label:'خرید کرد',             type:'campaign' },
    ],
  },
  {
    id: 's3', name: 'رضا — لید سرد', emoji: '🧊',
    desc: 'بعد از ۳۰ روز بی‌خبری کمپین بازگشت فعال می‌شه',
    events: [
      { t:0,  icon:'👤', label:'وارد شد',             type:'script'   },
      { t:10, icon:'😶', label:'۳۰ روز بی‌خبر',        type:'bot'      },
      { t:35, icon:'📢', label:'کمپین بازگشت',         type:'campaign' },
      { t:55, icon:'💬', label:'دوباره پیام داد',       type:'trigger'  },
      { t:75, icon:'📞', label:'مشاوره خواست',          type:'followup' },
    ],
  },
  {
    id: 's4', name: 'مریم — وسط کمپین', emoji: '⚡',
    desc: 'وسط کمپین یه تریگر فوری میاد — کی برنده می‌شه؟',
    events: [
      { t:0,  icon:'📢', label:'کمپین پیگیری فعاله',  type:'campaign' },
      { t:20, icon:'⚡', label:'تریگر keyword',         type:'trigger'  },
      { t:40, icon:'📢', label:'کمپین ادامه داد',       type:'campaign' },
      { t:60, icon:'⏰', label:'فالوآپ زمان‌بندی',      type:'followup' },
      { t:80, icon:'✅', label:'ثبت‌نام کرد',           type:'campaign' },
    ],
  },
  {
    id: 's5', name: 'حسین — بعد از خرید', emoji: '🛒',
    desc: 'بعد از خرید کمپین Upsell شروع می‌کنه',
    events: [
      { t:0,  icon:'✅', label:'خرید کرد',             type:'campaign' },
      { t:15, icon:'📢', label:'Upsell فعال شد',        type:'campaign' },
      { t:35, icon:'💬', label:'سوال فرستاد',           type:'script'   },
      { t:55, icon:'⚡', label:'تریگر keyword خاص',     type:'trigger'  },
      { t:75, icon:'📢', label:'Upsell ادامه داد',       type:'campaign' },
    ],
  },
  {
    id: 's6', name: 'نیلوفر — ریکاوری', emoji: '🔄',
    desc: 'مکالمه رها شد — بات نگه می‌داره تا handler بیاد',
    events: [
      { t:0,  icon:'👤', label:'وارد شد',              type:'script'   },
      { t:15, icon:'😶', label:'مکالمه قطع شد',        type:'bot'      },
      { t:30, icon:'⚡', label:'تریگر ریکاوری',         type:'trigger'  },
      { t:50, icon:'📢', label:'کمپین ریکاوری',         type:'campaign' },
      { t:70, icon:'📞', label:'فالوآپ تلفنی',          type:'followup' },
    ],
  },
];

// ─── کامپوننت Timeline یک سناریو ─────────────────────────
const ScenarioTimeline = ({ scenario, priorityOrder, colors }) => {
  const result = runSimulation(scenario.events, priorityOrder);
  const maxT   = Math.max(...scenario.events.map(e => e.t)) + 15;

  return (
    <div style={{
      background: 'rgba(255,255,255,0.02)',
      border: '1px solid rgba(255,255,255,0.07)',
      borderRadius: 12, padding: '16px 20px', marginBottom: 10,
    }}>
      {/* header سناریو */}
      <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 14 }}>
        <span style={{ fontSize: 16 }}>{scenario.emoji}</span>
        <div>
          <div style={{ fontSize: 13, fontWeight: 700, color: '#e2e8f0' }}>{scenario.name}</div>
          <div style={{ fontSize: 11, color: '#475569' }}>{scenario.desc}</div>
        </div>
      </div>

      {/* خط timeline */}
      <div style={{ position: 'relative', margin: '32px 0 28px' }}>
        {/* track */}
        <div style={{ height: 4, background: 'rgba(255,255,255,0.06)', borderRadius: 2, position: 'relative' }}>
          {/* رنگ‌آمیزی بر اساس owner */}
          {result.map((ev, i) => {
            const next = result[i + 1];
            const x1 = ev.t / maxT * 100;
            const x2 = next ? next.t / maxT * 100 : 100;
            return (
              <div key={i} style={{
                position: 'absolute', right: x1 + '%', width: (x2 - x1) + '%',
                height: '100%', background: colors[ev.owner] || '#475569',
                borderRadius: 2, opacity: 0.8,
              }} />
            );
          })}
        </div>

        {/* pin‌های رویداد */}
        {result.map((ev, i) => (
          <div key={i} style={{
            position: 'absolute', right: (ev.t / maxT * 100) + '%',
            transform: 'translateX(50%)',
            top: -24, display: 'flex', flexDirection: 'column', alignItems: 'center',
          }}>
            <div style={{ fontSize: 13, marginBottom: 3 }}>{ev.icon}</div>
            <div style={{
              width: 8, height: 8, borderRadius: '50%',
              background: colors[ev.owner], border: '2px solid #0d0d14',
              position: 'relative', top: 14,
            }} />
            <div style={{
              position: 'absolute', top: 28, fontSize: 9, color: '#64748b',
              whiteSpace: 'nowrap', textAlign: 'center', maxWidth: 70,
              lineHeight: 1.3,
            }}>{ev.label}</div>
          </div>
        ))}
      </div>

      {/* لاگ تغییر owner */}
      <div style={{ display: 'flex', flexDirection: 'column', gap: 3, marginTop: 8 }}>
        {result.filter(ev => ev.changed).map((ev, i) => (
          <div key={i} style={{ display: 'flex', alignItems: 'center', gap: 8, fontSize: 10 }}>
            <div style={{ width: 6, height: 6, borderRadius: '50%', background: colors[ev.owner], flexShrink: 0 }} />
            <span style={{ color: '#475569' }}>t+{ev.t}</span>
            <span style={{ color: colors[ev.owner], fontWeight: 600 }}>{ev.owner === 'trigger' ? 'تریگر' : ev.owner === 'followup' ? 'فالوآپ' : ev.owner === 'campaign' ? 'کمپین' : ev.owner === 'script' ? 'اسکریپت' : 'بات'}</span>
            <span style={{ color: '#334155' }}>کنترل گرفت</span>
            {ev.from && <span style={{ color: '#1e293b' }}>← از {ev.from === 'trigger' ? 'تریگر' : ev.from === 'followup' ? 'فالوآپ' : ev.from === 'campaign' ? 'کمپین' : ev.from === 'script' ? 'اسکریپت' : 'بات'}</span>}
          </div>
        ))}
      </div>
    </div>
  );
};

// ─── MindMap — نقشه زنده با انیمیشن bezier (طراحی اصلی) ─────
const MindMap = ({ entities, colors, handlerLabels, brainScript, items, onBrainClick, onRefresh, onClose }) => {

  /* ── load Vazirmatn ── */
  useEffect(() => {
    if (!document.getElementById('_vzf')) {
      const l = document.createElement('link');
      l.id='_vzf'; l.rel='stylesheet';
      l.href='https://fonts.googleapis.com/css2?family=Vazirmatn:wght@300;400;500;600;700;800&display=swap';
      document.head.appendChild(l);
    }
  }, []);

  /* ── refs ── */
  const stageRef = useRef(null);
  const rafRef   = useRef(null);
  const animRef  = useRef({ i:0, phase:'incoming', start:0, paused:false, pausedEl:0 });
  const logRef   = useRef([]);
  const msgsRef  = useRef([]);
  const [idle, setIdle]   = useState(false);

  /* ── state ── */
  const [tick, setTick]             = useState(0);
  const [stageScale, setStageScale] = useState(0.78);
  const [chatInput, setChatInput]   = useState('');

  /* ── helpers ── */
  const BX = 500, BY = 348;
  const D  = { incoming:1300, thinking:1400, routing:1600, delivered:1300, gap:600 };
  const col  = (h, a) => a == null ? `oklch(0.74 0.19 ${h})` : `oklch(0.74 0.19 ${h} / ${a})`;
  const fa   = (s) => String(s).replace(/[0-9]/g, d => '۰۱۲۳۴۵۶۷۸۹'[+d]);
  const ctP  = (ax,ay,bx2,by2,sign) => {
    const mx=(ax+bx2)/2,my=(ay+by2)/2,dx=bx2-ax,dy=by2-ay;
    const L=Math.hypot(dx,dy)||1,nx=-dy/L,ny=dx/L,o=L*.14*sign;
    return {x:mx+nx*o,y:my+ny*o};
  };
  const quad = (p0,cp,p1,t) => {
    const m=1-t,a=m*m,b=2*m*t,c=t*t;
    return {x:a*p0.x+b*cp.x+c*p1.x,y:a*p0.y+b*cp.y+c*p1.y};
  };
  const E = React.createElement;

  /* ── categories (همان موقعیت طراحی اصلی) ── */
  const HUE = {trigger:350,bot:322,followup:292,campaign:264,script:238};
  const rawCats = [
    {id:'trigger', name:'تریگرها',   desc:'نقطه ورود',   x:505,y:74, sign:-1},
    {id:'bot',     name:'بات‌ها',     desc:'پاسخ خودکار', x:122,y:196,sign:1 },
    {id:'followup',name:'فالوآپ‌ها', desc:'پیگیری',       x:892,y:212,sign:1 },
    {id:'campaign',name:'کمپین‌ها',  desc:'کمپین فعال',  x:852,y:560,sign:-1},
    {id:'script',  name:'اسکریپت‌ها',desc:'مکالمه',      x:150,y:566,sign:-1},
  ];
  const LEAF_DEF = {
    trigger:  ['لید جدید','پیام ورودی','فرم سایت'],
    bot:      ['بات پاسخ','دستیار فروش'],
    followup: ['No-Show','پرداخت رها شده','پیگیری مشاوره'],
    campaign: ['جذب لید جدید','Upsell بعد خرید','وفاداری'],
    script:   ['تماس اول','تماس دوم','ریکاوری مکالمه'],
  };
  const CNT_DEF = {trigger:6,bot:4,followup:12,campaign:33,script:8};

  const cats = rawCats.map(c => {
    const h=HUE[c.id];
    const cp=ctP(BX,BY,c.x,c.y,c.sign);
    const path=`M ${BX} ${BY} Q ${cp.x.toFixed(1)} ${cp.y.toFixed(1)} ${c.x} ${c.y}`;
    const ents=entities[c.id]||[];
    const leafNames=ents.length>0?ents.slice(0,3).map(e=>e.name):LEAF_DEF[c.id];
    const base=Math.atan2(c.y-BY,c.x-BX);
    const n=leafNames.length,spread=.52,R=98;
    const leaves=leafNames.map((name,i)=>{
      const ang=base+spread*(i-(n-1)/2);
      const lx=c.x+R*Math.cos(ang),ly=c.y+R*Math.sin(ang);
      return {name,x:+lx.toFixed(1),y:+ly.toFixed(1),conn:`M ${c.x} ${c.y} L ${lx.toFixed(1)} ${ly.toFixed(1)}`,hue:h,idx:i};
    });
    const count=ents.length>0?fa(ents.length):fa(CNT_DEF[c.id]);
    return {...c,hue:h,cp,path,leaves,count};
  });
  const byId=Object.fromEntries(cats.map(c=>[c.id,c]));

  /* ── animation loop (throttled to ~30fps for performance) ── */
  const frameRef = useRef(0);
  const pushLog=()=>{
    const a=animRef.current,msgs=msgsRef.current,m=msgs[a.i];
    const t=byId[m?.cat]; if(!t)return;
    const lf=t.leaves[m.leaf]||t.leaves[0];
    logRef.current=[...logRef.current,
      {intent:m.intent,dest:`${t.name} · ${lf?.name||''}`,confPct:fa(Math.round(m.conf*100))+'٪',color:col(t.hue),glow:col(t.hue,.8)}
    ].slice(-7);
  };
  useEffect(()=>{
    const a=animRef.current; a.start=performance.now();
    const loop=()=>{
      rafRef.current=requestAnimationFrame(loop);
      if(a.paused)return;
      const now=performance.now(),el=now-a.start,dur=D[a.phase];
      if(el>=dur){
        if     (a.phase==='incoming') {a.phase='thinking'; a.start=now;}
        else if(a.phase==='thinking') {a.phase='routing';  a.start=now;}
        else if(a.phase==='routing')  {a.phase='delivered';a.start=now;pushLog();}
        else if(a.phase==='delivered'){a.phase='gap';      a.start=now;}
        else{
          const len=msgsRef.current.length;
          if(len===0){a.paused=true;}
          else{a.i=(a.i+1)%len;a.phase='incoming';a.start=now;}
        }
      }
      /* throttle re-render to ~30fps */
      frameRef.current=(frameRef.current+1)%2;
      if(frameRef.current===0) setTick(t=>t+1);
    };
    rafRef.current=requestAnimationFrame(loop);
    return ()=>{if(rafRef.current)cancelAnimationFrame(rafRef.current);};
  },[]);

  /* ── polling پیام‌های واقعی از سرور ── */
  const CATS_VALID = new Set(['trigger','bot','followup','campaign','script']);
  const fetchEvents = () => {
    window.api('/orchestrator/recent-events?limit=30').then(r => {
      if (!r.success || !r.data?.length) { setIdle(true); return; }
      /* فقط پیام‌های ۱۰ دقیقه اخیر — قدیمی‌تر از اون idle می‌شه */
      const cutoff = Date.now() - 10 * 60 * 1000;
      const fresh = r.data.filter(ev => new Date(ev.time).getTime() >= cutoff);
      if (!fresh.length) { setIdle(true); msgsRef.current = []; return; }
      const mapped = fresh.map(ev => {
        const cat   = CATS_VALID.has(ev.cat) ? ev.cat : 'bot';
        const { type: detectedType } = detectEventType(ev.text || '');
        const finalCat = cat !== 'bot' ? cat : detectedType;
        const cn = byId[finalCat] || byId['bot'];
        const conf = 0.75 + Math.random() * 0.22;
        return {
          text:   ev.text,
          src:    0,
          cat:    cn.id,
          leaf:   Math.floor(Math.random() * (cn.leaves?.length || 1)),
          conf,
          intent: (ev.text || '').slice(0, 24),
          reason: `از ${ev.platform || 'پیام‌رسان'} — مسیر: ${cn.name}`,
          name:   ev.name,
        };
      });
      const prev = msgsRef.current;
      if (JSON.stringify(prev.map(m=>m.text)) !== JSON.stringify(mapped.map(m=>m.text))) {
        msgsRef.current = mapped;
        setIdle(false);
        const a = animRef.current;
        if (a.i >= mapped.length) { a.i = 0; a.phase = 'incoming'; a.start = performance.now(); }
      }
    }).catch(() => setIdle(true));
  };
  useEffect(() => {
    fetchEvents();
    const tid = setInterval(fetchEvents, 12000);
    return () => clearInterval(tid);
  }, []); // eslint-disable-line

  /* ── stage scale measurement ── */
  useEffect(()=>{
    const measure=()=>{
      const el=stageRef.current; if(!el)return;
      const w=el.clientWidth-8,h=el.clientHeight-200;
      const s=Math.max(.32,Math.min(w/1012,h/712,1.0));
      setStageScale(prev=>Math.abs(s-prev)>.005?s:prev);
    };
    measure();const tid=setTimeout(measure,200);
    window.addEventListener('resize',measure);
    return ()=>{clearTimeout(tid);window.removeEventListener('resize',measure);};
  },[]);

  /* ── controls ── */
  const select=(i)=>{
    const a=animRef.current;
    a.i=i%msgsRef.current.length;a.phase='incoming';a.start=performance.now();a.paused=false;
    setTick(t=>t+1);
  };
  const toggle=()=>{
    const a=animRef.current,now=performance.now();
    if(a.paused){a.paused=false;a.start=now-a.pausedEl;}
    else        {a.paused=true; a.pausedEl=now-a.start;}
    setTick(t=>t+1);
  };
  const sendChat=()=>{
    const text=chatInput.trim(); if(!text)return;
    setChatInput('');
    const {type}=detectEventType(text);
    const cn=byId[type]||byId['bot'];
    const conf=.80+Math.random()*.17;
    msgsRef.current=[...msgsRef.current,
      {text,src:0,cat:cn.id,leaf:0,conf,intent:text.slice(0,22),reason:`پیام کاربر — مسیر: ${cn.name}`}
    ];
    const a=animRef.current;
    a.phase='incoming'; a.start=performance.now(); a.paused=false;
    a.i=msgsRef.current.length-1;
    setIdle(false);
    setTick(t=>t+1);
  };

  /* ── render values (هر frame محاسبه می‌شه) ── */
  const a=animRef.current,msgs=msgsRef.current;
  const phase=a.phase,msg=msgs[a.i]||msgs[0];
  const target=byId[msg?.cat]||cats[3],trig=byId['trigger'];
  const nowT=performance.now(),elT=a.paused?a.pausedEl:nowT-a.start;
  const prog=Math.max(0,Math.min(1,elT/(D[phase]||1)));
  const brain={x:BX,y:BY};
  const incoming=phase==='incoming',analyzing=phase==='thinking';
  const routing=phase==='routing',delivered=phase==='delivered';
  const showDec=routing||delivered;

  /* category views */
  const catViews=cats.map(c=>{
    const isSrc=incoming&&c.id==='trigger';
    const isTgt=(routing||delivered)&&c.id===target?.id;
    const active=isSrc||isTgt,h=c.hue;
    return {...c,active,
      ns:{  /* nodeStyle */
        position:'absolute',left:c.x+'px',top:c.y+'px',
        transform:`translate(-50%,-50%) scale(${active?1.06:1})`,
        display:'flex',alignItems:'center',gap:'10px',
        padding:'10px 14px',borderRadius:'15px',whiteSpace:'nowrap',
        background:active?`linear-gradient(150deg,${col(h,.28)},rgba(20,11,26,.92))`:'rgba(19,11,25,.78)',
        border:`1px solid ${active?col(h,.9):'rgba(255,255,255,.1)'}`,
        boxShadow:active?`0 0 0 1px ${col(h,.4)},0 10px 34px ${col(h,.45)},0 0 46px ${col(h,.3)}`:'0 6px 20px rgba(0,0,0,.45)',
        backdropFilter:'blur(12px)',WebkitBackdropFilter:'blur(12px)',
        transition:'all .35s',zIndex:active?8:5,pointerEvents:'none',
      },
      ds:{width:'11px',height:'11px',borderRadius:'4px',flex:'0 0 auto',background:col(h),boxShadow:`0 0 12px ${col(h,.95)}`},
      cs:{  /* countStyle */
        marginInlineStart:'4px',fontSize:'12px',fontWeight:'800',
        color:active?'#fff':col(h,.95),
        background:active?col(h,.3):'rgba(255,255,255,.06)',
        border:`1px solid ${active?col(h,.7):'rgba(255,255,255,.08)'}`,
        padding:'2px 8px',borderRadius:'999px',
      },
    };
  });

  /* leaf views */
  const leafViews=[],leafLinks=[];
  cats.forEach(c=>c.leaves.forEach(lf=>{
    const isSrc=incoming&&c.id==='trigger'&&lf.idx===msg?.src;
    const isTgt=(routing||delivered)&&c.id===target?.id&&lf.idx===msg?.leaf;
    const active=isSrc||isTgt,h=lf.hue;
    leafLinks.push({conn:lf.conn,stroke:col(h,.18)});
    leafViews.push({name:lf.name,style:{
      position:'absolute',left:lf.x+'px',top:lf.y+'px',transform:'translate(-50%,-50%)',
      padding:'5px 11px',borderRadius:'999px',fontSize:'11.5px',fontWeight:active?'700':'500',whiteSpace:'nowrap',
      background:active?col(h,.2):'rgba(255,255,255,.04)',
      border:`1px solid ${active?col(h,.75):'rgba(255,255,255,.08)'}`,
      color:active?'#fff':'rgba(225,210,225,.55)',
      boxShadow:active?`0 0 18px ${col(h,.55)}`:'none',
      textShadow:active?`0 0 9px ${col(h,.8)}`:'none',
      transition:'all .3s',zIndex:active?7:4,pointerEvents:'none',
    }});
  }));

  /* SVG overlay */
  const gp=(d,h,key,w,op)=>[
    E('path',{key:key+'h',d,fill:'none',stroke:col(h,op*.5),strokeWidth:(w||3)+5,strokeLinecap:'round',filter:'url(#mg1)',opacity:op*.7}),
    E('path',{key:key+'c',d,fill:'none',stroke:'#fff',strokeWidth:1.6,strokeLinecap:'round',opacity:op*.9}),
    E('path',{key:key+'m',d,fill:'none',stroke:col(h),strokeWidth:w||3,strokeLinecap:'round',filter:'url(#mg1)',opacity:op}),
  ];
  const pt=(p,h,key)=>[
    E('circle',{key:key+'g',cx:p.x,cy:p.y,r:13,fill:col(h,.4),filter:'url(#mg1)'}),
    E('circle',{key:key+'o',cx:p.x,cy:p.y,r:7,fill:col(h,.9)}),
    E('circle',{key:key+'i',cx:p.x,cy:p.y,r:3.2,fill:'#fff'}),
  ];
  const ov=[];
  if(incoming&&trig){
    ov.push(...gp(trig.path,trig.hue,'inc',2.6,.85));
    ov.push(...pt(quad(brain,trig.cp,{x:trig.x,y:trig.y},1-prog),trig.hue,'incp'));
  }
  if(analyzing){
    const r=26+prog*64,op=Math.max(0,.5*(1-prog));
    ov.push(E('circle',{key:'th1',cx:BX,cy:BY,r,fill:'none',stroke:col(340,op),strokeWidth:2}));
    const p2=(prog+.5)%1,r2=26+p2*64,op2=Math.max(0,.4*(1-p2));
    ov.push(E('circle',{key:'th2',cx:BX,cy:BY,r:r2,fill:'none',stroke:col(330,op2),strokeWidth:2}));
  }
  if((routing||delivered)&&target){
    ov.push(...gp(target.path,target.hue,'rt',3,.95));
    const lf=target.leaves[msg?.leaf||0]||target.leaves[0];
    if(lf)ov.push(...gp(lf.conn,target.hue,'rtl',1.8,.85));
    if(routing)ov.push(...pt(quad(brain,target.cp,{x:target.x,y:target.y},prog),target.hue,'rtp'));
    if(delivered){
      const r=12+prog*70,op=Math.max(0,1-prog);
      ov.push(E('circle',{key:'dl',cx:target.x,cy:target.y,r,fill:'none',stroke:col(target.hue,op*.8),strokeWidth:2.4}));
    }
  }

  /* rail data */
  const current={
    channel:trig?.leaves[msg?.src||0]?.name||'ورودی',
    text:msg?.text||'',
    time:incoming?'در حال دریافت…':'هم‌اکنون',
  };
  const decision=showDec&&target&&msg?{
    catName:target.name,
    leaf:(target.leaves[msg.leaf||0]||target.leaves[0])?.name||'',
    reason:msg.reason,
    confPct:fa(Math.round(msg.conf*100))+'٪',confW:Math.round(msg.conf*100)+'%',
    chipBg:col(target.hue,.22),chipBorder:col(target.hue,.6),
    chipShadow:`0 0 16px ${col(target.hue,.4)}`,leafColor:col(target.hue,.95),
    barBg:`linear-gradient(90deg,${col(target.hue,.6)},${col(target.hue)})`,barGlow:col(target.hue,.7),
  }:null;
  const queue=msgs.length>1?[1,2].map(k=>{const j=(a.i+k)%msgs.length;return{text:msgs[j]?.text||'',idx:j};}):[];
  const recent=logRef.current.slice().reverse();
  const legend=cats.map(c=>({name:c.name,color:col(c.hue),glow:col(c.hue,.7)}));
  const statusText=incoming?'دریافت پیام…':analyzing?'در حال تحلیل…':routing?'ارجاع…':delivered?'✓ ارجاع شد':'آماده';
  const thinkGlow=analyzing?.95:routing?.6:delivered?.55:.32;
  const kpis=[{val:'۲٬۴۸۰',label:'پیام امروز'},{val:'٪۹۶',label:'ارجاع درست'},{val:'۰٫۸s',label:'میانگین تصمیم'}];

  /* ── JSX ── */
  return (
    <div dir="rtl" style={{
      position:'fixed',inset:0,zIndex:100,
      fontFamily:"'Vazirmatn',system-ui,sans-serif",
      background:'radial-gradient(1100px 720px at 60% 42%, #1a0a1e 0%, #0c0512 48%, #06030a 100%)',
      color:'#f6eef4',display:'flex',flexDirection:'column',overflow:'hidden',
    }}>
      <style>{`
        @keyframes brainPulse{0%,100%{filter:drop-shadow(0 0 18px rgba(255,40,160,.55)) drop-shadow(0 0 42px rgba(255,40,160,.35));transform:translate(-50%,-50%) scale(1);}50%{filter:drop-shadow(0 0 28px rgba(255,60,180,.85)) drop-shadow(0 0 70px rgba(255,40,160,.55));transform:translate(-50%,-50%) scale(1.025);}}
        @keyframes mmRing{0%{transform:scale(.55);opacity:.55;}70%{opacity:0;}100%{transform:scale(1.5);opacity:0;}}
        @keyframes mmDash{to{stroke-dashoffset:-26;}}
        @keyframes mmBlink{0%,100%{opacity:1;}50%{opacity:.25;}}
        @keyframes mmSpin{to{transform:rotate(360deg);}}
        .mm-scrl::-webkit-scrollbar{width:5px;}
        .mm-scrl::-webkit-scrollbar-thumb{background:rgba(255,80,170,.3);border-radius:9px;}
      `}</style>

      {/* dot grid */}
      <div style={{position:'absolute',inset:0,backgroundImage:'radial-gradient(rgba(255,255,255,.04) 1px,transparent 1px)',backgroundSize:'34px 34px',opacity:.5,pointerEvents:'none',maskImage:'radial-gradient(circle at 56% 46%,#000 30%,transparent 78%)',WebkitMaskImage:'radial-gradient(circle at 56% 46%,#000 30%,transparent 78%)'}}/>
      {/* center glow */}
      <div style={{position:'absolute',width:680,height:680,left:'54%',top:'46%',transform:'translate(-50%,-50%)',background:'radial-gradient(circle,rgba(255,42,154,.16) 0%,rgba(255,42,154,0) 62%)',pointerEvents:'none',filter:'blur(8px)'}}/>

      {/* ── HEADER ── */}
      <div style={{position:'relative',zIndex:20,display:'flex',alignItems:'center',justifyContent:'space-between',padding:'13px 24px 11px',flexShrink:0,borderBottom:'1px solid rgba(255,255,255,.06)'}}>
        <div style={{display:'flex',alignItems:'center',gap:12}}>
          {onClose&&<button onClick={onClose} style={{display:'flex',alignItems:'center',gap:5,padding:'6px 11px',borderRadius:9,background:'rgba(255,255,255,.06)',border:'1px solid rgba(255,255,255,.1)',color:'rgba(225,205,225,.7)',cursor:'pointer',fontSize:12,fontWeight:600,flexShrink:0}} title="بازگشت به ارکستریشن">
            <Icon name="arrow-right" size={14}/>
            <span>بازگشت</span>
          </button>}
          <img src="/assets/brain.png" alt="" style={{width:40,height:40,objectFit:'contain',filter:'drop-shadow(0 0 12px rgba(255,42,154,.7))'}} onError={e=>e.target.style.display='none'}/>
          <div style={{display:'flex',flexDirection:'column',gap:2}}>
            <div style={{display:'flex',alignItems:'center',gap:9}}>
              <span style={{fontSize:20,fontWeight:800}}>Orchestra</span>
              <span style={{display:'inline-flex',alignItems:'center',gap:5,fontSize:11,fontWeight:600,color:'oklch(0.8 0.16 150)',background:'oklch(0.7 0.16 150 / .12)',border:'1px solid oklch(0.7 0.16 150 / .3)',padding:'2px 8px',borderRadius:999}}>
                <span style={{width:6,height:6,borderRadius:'50%',background:'oklch(0.8 0.18 150)',boxShadow:'0 0 8px oklch(0.8 0.18 150)',animation:'mmBlink 2s infinite'}}/>آنلاین
              </span>
            </div>
            <span style={{fontSize:12,color:'rgba(225,205,225,.5)',fontWeight:500}}>مغز مرکزی هوشمند · موتور ارجاع پیام</span>
          </div>
        </div>
        <div style={{display:'flex',alignItems:'center',gap:9}}>
          {kpis.map((k,i)=>(
            <div key={i} style={{display:'flex',flexDirection:'column',gap:2,padding:'6px 13px',borderRadius:12,background:'rgba(255,255,255,.03)',border:'1px solid rgba(255,255,255,.07)',minWidth:88}}>
              <span style={{fontSize:17,fontWeight:700,color:'#fff'}}>{k.val}</span>
              <span style={{fontSize:10,color:'rgba(225,205,225,.5)',fontWeight:500}}>{k.label}</span>
            </div>
          ))}
          {onClose&&(
            <button onClick={onClose} style={{marginRight:4,padding:'8px 14px',borderRadius:12,border:'1px solid rgba(255,255,255,.12)',background:'rgba(255,255,255,.05)',color:'rgba(225,205,225,.7)',fontFamily:'inherit',fontSize:12,fontWeight:600,cursor:'pointer'}}>
              ✕ بستن
            </button>
          )}
        </div>
      </div>

      {/* ── BODY ── */}
      <div style={{position:'relative',zIndex:10,flex:'1 1 auto',display:'flex',alignItems:'stretch',minHeight:0}}>

        {/* ── RAIL ── */}
        <aside style={{flex:'0 0 282px',display:'flex',flexDirection:'column',gap:11,minHeight:0,padding:'14px 18px',borderLeft:'1px solid rgba(255,255,255,.05)'}}>
          <div style={{display:'flex',alignItems:'center',justifyContent:'space-between'}}>
            <span style={{fontSize:13.5,fontWeight:700}}>جریان پیام‌ها</span>
            <span style={{display:'inline-flex',alignItems:'center',gap:5,fontSize:11,color:'rgba(225,205,225,.45)'}}>
              <span style={{width:5,height:5,borderRadius:'50%',background:'#4ade80',boxShadow:'0 0 6px #4ade80'}}/>زنده
            </span>
          </div>

          {/* current message card */}
          <div style={{borderRadius:18,padding:'13px 14px',background:'linear-gradient(160deg,rgba(40,16,44,.9),rgba(18,9,24,.86))',border:'1px solid rgba(255,255,255,.09)',backdropFilter:'blur(14px)',WebkitBackdropFilter:'blur(14px)',flexShrink:0}}>
            {idle||!msgs.length?(
              <div style={{display:'flex',flexDirection:'column',alignItems:'center',justifyContent:'center',gap:10,padding:'18px 0',color:'rgba(225,205,225,.35)',fontSize:12,textAlign:'center'}}>
                <span style={{fontSize:22,opacity:.5,animation:'mmBlink 2.5s ease-in-out infinite'}}>📭</span>
                <span>هنوز پیامی دریافت نشده</span>
                <span style={{fontSize:10,opacity:.6}}>وقتی لید پیام بفرسته اینجا نشون داده می‌شه</span>
              </div>
            ):(
              <>
            <div style={{display:'flex',alignItems:'center',justifyContent:'space-between',marginBottom:10}}>
              <span style={{display:'inline-flex',alignItems:'center',gap:5,fontSize:11,fontWeight:600,color:'oklch(0.78 0.18 350)',background:'oklch(0.72 0.19 350 / .12)',border:'1px solid oklch(0.72 0.19 350 / .28)',padding:'2px 8px',borderRadius:999}}>
                <span style={{width:4,height:4,borderRadius:'50%',background:'oklch(0.78 0.18 350)'}}/>{current.channel}
              </span>
              <span style={{fontSize:10.5,color:'rgba(225,205,225,.4)'}}>{current.time}</span>
            </div>
            <p style={{margin:0,fontSize:13.5,lineHeight:1.8,fontWeight:500,color:'#f4ecf2'}}>«{current.text}»</p>
            <div style={{height:1,background:'linear-gradient(90deg,transparent,rgba(255,255,255,.1),transparent)',margin:'12px 0'}}/>
            {analyzing?(
              <div style={{display:'flex',alignItems:'center',gap:10}}>
                <span style={{width:15,height:15,borderRadius:'50%',border:'2px solid rgba(255,42,154,.25)',borderTopColor:'oklch(0.78 0.18 340)',animation:'mmSpin .8s linear infinite',flex:'0 0 auto',display:'inline-block'}}/>
                <span style={{fontSize:12.5,fontWeight:600,color:'oklch(0.85 0.12 340)'}}>مغز در حال تحلیل پیام…</span>
              </div>
            ):decision?(
              <div>
                <div style={{display:'flex',alignItems:'center',gap:7,marginBottom:10}}>
                  <span style={{fontSize:11,color:'rgba(225,205,225,.5)',fontWeight:600}}>ارجاع به</span>
                  <span style={{fontSize:14,color:'rgba(225,205,225,.4)'}}>←</span>
                  <span style={{fontSize:12.5,fontWeight:700,color:'#fff',padding:'3px 10px',borderRadius:8,background:decision.chipBg,border:`1px solid ${decision.chipBorder}`,boxShadow:decision.chipShadow}}>{decision.catName}</span>
                  <span style={{fontSize:12,fontWeight:600,color:decision.leafColor}}>{decision.leaf}</span>
                </div>
                <div style={{display:'flex',alignItems:'center',gap:9,marginBottom:9}}>
                  <div style={{flex:1,height:6,borderRadius:99,background:'rgba(255,255,255,.07)',overflow:'hidden'}}>
                    <div style={{height:'100%',borderRadius:99,width:decision.confW,background:decision.barBg,boxShadow:`0 0 10px ${decision.barGlow}`,transition:'width .5s ease'}}/>
                  </div>
                  <span style={{fontSize:12.5,fontWeight:800,color:'#fff',minWidth:36}}>{decision.confPct}</span>
                </div>
                <p style={{margin:0,fontSize:11.5,lineHeight:1.65,color:'rgba(225,205,225,.6)'}}>{decision.reason}</p>
              </div>
            ):(
              <span style={{fontSize:12,color:'rgba(225,205,225,.35)'}}>در انتظار پیام…</span>
            )}
              </>
            )}
          </div>

          {/* queue */}
          {queue.length>0&&(
            <>
            <div style={{fontSize:11.5,fontWeight:700,color:'rgba(225,205,225,.5)'}}>در صف</div>
            <div style={{display:'flex',flexDirection:'column',gap:6}}>
              {queue.map((q,i)=>(
                <div key={i} onClick={()=>select(q.idx)} style={{display:'flex',alignItems:'center',gap:9,padding:'9px 11px',borderRadius:12,background:'rgba(255,255,255,.025)',border:'1px solid rgba(255,255,255,.06)',cursor:'pointer',transition:'background .2s'}}>
                  <span style={{width:6,height:6,borderRadius:'50%',background:'rgba(225,205,225,.3)',flex:'0 0 auto'}}/>
                  <span style={{fontSize:12,color:'rgba(235,220,235,.75)',overflow:'hidden',textOverflow:'ellipsis',whiteSpace:'nowrap',flex:1}}>{q.text}</span>
                </div>
              ))}
            </div>
            </>
          )}

          {/* recent */}
          <div style={{fontSize:11.5,fontWeight:700,color:'rgba(225,205,225,.5)',paddingTop:4}}>ارجاع‌های اخیر</div>
          <div className="mm-scrl" style={{display:'flex',flexDirection:'column',gap:6,overflowY:'auto',flex:1,minHeight:0}}>
            {recent.length===0?(
              <span style={{fontSize:11,color:'rgba(225,205,225,.28)'}}>هنوز ارجاعی ثبت نشده…</span>
            ):recent.map((r,i)=>(
              <div key={i} style={{display:'flex',alignItems:'center',gap:9,padding:'8px 11px',borderRadius:11,background:'rgba(255,255,255,.02)',border:'1px solid rgba(255,255,255,.05)'}}>
                <span style={{width:7,height:7,borderRadius:2,background:r.color,boxShadow:`0 0 8px ${r.glow}`,flex:'0 0 auto'}}/>
                <div style={{display:'flex',flexDirection:'column',gap:1,flex:1,minWidth:0}}>
                  <span style={{fontSize:11.5,fontWeight:600,color:'#ece0ec',overflow:'hidden',textOverflow:'ellipsis',whiteSpace:'nowrap'}}>{r.intent}</span>
                  <span style={{fontSize:10,color:'rgba(225,205,225,.4)',overflow:'hidden',textOverflow:'ellipsis',whiteSpace:'nowrap'}}>{r.dest}</span>
                </div>
                <span style={{fontSize:11,fontWeight:700,color:'rgba(235,220,235,.65)'}}>{r.confPct}</span>
              </div>
            ))}
          </div>
        </aside>

        {/* ── STAGE ── */}
        <div ref={stageRef} style={{flex:'1 1 auto',display:'flex',flexDirection:'column',alignItems:'center',justifyContent:'center',minWidth:0,gap:10,padding:'10px 14px 18px',overflowY:'auto',overflowX:'hidden'}}>

          {/* scaled mindmap canvas */}
          <div style={{transform:`scale(${stageScale})`,transformOrigin:'center center',flexShrink:0}}>
            <div style={{position:'relative',width:1000,height:704}}>
              <svg viewBox="0 0 1000 704" style={{position:'absolute',inset:0,width:'100%',height:'100%',overflow:'visible'}}>
                <defs>
                  <filter id="mg1" x="-60%" y="-60%" width="220%" height="220%">
                    <feGaussianBlur stdDeviation="3.4" result="b"/>
                    <feMerge><feMergeNode in="b"/><feMergeNode in="SourceGraphic"/></feMerge>
                  </filter>
                </defs>
                {/* ambient rings */}
                <circle cx={BX} cy={BY} r={150} fill="none" stroke="rgba(255,42,154,.12)" strokeWidth={1}/>
                <circle cx={BX} cy={BY} r={240} fill="none" stroke="rgba(255,42,154,.07)" strokeWidth={1}/>
                <circle cx={BX} cy={BY} r={330} fill="none" stroke="rgba(255,42,154,.04)" strokeWidth={1}/>
                {/* dashed bezier lines */}
                {cats.map((c,i)=>(
                  <path key={i} d={c.path} fill="none" stroke={col(c.hue,.32)} strokeWidth={1.6} strokeDasharray="2 7" strokeLinecap="round" style={{animation:'mmDash 1.6s linear infinite'}}/>
                ))}
                {/* leaf connectors */}
                {leafLinks.map((l,i)=>(
                  <path key={i} d={l.conn} fill="none" stroke={l.stroke} strokeWidth={1.1}/>
                ))}
                {/* animated overlay */}
                {E('g',{key:'ov'},ov)}
              </svg>

              {/* brain glow + expand ring */}
              <div style={{position:'absolute',left:BX,top:BY,width:300,height:300,transform:'translate(-50%,-50%)',pointerEvents:'none'}}>
                <div style={{position:'absolute',left:'50%',top:'50%',width:240,height:240,transform:'translate(-50%,-50%)',borderRadius:'50%',background:'radial-gradient(circle,rgba(255,42,154,.42) 0%,rgba(255,42,154,0) 66%)',opacity:thinkGlow,transition:'opacity .4s'}}/>
                <div style={{position:'absolute',left:'50%',top:'50%',width:178,height:178,transform:'translate(-50%,-50%)',borderRadius:'50%',border:'1px solid rgba(255,80,180,.18)',animation:'mmRing 3.4s ease-out infinite'}}/>
              </div>
              <img src="/assets/brain.png" alt="🧠" style={{position:'absolute',left:BX,top:BY,width:182,transform:'translate(-50%,-50%)',animation:'brainPulse 3.4s ease-in-out infinite',zIndex:6}} onError={e=>e.target.style.display='none'} />

              {/* brain label */}
              <div style={{position:'absolute',left:BX,top:BY+96,transform:'translate(-50%,0)',zIndex:7,display:'flex',flexDirection:'column',alignItems:'center',gap:3,textAlign:'center',pointerEvents:'none'}}>
                <span style={{fontSize:13.5,fontWeight:800,color:'#fff',textShadow:'0 0 14px rgba(255,42,154,.8)'}}>مغز اصلی</span>
                <span style={{fontSize:11,fontWeight:600,color:analyzing?'oklch(0.85 0.12 340)':delivered&&target?col(target.hue,.95):'rgba(235,220,235,.6)',transition:'color .3s'}}>{statusText}</span>
              </div>

              {/* category nodes */}
              {catViews.map(c=>(
                <div key={c.id} style={c.ns}>
                  <span style={c.ds}/>
                  <div style={{display:'flex',flexDirection:'column',gap:1}}>
                    <span style={{fontSize:13.5,fontWeight:700,color:'#fff',lineHeight:1.2}}>{c.name}</span>
                    <span style={{fontSize:10.5,fontWeight:500,color:'rgba(225,205,225,.5)',lineHeight:1.2}}>{c.desc}</span>
                  </div>
                  <span style={c.cs}>{c.count}</span>
                </div>
              ))}

              {/* leaves */}
              {leafViews.map((l,i)=>(
                <div key={i} style={l.style}>{l.name}</div>
              ))}
            </div>
          </div>

          {/* legend + controls */}
          <div style={{display:'flex',alignItems:'center',gap:12,flexWrap:'wrap',justifyContent:'center',flexShrink:0}}>
            <div style={{display:'flex',alignItems:'center',gap:12,padding:'8px 14px',borderRadius:13,background:'rgba(255,255,255,.03)',border:'1px solid rgba(255,255,255,.06)'}}>
              {legend.map((g,i)=>(
                <span key={i} style={{display:'inline-flex',alignItems:'center',gap:5,fontSize:11,fontWeight:600,color:'rgba(235,220,235,.7)'}}>
                  <span style={{width:8,height:8,borderRadius:3,background:g.color,boxShadow:`0 0 7px ${g.glow}`}}/>{g.name}
                </span>
              ))}
            </div>
            <button onClick={toggle} style={{display:'inline-flex',alignItems:'center',gap:7,padding:'9px 16px',borderRadius:13,background:'linear-gradient(135deg,oklch(0.66 0.22 350),oklch(0.6 0.2 320))',border:'none',color:'#fff',fontFamily:'inherit',fontSize:13,fontWeight:700,cursor:'pointer',boxShadow:'0 5px 20px oklch(0.6 0.22 340 / .5)'}}>
              {a.paused?'▶ پخش':'❚❚ مکث'}
            </button>
            <button onClick={onRefresh} style={{padding:'9px 13px',borderRadius:13,border:'1px solid rgba(255,255,255,.1)',background:'rgba(255,255,255,.04)',color:'rgba(225,205,225,.6)',fontFamily:'inherit',fontSize:12,cursor:'pointer'}}>↺ بازسازی</button>
          </div>

          {/* chat input */}
          <div style={{display:'flex',gap:8,maxWidth:580,width:'100%',flexShrink:0}}>
            <input
              value={chatInput}
              onChange={e=>setChatInput(e.target.value)}
              onKeyDown={e=>e.key==='Enter'&&sendChat()}
              placeholder="پیام بفرست — مسیر روی نقشه انیمیت می‌شه"
              style={{flex:1,padding:'10px 14px',borderRadius:12,fontSize:13,fontFamily:'inherit',background:'rgba(255,255,255,.06)',border:'1px solid rgba(255,255,255,.13)',color:'#f4ecf2',outline:'none'}}
            />
            <button onClick={sendChat} style={{padding:'10px 20px',borderRadius:12,border:'none',background:'linear-gradient(135deg,oklch(0.66 0.22 350),oklch(0.6 0.2 320))',color:'#fff',fontFamily:'inherit',fontSize:13,fontWeight:700,cursor:'pointer',flexShrink:0}}>
              ارسال
            </button>
          </div>
        </div>

      </div>
    </div>
  );
};

// ─── Orchestra Board ──────────────────────────────────────
const OrchestraBoard = () => {
  const { Icon, useToast } = window.SB_UI;
  const toast = useToast();

  const DEFAULTS = [
    { id: 'trigger',  label: 'تریگر',    icon: 'zap',       color: '#F87171', desc: 'رویداد فوری — بلافاصله قطع می‌کنه' },
    { id: 'followup', label: 'فالوآپ',   icon: 'clock',     color: '#FB923C', desc: 'قرار تماس از قبل تنظیم شده' },
    { id: 'campaign', label: 'کمپین',    icon: 'megaphone', color: '#60A5FA', desc: 'برنامه بازاریابی در حال اجرا' },
    { id: 'script',   label: 'اسکریپت', icon: 'file-text', color: '#A78BFA', desc: 'رفتار پیشفرض لید گیری' },
    { id: 'bot',      label: 'بات',      icon: 'cpu',       color: '#34D399', desc: 'اگه هیچ handler دیگه‌ای نبود' },
  ];

  const [items, setItems]             = useState(DEFAULTS);
  const [entities, setEntities]       = useState({ campaign: [], script: [], followup: [], trigger: [], bot: [] });
  const [saving, setSaving]           = useState(false);
  const [dirty, setDirty]             = useState(false);
  const [dragging, setDragging]       = useState(null);
  const [innerDirty, setInnerDirty]   = useState(false);
  const [innerSaving, setInnerSaving] = useState(false);
  const [tab, setTab]                 = useState('priority'); // priority | scenarios | chat | alerts
  const [alerts, setAlerts]           = useState([]);
  const [alertsLoading, setAlertsLoading] = useState(false);
  const [brainScript, setBrainScript] = useState(null);
  const [showBrain, setShowBrain]     = useState(false);
  const [brainEdit, setBrainEdit]           = useState('');
  const [brainFallback, setBrainFallback]   = useState('');
  const [brainSaving, setBrainSaving]       = useState(false);
  const [distPrompt, setDistPrompt]         = useState('');     // متن هاردکد توزیع
  const [distUnlocked, setDistUnlocked]     = useState(false);  // بعد از وارد کردن رمز درست
  const [distPassword, setDistPassword]     = useState('');
  const [distSaving, setDistSaving]         = useState(false);
  const dragIdx      = useRef(null);
  const innerDragIdx = useRef(null);

  const colors = Object.fromEntries(DEFAULTS.map(d => [d.id, d.color]));
  const priorityOrder = items.map(i => i.id);

  const loadData = () => {
    window.api('/orchestrator/order').then(r => {
      if (r.success && r.data?.length === 5) {
        const ordered = r.data.map(id => DEFAULTS.find(d => d.id === id)).filter(Boolean);
        if (ordered.length === 5) setItems(ordered);
      }
    }).catch(() => {});

    Promise.all([
      window.api('/campaigns/campaigns').catch(() => []),
      window.api('/scripts').catch(() => ({})),
      window.api('/followup/templates').catch(() => ({ success: false })),
      window.api('/orchestrator/rules').catch(() => ({ success: false })),
    ]).then(([camps, scripts, followups, rules]) => {
      const ruleMap = {};
      if (rules.success) rules.data.forEach(r => { if (r.ref_id) ruleMap[r.ref_id] = r.priority; });
      const campList = Array.isArray(camps)
        ? camps.filter(c => c.is_active).map(c => ({ id: c.id, name: c.name, priority: ruleMap[c.id] ?? null, is_active: c.is_active }))
            .sort((a, b) => a.priority === null ? 1 : b.priority === null ? -1 : a.priority - b.priority)
        : [];
      const rawScripts = scripts?.data?.scripts || scripts?.scripts || scripts?.data || [];
      const scriptList = Array.isArray(rawScripts)
        ? rawScripts.filter(s => s.is_active).map(s => ({ id: s.id, name: s.name, badge: s.is_default ? 'پیشفرض' : null, is_active: s.is_active }))
        : [];
      const followupList = followups.success && Array.isArray(followups.data)
        ? [...new Map(followups.data.map(f => {
            const camp = f.name?.match(/^\[(.*?)\]/)?.[1] || '';
            return [camp, { id: camp, name: camp }];
          })).values()].filter(f => f.name)
        : [];
      window.api('/orchestrator/brain-script').then(r => {
        if (r.success && r.data) {
          setBrainScript(r.data);
          setBrainEdit(r.data.system_prompt || '');
          setBrainFallback(r.data.fallback_message || '');
          setDistPrompt(r.data.distribution_prompt || '');
        }
      }).catch(() => {});
      const brain = Array.isArray(rawScripts) ? rawScripts.find(s => s.is_default) : null;
      if (!brain) setBrainScript(null);
      setEntities({
        campaign: campList, script: scriptList.filter(s => !s.badge), followup: followupList,
        trigger: [{ id: 't1', name: 'رویدادهای سیستمی (خودکار)' }],
        bot:     [{ id: 'b1', name: 'بات پاسخ‌دهنده عمومی' }],
      });
    });

    window.api('/orchestrator/brain-alerts').then(r => {
      if (r.success) setAlerts(r.data || []);
    }).catch(() => {});
  };

  useEffect(() => { loadData(); }, []);

  // drag داخلی کمپین
  const onInnerDragStart = (e, i) => { e.stopPropagation(); innerDragIdx.current = i; };
  const onInnerDragEnter = (e, i) => {
    e.preventDefault(); e.stopPropagation();
    if (innerDragIdx.current === null || innerDragIdx.current === i) return;
    setEntities(prev => {
      const camps = [...prev.campaign];
      const [moved] = camps.splice(innerDragIdx.current, 1);
      camps.splice(i, 0, moved);
      innerDragIdx.current = i;
      return { ...prev, campaign: camps };
    });
    setInnerDirty(true);
  };
  const onInnerDragEnd = (e) => { e.stopPropagation(); innerDragIdx.current = null; };

  const saveInnerOrder = async () => {
    setInnerSaving(true);
    const r = await window.api('/orchestrator/rules');
    if (r.success) {
      const registered = entities.campaign.filter(c => c.priority !== null);
      await Promise.all(registered.map((c, i) => {
        const rule = r.data.find(x => x.ref_id === c.id);
        if (!rule) return;
        return window.api(`/orchestrator/rules/${rule.id}`, { method: 'PUT', body: { priority: (i + 1) * 2 } });
      }));
    }
    setInnerSaving(false); setInnerDirty(false);
    toast('ترتیب کمپین‌ها ذخیره شد', 'success');
  };

  // drag خارجی بلوک‌ها
  const onDragStart = (e, i) => { dragIdx.current = i; setDragging(i); e.dataTransfer.effectAllowed = 'move'; };
  const onDragEnter = (e, i) => {
    e.preventDefault();
    if (dragIdx.current === null || dragIdx.current === i) return;
    setItems(prev => {
      const next = [...prev];
      const [moved] = next.splice(dragIdx.current, 1);
      next.splice(i, 0, moved);
      dragIdx.current = i;
      return next;
    });
  };
  const onDragEnd = () => { setDragging(null); dragIdx.current = null; setDirty(true); };

  const save = async () => {
    setSaving(true);
    const r = await window.api('/orchestrator/order', { method: 'POST', body: { order: items.map(i => i.id) } });
    setSaving(false);
    if (r.success) { setDirty(false); toast('ترتیب ذخیره شد', 'success'); }
    else toast(r.error || 'خطا', 'error');
  };

  return (
    <div style={{ maxWidth: 640, margin: '40px auto', padding: '0 16px' }}>

      {/* تب‌ها */}
      <div style={{ display: 'flex', gap: 4, marginBottom: 24, background: 'rgba(255,255,255,0.03)', borderRadius: 10, padding: 4 }}>
        {[['priority','ترتیب اولویت'],['mindmap','نقشه سیستم'],['scenarios','سناریوها'],['chat','تست چت'],['alerts','هشدارها']].map(([id, label]) => (
          <button key={id} onClick={() => setTab(id)} style={{
            flex: 1, padding: '7px 0', borderRadius: 7, border: 'none', cursor: 'pointer',
            background: tab === id ? 'rgba(255,255,255,0.08)' : 'transparent',
            color: id === 'alerts' && alerts.filter(a=>!a.resolved).length > 0
              ? tab === id ? '#FCD34D' : '#F59E0B'
              : tab === id ? '#e2e8f0' : '#475569',
            fontSize: 13, fontWeight: tab === id ? 600 : 400, transition: 'all 0.15s',
            position: 'relative',
          }}>
            {label}
            {id === 'alerts' && alerts.filter(a=>!a.resolved).length > 0 && (
              <span style={{ marginRight: 4, background: '#EF4444', color: '#fff', borderRadius: 10, fontSize: 9, padding: '1px 5px', fontWeight: 700 }}>
                {alerts.filter(a=>!a.resolved).length}
              </span>
            )}
          </button>
        ))}
      </div>

      {/* ─── تب اولویت ─── */}
      {tab === 'priority' && (<>
        <div style={{ marginBottom: 20 }}>
          <div style={{ fontSize: 14, color: '#64748b' }}>
            وقتی دو handler همزمان می‌خوان یه لید رو بگیرن، بالاترین در لیست برنده می‌شه.
            <span style={{ color: '#3B82F6', marginRight: 6 }}>بکش و بچین.</span>
          </div>
        </div>

        {/* ─── بلوک مغز اصلی ─── */}
        <div onClick={() => brainScript && setShowBrain(true)} style={{
          display: 'flex', alignItems: 'center', gap: 12,
          padding: '12px 16px', borderRadius: 12, marginBottom: 4,
          background: 'linear-gradient(135deg, rgba(251,191,36,0.08), rgba(245,158,11,0.04))',
          border: '1px solid rgba(251,191,36,0.25)',
          cursor: brainScript ? 'pointer' : 'default',
          transition: 'background 0.15s',
        }}>
          <div style={{ fontSize: 20 }}>🧠</div>
          <div style={{ flex: 1 }}>
            <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
              <span style={{ color: '#FCD34D', fontWeight: 700, fontSize: 13 }}>مغز اصلی</span>
              <span style={{ fontSize: 9, padding: '2px 6px', borderRadius: 8, background: 'rgba(251,191,36,0.1)', color: '#F59E0B', border: '1px solid rgba(251,191,36,0.2)' }}>🔒 قفل</span>
              {!brainScript && (
                <span style={{ fontSize: 9, padding: '2px 6px', borderRadius: 8, background: 'rgba(239,68,68,0.1)', color: '#EF4444', border: '1px solid rgba(239,68,68,0.2)' }}>⚠ در حال بارگذاری...</span>
              )}
            </div>
            <div style={{ fontSize: 11, color: '#64748b', marginTop: 2 }}>
              {brainScript ? brainScript.name : 'همیشه اول — توزیع‌کننده و fallback'}
            </div>
          </div>
          <div style={{ fontSize: 10, color: '#F59E0B' }}>مشاهده اسکریپت ←</div>
        </div>

        {/* ─── Modal اسکریپت مغز ─── */}
        {showBrain && brainScript && (
          <div style={{
            position: 'fixed', inset: 0, zIndex: 1000,
            background: 'rgba(0,0,0,0.7)', display: 'flex', alignItems: 'center', justifyContent: 'center',
          }} onClick={() => { setShowBrain(false); setDistUnlocked(false); setDistPassword(''); }}>
            <div onClick={e => e.stopPropagation()} style={{
              width: 620, maxHeight: '80vh', borderRadius: 16, overflow: 'hidden',
              background: '#0f172a', border: '1px solid rgba(251,191,36,0.2)',
              display: 'flex', flexDirection: 'column',
            }}>
              {/* هدر */}
              <div style={{ padding: '16px 20px', borderBottom: '1px solid rgba(255,255,255,0.06)', display: 'flex', alignItems: 'center', gap: 10 }}>
                <span style={{ fontSize: 18 }}>🧠</span>
                <div style={{ flex: 1 }}>
                  <div style={{ color: '#FCD34D', fontWeight: 700, fontSize: 14 }}>{brainScript.name}</div>
                  <div style={{ color: '#475569', fontSize: 10, marginTop: 2 }}>این اسکریپت قابل ویرایش است — تغییرات بلافاصله اعمال می‌شه</div>
                </div>
                <button onClick={() => { setShowBrain(false); setDistUnlocked(false); setDistPassword(''); }} style={{ background: 'none', border: 'none', color: '#475569', fontSize: 18, cursor: 'pointer' }}>✕</button>
              </div>
              {/* متن اسکریپت */}
              <div style={{ flex: 1, overflowY: 'auto', padding: '16px 20px' }}>

                {/* ─── بخش هاردکد منطق توزیع — بالای متن ادمین، قفل با رمز ─── */}
                <div style={{ marginBottom: 16, border: '1px solid rgba(251,191,36,0.25)', borderRadius: 10, overflow: 'hidden' }}>
                  <div style={{ padding: '8px 12px', background: 'rgba(251,191,36,0.06)', display: 'flex', alignItems: 'center', gap: 6 }}>
                    <span style={{ fontSize: 12 }}>{distUnlocked ? '🔓' : '🔒'}</span>
                    <span style={{ color: '#FCD34D', fontSize: 11, fontWeight: 700, flex: 1 }}>منطق اصلی توزیع (همیشه بالای متن ادمین قرار می‌گیرد)</span>
                    {!distUnlocked && (
                      <span style={{ color: '#64748b', fontSize: 10 }}>برای ویرایش رمز عبور لازم است</span>
                    )}
                  </div>
                  <textarea
                    value={distPrompt}
                    onChange={e => setDistPrompt(e.target.value)}
                    readOnly={!distUnlocked}
                    style={{
                      width: '100%', minHeight: 180, background: distUnlocked ? 'rgba(251,191,36,0.04)' : 'rgba(255,255,255,0.02)',
                      border: 'none', borderTop: '1px solid rgba(251,191,36,0.15)',
                      color: distUnlocked ? '#cbd5e1' : '#64748b', fontSize: 12, lineHeight: 1.8, padding: '12px',
                      fontFamily: 'inherit', resize: 'vertical', outline: 'none', boxSizing: 'border-box',
                      cursor: distUnlocked ? 'text' : 'default',
                    }}
                  />
                  <div style={{ padding: '8px 12px', background: 'rgba(251,191,36,0.06)', display: 'flex', alignItems: 'center', gap: 8 }}>
                    {!distUnlocked ? (
                      <>
                        <input
                          type="password"
                          value={distPassword}
                          onChange={e => setDistPassword(e.target.value)}
                          placeholder="رمز عبور ادمین"
                          style={{
                            flex: 1, background: 'rgba(255,255,255,0.04)', border: '1px solid rgba(255,255,255,0.08)',
                            borderRadius: 6, color: '#cbd5e1', fontSize: 12, padding: '6px 10px', fontFamily: 'inherit', outline: 'none',
                          }}
                        />
                        <button onClick={async () => {
                          const r = await window.api('/auth/verify-password', { method: 'POST', body: { password: distPassword } });
                          if (r.success) { setDistUnlocked(true); toast('باز شد — حالا می‌تونی ویرایش کنی', 'success'); }
                          else toast(r.error || 'رمز اشتباه است', 'error');
                        }} style={{ padding: '6px 14px', borderRadius: 6, border: 'none', background: 'rgba(251,191,36,0.15)', color: '#FCD34D', fontSize: 11, fontWeight: 700, cursor: 'pointer' }}>
                          باز کردن قفل
                        </button>
                      </>
                    ) : (
                      <button disabled={distSaving} onClick={async () => {
                        setDistSaving(true);
                        const r = await window.api('/orchestrator/brain-script/distribution', { method: 'PUT', body: { distribution_prompt: distPrompt, password: distPassword } });
                        setDistSaving(false);
                        if (r.success) { toast('منطق توزیع ذخیره شد', 'success'); setDistUnlocked(false); setDistPassword(''); }
                        else toast(r.error || 'خطا', 'error');
                      }} style={{ padding: '6px 14px', borderRadius: 6, border: 'none', background: '#F59E0B', color: '#000', fontSize: 11, fontWeight: 700, cursor: 'pointer', marginRight: 'auto' }}>
                        {distSaving ? 'در حال ذخیره...' : 'ذخیره منطق توزیع'}
                      </button>
                    )}
                  </div>
                </div>

                <div style={{ color: '#64748b', fontSize: 11, marginBottom: 6 }}>متن آزاد ادمین — زیر بخش بالا اضافه می‌شه:</div>
                <textarea
                  value={brainEdit}
                  onChange={e => setBrainEdit(e.target.value)}
                  style={{
                    width: '100%', minHeight: 220, background: 'rgba(255,255,255,0.03)',
                    border: '1px solid rgba(255,255,255,0.08)', borderRadius: 10,
                    color: '#cbd5e1', fontSize: 12, lineHeight: 1.8, padding: '12px',
                    fontFamily: 'inherit', resize: 'vertical', outline: 'none', boxSizing: 'border-box',
                  }}
                />
                <div style={{ marginTop: 14 }}>
                  <div style={{ color: '#94a3b8', fontSize: 11, marginBottom: 6, display: 'flex', alignItems: 'center', gap: 6 }}>
                    <span>⚠️</span>
                    <span>پیام هنگام قطعی سرویس هوش مصنوعی</span>
                    <span style={{ color: '#475569', fontSize: 10 }}>(اگه خالی بمونه پیام پیش‌فرض فرستاده می‌شه)</span>
                  </div>
                  <input
                    value={brainFallback}
                    onChange={e => setBrainFallback(e.target.value)}
                    placeholder="متأسفم، الان یه مشکل فنی موقت داریم. لطفاً چند دقیقه دیگه دوباره پیام بده 🙏"
                    style={{
                      width: '100%', background: 'rgba(255,255,255,0.03)',
                      border: '1px solid rgba(251,191,36,0.2)', borderRadius: 8,
                      color: '#cbd5e1', fontSize: 12, padding: '9px 12px',
                      fontFamily: 'inherit', outline: 'none', boxSizing: 'border-box',
                    }}
                  />
                </div>
              </div>
              {/* فوتر */}
              <div style={{ padding: '12px 20px', borderTop: '1px solid rgba(255,255,255,0.06)', display: 'flex', justifyContent: 'flex-end', gap: 8 }}>
                <button onClick={() => { setShowBrain(false); setDistUnlocked(false); setDistPassword(''); }} style={{ padding: '7px 16px', borderRadius: 8, border: '1px solid rgba(255,255,255,0.08)', background: 'none', color: '#475569', fontSize: 12, cursor: 'pointer' }}>
                  بستن
                </button>
                <button disabled={brainSaving} onClick={async () => {
                  setBrainSaving(true);
                  const r = await window.api('/orchestrator/brain-script', { method: 'PUT', body: { system_prompt: brainEdit, fallback_message: brainFallback } });
                  setBrainSaving(false);
                  if (r.success) { setBrainScript(prev => ({...prev, system_prompt: brainEdit, fallback_message: brainFallback})); toast('اسکریپت ذخیره شد', 'success'); setShowBrain(false); }
                  else toast(r.error || 'خطا', 'error');
                }} style={{ padding: '7px 16px', borderRadius: 8, border: 'none', background: '#F59E0B', color: '#000', fontSize: 12, fontWeight: 700, cursor: 'pointer' }}>
                  {brainSaving ? 'در حال ذخیره...' : 'ذخیره'}
                </button>
              </div>
            </div>
          </div>
        )}

        <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
          {items.map((item, i) => {
            const ents = entities[item.id] || [];
            return (
              <div key={item.id} draggable
                onDragStart={e => onDragStart(e, i)} onDragEnter={e => onDragEnter(e, i)}
                onDragEnd={onDragEnd} onDragOver={e => e.preventDefault()}
                style={{
                  background: 'rgba(255,255,255,0.03)',
                  border: `1px solid ${i === 0 ? item.color + '40' : 'rgba(255,255,255,0.07)'}`,
                  borderRadius: 12, cursor: dragging === i ? 'grabbing' : 'grab',
                  overflow: 'hidden', opacity: dragging === i ? 0.4 : 1, transition: 'opacity 0.15s',
                }}
                onMouseEnter={e => { if (dragging === null) e.currentTarget.style.background = 'rgba(255,255,255,0.05)'; }}
                onMouseLeave={e => e.currentTarget.style.background = 'rgba(255,255,255,0.03)'}
              >
                <div style={{ display: 'flex', alignItems: 'center', gap: 12, padding: '13px 16px' }}>
                  <div style={{
                    width: 24, height: 24, borderRadius: 7, flexShrink: 0,
                    background: i === 0 ? item.color + '20' : 'rgba(255,255,255,0.04)',
                    border: `1px solid ${i === 0 ? item.color + '50' : 'rgba(255,255,255,0.08)'}`,
                    display: 'flex', alignItems: 'center', justifyContent: 'center',
                    fontSize: 10, fontWeight: 700, fontFamily: 'JetBrains Mono',
                    color: i === 0 ? item.color : '#475569',
                  }}>{i + 1}</div>
                  <div style={{ width: 34, height: 34, borderRadius: 9, flexShrink: 0, background: item.color + '12', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
                    <Icon name={item.icon} size={15} color={item.color} />
                  </div>
                  <div style={{ flex: 1 }}>
                    <div style={{ fontSize: 14, fontWeight: 600, color: '#e2e8f0' }}>{item.label}</div>
                    <div style={{ fontSize: 11, color: '#475569', marginTop: 1 }}>{item.desc}</div>
                  </div>
                  {ents.length > 0 && (
                    <div style={{ fontSize: 11, padding: '2px 8px', borderRadius: 20, background: item.color + '15', color: item.color, fontFamily: 'JetBrains Mono', fontWeight: 600, flexShrink: 0 }}>
                      {ents.length}
                    </div>
                  )}
                  <div style={{ color: '#2d3748', flexShrink: 0 }}><Icon name="grip-vertical" size={15} /></div>
                </div>

                {ents.length > 0 && (
                  <div style={{ borderTop: '1px solid rgba(255,255,255,0.05)', padding: '8px 16px 10px', display: 'flex', flexWrap: 'wrap', gap: 6, alignItems: 'center' }}>
                    {item.id === 'campaign' && innerDirty && (
                      <button onClick={saveInnerOrder} disabled={innerSaving} style={{ padding: '3px 12px', borderRadius: 20, border: 'none', background: '#3B82F6', color: '#fff', fontSize: 11, fontWeight: 600, cursor: 'pointer', marginRight: 'auto', flexShrink: 0 }}>
                        {innerSaving ? '...' : 'ذخیره ترتیب'}
                      </button>
                    )}
                    {ents.map((e, ei) => {
                      const isCamp = item.id === 'campaign';
                      const isReg  = isCamp && e.priority !== null;
                      return (
                        <div key={e.id} draggable={isCamp}
                          onDragStart={isCamp ? ev => onInnerDragStart(ev, ei) : undefined}
                          onDragEnter={isCamp ? ev => onInnerDragEnter(ev, ei) : undefined}
                          onDragEnd={isCamp ? onInnerDragEnd : undefined}
                          onDragOver={isCamp ? ev => ev.preventDefault() : undefined}
                          style={{
                            fontSize: 11, padding: '3px 10px', borderRadius: 20,
                            background: isReg ? 'rgba(255,255,255,0.06)' : 'rgba(255,255,255,0.03)',
                            border: `1px solid ${isReg ? 'rgba(255,255,255,0.12)' : 'rgba(255,255,255,0.06)'}`,
                            color: isReg ? '#cbd5e1' : '#475569',
                            display: 'flex', alignItems: 'center', gap: 5,
                            cursor: isCamp ? 'grab' : 'default', userSelect: 'none',
                          }}>
                          {isCamp && <span style={{ fontSize: 9, fontFamily: 'JetBrains Mono', fontWeight: 700, color: isReg ? item.color : '#334155', minWidth: 16 }}>{isReg ? `#${e.priority}` : '—'}</span>}
                          {e.name}
                          {e.badge && <span style={{ fontSize: 9, padding: '1px 5px', borderRadius: 10, background: item.color + '20', color: item.color, fontWeight: 700 }}>{e.badge}</span>}
                        </div>
                      );
                    })}
                  </div>
                )}
              </div>
            );
          })}
        </div>

        {dirty && (
          <div style={{ display: 'flex', gap: 10, marginTop: 16, justifyContent: 'flex-end' }}>
            <button onClick={() => { setItems(DEFAULTS); setDirty(true); }} style={{ padding: '8px 16px', borderRadius: 8, cursor: 'pointer', border: '1px solid rgba(255,255,255,0.1)', background: 'transparent', color: '#64748b', fontSize: 13 }}>بازنشانی</button>
            <button onClick={save} disabled={saving} style={{ padding: '8px 20px', borderRadius: 8, border: 'none', background: saving ? '#1e3a5f' : '#3B82F6', color: '#fff', fontSize: 13, fontWeight: 600, cursor: saving ? 'default' : 'pointer' }}>
              {saving ? 'در حال ذخیره...' : 'ذخیره ترتیب'}
            </button>
          </div>
        )}
      </>)}

      {/* ─── تب نقشه سیستم ─── */}
      {tab === 'mindmap' && (
        <MindMap
          entities={entities}
          colors={colors}
          handlerLabels={{ trigger:'تریگر', followup:'فالوآپ', campaign:'کمپین', script:'اسکریپت', bot:'بات' }}
          brainScript={brainScript}
          items={items}
          onBrainClick={() => brainScript && setShowBrain(true)}
          onRefresh={loadData}
          onClose={() => setTab('priority')}
        />
      )}

      {/* ─── تب تست چت ─── */}
      {tab === 'chat' && (<>
        <div style={{ marginBottom: 12, fontSize: 12, color: '#475569', lineHeight: 1.7 }}>
          پیام بفرست — سیستم بر اساس <span style={{ color: '#60A5FA', fontWeight: 600 }}>ترتیب فعلی اولویت</span> می‌گه کدوم handler فعال می‌شه.
        </div>
        <ChatSimulator
          priorityOrder={priorityOrder}
          colors={colors}
          handlerLabels={{ trigger:'تریگر', followup:'فالوآپ', campaign:'کمپین', script:'اسکریپت', bot:'بات' }}
          entities={entities}
        />
      </>)}

      {/* ─── تب سناریوها ─── */}
      {tab === 'scenarios' && (<>
        <div style={{ marginBottom: 16, fontSize: 12, color: '#475569', lineHeight: 1.7 }}>
          سناریوها بر اساس <span style={{ color: '#60A5FA', fontWeight: 600 }}>ترتیب فعلی اولویت</span> محاسبه می‌شن.
          برو تب «ترتیب اولویت» تغییر بده، برگرد اینجا — همه خودکار آپدیت می‌شن.
        </div>

        {/* legend */}
        <div style={{ display: 'flex', gap: 12, flexWrap: 'wrap', marginBottom: 16 }}>
          {items.map((item, i) => (
            <div key={item.id} style={{ display: 'flex', alignItems: 'center', gap: 5, fontSize: 11, color: '#64748b' }}>
              <div style={{ width: 8, height: 8, borderRadius: 2, background: item.color }} />
              <span style={{ color: '#475569', fontFamily: 'JetBrains Mono', fontSize: 9 }}>{i + 1}</span>
              {item.label}
            </div>
          ))}
        </div>

        {SCENARIOS.map(sc => (
          <ScenarioTimeline key={sc.id} scenario={sc} priorityOrder={priorityOrder} colors={colors} />
        ))}
      </>)}

      {/* ─── تب هشدارها ─── */}
      {tab === 'alerts' && (<>
        <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 16 }}>
          <div style={{ fontSize: 12, color: '#475569', lineHeight: 1.7 }}>
            وقتی مغز اصلی پیامی رو نمی‌تونه به هیچ handler وصل کنه، اینجا ثبت می‌شه.
          </div>
          <button onClick={() => window.api('/orchestrator/brain-alerts').then(r => r.success && setAlerts(r.data))}
            style={{ fontSize: 10, color: '#475569', background: 'none', border: '1px solid rgba(255,255,255,0.08)', borderRadius: 6, padding: '4px 10px', cursor: 'pointer' }}>
            رفرش
          </button>
        </div>

        {alerts.length === 0 && (
          <div style={{ textAlign: 'center', color: '#334155', fontSize: 13, padding: '40px 0' }}>
            🎉 هیچ موضوع بی‌جوابی ثبت نشده
          </div>
        )}

        <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
          {alerts.map(alert => (
            <div key={alert.id} style={{
              padding: '12px 16px', borderRadius: 12,
              background: alert.resolved ? 'rgba(255,255,255,0.02)' : 'rgba(239,68,68,0.06)',
              border: `1px solid ${alert.resolved ? 'rgba(255,255,255,0.05)' : 'rgba(239,68,68,0.2)'}`,
              display: 'flex', alignItems: 'flex-start', gap: 12, opacity: alert.resolved ? 0.5 : 1,
            }}>
              <div style={{ fontSize: 18, marginTop: 2 }}>{alert.resolved ? '✅' : '⚠️'}</div>
              <div style={{ flex: 1 }}>
                <div style={{ fontWeight: 600, fontSize: 13, color: alert.resolved ? '#475569' : '#FCA5A5', marginBottom: 4 }}>
                  {alert.topic}
                </div>
                {alert.sample_text && (
                  <div style={{ fontSize: 11, color: '#475569', fontStyle: 'italic', marginBottom: 4 }}>
                    «{alert.sample_text}»
                  </div>
                )}
                <div style={{ display: 'flex', gap: 12, fontSize: 10, color: '#334155' }}>
                  <span>{alert.count} بار تکرار</span>
                  <span>{alert.platform || '—'}</span>
                  <span>{new Date(alert.updated_at).toLocaleDateString('fa-IR')}</span>
                </div>
              </div>
              {!alert.resolved && (
                <button onClick={() => {
                  window.api(`/orchestrator/brain-alerts/${alert.id}/resolve`, { method: 'PATCH' })
                    .then(() => setAlerts(prev => prev.map(a => a.id === alert.id ? {...a, resolved: 1} : a)));
                }} style={{
                  fontSize: 10, color: '#34D399', background: 'rgba(52,211,153,0.08)',
                  border: '1px solid rgba(52,211,153,0.2)', borderRadius: 6, padding: '4px 10px', cursor: 'pointer', flexShrink: 0,
                }}>
                  حل شد
                </button>
              )}
            </div>
          ))}
        </div>
      </>)}
    </div>
  );
};

window.OrchestraBoard = OrchestraBoard;
