/* ============================================================
   Kanban doska + Zakaz detallari + Deadline modali
   ============================================================ */

/* ---------- Bitta zakaz kartasi ---------- */
function OrderCard({ order, onOpen, onEdit, canEdit, onDragStart, onDragEnd, dragging, canDrag, density, queueIndex, canReorder }) {
  const total = DB.orderTotal(order);
  const qty = DB.orderQty(order);
  const col = DB.COLUMNS[DB.COL_INDEX[order.status]];
  const brands = [...new Set(order.lines.map(l => DB.brandOfProduct(l.productId)?.id).filter(Boolean))];
  const deadline = DB.fmtDeadline(order.deadline);
  const dlMs = order.deadline ? new Date(order.deadline).getTime() : null;
  const nowMs = Date.now();
  const overdue = dlMs != null && dlMs < nowMs && order.status !== 'delivered';
  const soon = dlMs != null && !overdue && order.status !== 'delivered' && (dlMs - nowMs) <= 24 * 3600 * 1000;
  const dlBg = overdue ? '#F6DCD6' : (soon ? '#F6E7CF' : 'var(--bg-2)');
  const dlInk = overdue ? '#C2453A' : (soon ? '#A6651E' : 'var(--ink-2)');
  const mgr = DB.orderManager(order);

  return (
    <div
      draggable={canDrag}
      onDragStart={(e) => onDragStart(e, order)}
      onDragEnd={onDragEnd}
      onClick={() => onOpen(order)}
      className="ocard"
      style={{
        background: 'var(--surface)', border: '1px solid var(--border)', borderRadius: 'var(--r)',
        padding: density === 'compact' ? '10px 12px' : '13px 14px', boxShadow: 'var(--sh-1)',
        cursor: canDrag ? 'grab' : 'pointer', opacity: dragging ? .4 : 1, transition: 'box-shadow .15s, transform .12s, border-color .15s',
        borderLeft: `3px solid ${col.color}`, position: 'relative',
      }}>
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 8, marginBottom: 7 }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 7 }}>
          {queueIndex != null && (
            <span title="Navbat" style={{ display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
              minWidth: 22, height: 22, padding: '0 6px', borderRadius: 6, background: 'var(--st-planned)', color: '#fff',
              fontWeight: 800, fontSize: 12, letterSpacing: '.01em' }} className="tnum">#{queueIndex}</span>
          )}
          <span className="tnum" style={{ fontSize: 11.5, fontWeight: 700, color: 'var(--ink-4)', letterSpacing: '.02em' }}>{order.code}</span>
          {order.note && <span title="Izoh bor" style={{ display: 'inline-flex', color: 'var(--brand-700)' }}><Icon name="note" size={13} stroke={2} /></span>}
        </div>
        <div style={{ display: 'flex', alignItems: 'center', gap: 4 }}>
          {brands.map(b => <BrandTag key={b} brandId={b} />)}
          {canReorder && <span title="Navbatni o'zgartirish uchun sudrang" style={{ color: 'var(--st-planned)', display: 'inline-flex', marginLeft: 1 }}><Icon name="drag" size={14} /></span>}
          {canEdit && (
            <button type="button" title="Tahrirlash" aria-label="Tahrirlash"
              onClick={(e) => { e.stopPropagation(); onEdit(); }}
              onMouseDown={(e) => e.stopPropagation()}
              style={{ display: 'inline-flex', alignItems: 'center', justifyContent: 'center', padding: 4, marginLeft: 1,
                       border: 'none', background: 'transparent', borderRadius: 6, color: 'var(--ink-4)', cursor: 'pointer' }}
              onMouseEnter={e => { e.currentTarget.style.background = 'var(--bg-2)'; e.currentTarget.style.color = 'var(--brand-700)'; }}
              onMouseLeave={e => { e.currentTarget.style.background = 'transparent'; e.currentTarget.style.color = 'var(--ink-4)'; }}>
              <Icon name="edit" size={14} />
            </button>
          )}
        </div>
      </div>

      <div style={{ fontWeight: 700, fontSize: 14, letterSpacing: '-.01em', marginBottom: 3, lineHeight: 1.25 }}>
        {DB.distributorName(order.distributorId)}
      </div>
      <div style={{ display: 'flex', alignItems: 'center', gap: 5, color: 'var(--ink-3)', fontSize: 12, marginBottom: 7 }}>
        <Icon name="pin" size={13} stroke={1.8} /> {DB.regionName(order.region)}
      </div>

      {order.createdAt && (
        <div style={{ display: 'flex', alignItems: 'center', gap: 5, color: 'var(--ink-4)', fontSize: 11.5, marginBottom: 7 }}
             title="Kiritilgan sana va vaqt">
          <Icon name="clock" size={12.5} stroke={1.8} /> {DB.fmtDeadline(order.createdAt)}
        </div>
      )}

      {mgr && (
        <div style={{ display: 'flex', alignItems: 'center', gap: 6, marginBottom: 10 }}>
          <span style={{ width: 18, height: 18, borderRadius: '50%', background: 'var(--brand-tint)', color: 'var(--brand-700)',
                         display: 'grid', placeItems: 'center', fontWeight: 800, fontSize: 9, flex: 'none' }}>
            {mgr.name.split(' ').map(s => s[0]).join('').slice(0, 2)}
          </span>
          <span style={{ fontSize: 11.5, color: 'var(--ink-2)', fontWeight: 600 }} title="Javobgar menejer">{mgr.name}</span>
        </div>
      )}

      <div style={{ display: 'flex', alignItems: 'center', gap: 14, fontSize: 12, color: 'var(--ink-2)', marginBottom: deadline ? 9 : 0 }}>
        <span style={{ display: 'flex', alignItems: 'center', gap: 5 }} title="SKU soni">
          <Icon name="layers" size={13} stroke={1.8} style={{ color:'var(--ink-4)' }} /> {order.lines.length} SKU
        </span>
        <span style={{ display: 'flex', alignItems: 'center', gap: 5 }} title="Umumiy miqdor">
          <Icon name="box" size={13} stroke={1.8} style={{ color:'var(--ink-4)' }} /> {qty} dona
        </span>
      </div>

      <div style={{ display: 'flex', alignItems: 'flex-end', justifyContent: 'space-between', gap: 8,
                    marginTop: 10, paddingTop: 10, borderTop: '1px dashed var(--border)' }}>
        <div>
          <div style={{ fontSize: 10.5, color: 'var(--ink-4)', fontWeight: 600 }}>Jami summa</div>
          <div className="tnum" style={{ fontWeight: 800, fontSize: 15, letterSpacing: '-.01em' }}>{DB.fmtSum(total)} <span style={{ fontSize: 11, fontWeight: 600, color: 'var(--ink-3)' }}>so'm</span></div>
        </div>
        {deadline && (
          <div style={{ display: 'flex', alignItems: 'center', gap: 5, fontSize: 11.5, fontWeight: 600,
                        padding: '4px 8px', borderRadius: 6, background: dlBg, color: dlInk }}>
            <Icon name="clock" size={12.5} stroke={2} /> {deadline}
            {overdue && <span style={{ fontWeight: 800 }}>· kechikdi</span>}
          </div>
        )}
      </div>
    </div>
  );
}

/* ---------- Ustun ---------- */
function Column({ col, index, orders, onOpen, onEditOrder, onAdd, perms, canAddHere, dnd, density }) {
  const canEditHere = perms.addOrder || perms.editOrder; // qoʼshish yoki tahrirlash ruxsati boʼlsa edit mumkin
  const total = orders.reduce((s, o) => s + DB.orderTotal(o), 0);
  const isOver = dnd.overCol === col.key;
  const dropAllowed = dnd.dragging && dnd.canDropIn(col.key);
  const isPlanned = col.key === 'planned';
  const canReorder = isPlanned && perms.reorderQueue;
  // reorder faqat planned ustun ichida, dragging karta ham planned'dan bo'lsa
  const reorderActive = canReorder && dnd.dragging && dnd.dragSource === 'planned';

  // insertion indikatori joyi
  const excluded = reorderActive ? orders.filter(o => o.id !== dnd.draggingId) : [];
  const k = dnd.reorderCol === col.key ? dnd.reorderIndex : null;
  const barBeforeId = (reorderActive && k != null && k < excluded.length) ? excluded[k].id : null;
  const barAtEnd = reorderActive && k != null && k >= excluded.length;

  function cardDragOver(e, cardId) {
    if (!reorderActive) return;
    e.preventDefault(); e.stopPropagation();
    const rect = e.currentTarget.getBoundingClientRect();
    const before = (e.clientY - rect.top) < rect.height / 2;
    const j = excluded.findIndex(o => o.id === cardId);
    if (j < 0) return;
    dnd.setReorder(col.key, before ? j : j + 1);
  }

  const Bar = () => (
    <div style={{ height: 3, borderRadius: 3, background: 'var(--st-planned)', margin: '-3px 2px', boxShadow: '0 0 0 3px var(--st-planned-bg)' }} />
  );

  return (
    <div style={{ flex: '1 1 0', minWidth: 236, display: 'flex', flexDirection: 'column', height: '100%' }}>
      {/* Sarlavha */}
      <div style={{ display: 'flex', alignItems: 'center', gap: 9, padding: '0 4px 10px' }}>
        <span className="dot" style={{ width: 9, height: 9, background: col.color }} />
        <span style={{ fontWeight: 700, fontSize: 13.5, letterSpacing: '-.01em' }}>{col.title}</span>
        <span className="chip tnum" style={{ background: col.bg, color: col.color, padding: '2px 8px', fontSize: 11.5 }}>{orders.length}</span>
        <div style={{ flex: 1 }} />
      </div>
      <div className="tnum" style={{ padding: '0 6px 8px', fontSize: 11.5, color: 'var(--ink-4)', fontWeight: 600 }}>
        {DB.fmtSum(total)} so'm
      </div>

      {/* Karta zonasi */}
      <div
        onDragOver={(e) => { if (dropAllowed) { e.preventDefault(); if (reorderActive) dnd.setReorder(col.key, excluded.length); else dnd.setOver(col.key); } }}
        onDragLeave={(e) => { if (e.currentTarget === e.target) dnd.setOver(null); }}
        onDrop={(e) => { e.preventDefault(); dnd.onDrop(col.key); }}
        style={{
          flex: 1, overflowY: 'auto', overflowX: 'hidden', padding: '4px 6px 14px', display: 'flex', flexDirection: 'column', gap: 9,
          borderRadius: 'var(--r)', background: isOver && dropAllowed && !reorderActive ? 'var(--brand-tint)' : (dnd.dragging && dropAllowed && !reorderActive ? 'rgba(11,130,118,.04)' : 'transparent'),
          outline: isOver && dropAllowed && !reorderActive ? '2px dashed var(--brand)' : '2px dashed transparent',
          outlineOffset: -2, transition: 'background .15s, outline-color .15s',
        }}>
        {canAddHere && (
          <button className="add-order-btn" onClick={onAdd}
            style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 7, padding: '11px',
                     border: '1.5px dashed var(--border-2)', borderRadius: 'var(--r)', background: 'var(--surface)',
                     color: 'var(--brand-700)', fontWeight: 700, fontSize: 13, transition: 'all .15s var(--ease)' }}
            onMouseEnter={e => { e.currentTarget.style.borderColor = 'var(--brand)'; e.currentTarget.style.background = 'var(--brand-tint)'; }}
            onMouseLeave={e => { e.currentTarget.style.borderColor = 'var(--border-2)'; e.currentTarget.style.background = 'var(--surface)'; }}>
            <Icon name="plus" size={16} stroke={2.4} /> Zakaz qo'shish
          </button>
        )}
        {orders.map((o, i) => (
          <React.Fragment key={o.id}>
            {barBeforeId === o.id && <Bar />}
            <div onDragOver={(e) => cardDragOver(e, o.id)}>
              <OrderCard order={o} onOpen={onOpen} density={density}
                onEdit={() => onEditOrder(o)} canEdit={canEditHere}
                canDrag={perms.moveAny}
                queueIndex={isPlanned ? i + 1 : null}
                canReorder={canReorder}
                dragging={dnd.draggingId === o.id}
                onDragStart={dnd.onDragStart} onDragEnd={dnd.onDragEnd} />
            </div>
          </React.Fragment>
        ))}
        {barAtEnd && <Bar />}
        {orders.length === 0 && !canAddHere && (
          <div className="px-colempty">
            <Icon name="box" size={16} />
            <span>Bu bosqichda zakaz yo'q</span>
          </div>
        )}
      </div>
    </div>
  );
}

/* ---------- Doska ---------- */
function KanbanBoard({ orders, setOrders, user, perms, onAddOrder, onEditOrder, onDeleteOrder, showToast, reloadOrders, density, search, regionFilter, sortBy }) {
  // Bir zakazni ketma-ket ko'chirishlarni navbatga qo'yamiz (server ularni to'g'ri
  // tartibda oladi); har xil zakazlar parallel ketadi. Vaqtinchalik server xatosida
  // (sekin/5xx/tarmoq) REVERT QILMAYMIZ — optimistik holat qoladi va qayta urinamiz.
  // Faqat haqiqiy rad etishда (4xx — ruxsat/validatsiya) serverga moslaymiz.
  const moveChains = useRef({});
  // Faqat BITTA kartani orqaga qaytaradi (butun doskani emas) — boshqa ko'chirishlarni buzmaydi.
  function revertCard(orderId, status, deadline) {
    setOrders((prev) => prev.map((o) => (o.id === orderId
      ? { ...o, status, ...(deadline !== undefined ? { deadline } : {}) } : o)));
  }
  async function persistMove(fn, revert) {
    const RETRIES = 4;
    for (let a = 0; a <= RETRIES; a++) {
      try {
        await fn();
        return; // muvaffaqiyat — optimistik holat to'g'ri
      } catch (ex) {
        const st = ex && ex.status;
        if (st && st >= 400 && st < 500) { // haqiqiy rad (ruxsat/validatsiya) — FAQAT shu kartani qaytaramiz
          showToast((ex && ex.message) || 'Ruxsat yo`q');
          if (revert) revert();
          return;
        }
        if (a < RETRIES) { await new Promise((r) => setTimeout(r, 400 * (a + 1))); continue; } // vaqtinchalik — qayta
        return; // oxirigacha muvaffaqiyatsiz — optimistik holat qoladi (revert yo'q)
      }
    }
  }
  // Bir zakaz ko'chirishlarini navbatga qo'yamiz (tartib to'g'ri bo'lsin); har xil zakazlar parallel.
  function queueMove(orderId, fn, revert) {
    const prev = moveChains.current[orderId] || Promise.resolve();
    const next = prev.then(() => persistMove(fn, revert)).catch(() => {});
    moveChains.current[orderId] = next;
  }
  // Eski nomlar bilan moslik (izohlar/boshqa amallar uchun)
  const onApiError = (ex) => { showToast((ex && ex.message) || 'Server xatosi'); if (reloadOrders) reloadOrders(); };
  const [openOrder, setOpenOrder] = useState(null);
  const [deadlineFor, setDeadlineFor] = useState(null); // {orderId}
  const [draggingId, setDraggingId] = useState(null);
  const [overCol, setOverCol] = useState(null);
  const [reorderCol, setReorderCol] = useState(null);
  const [reorderIndex, setReorderIndex] = useState(null);
  const dragRef = useRef(null);

  const filtered = useMemo(() => orders.filter(o => {
    if (regionFilter !== 'all' && o.region !== regionFilter) return false;
    if (search) {
      const s = search.toLowerCase();
      const hit = DB.distributorName(o.distributorId).toLowerCase().includes(s)
        || o.code.toLowerCase().includes(s)
        || DB.regionName(o.region).toLowerCase().includes(s);
      if (!hit) return false;
    }
    return true;
  }), [orders, search, regionFilter]);

  const byCol = useMemo(() => {
    const m = {}; DB.COLUMNS.forEach(c => m[c.key] = []);
    filtered.forEach(o => m[o.status].push(o));
    const dl = (o) => (o.deadline ? new Date(o.deadline).getTime() : Infinity); // deadline yo'q — oxiriga
    const nameOf = (o) => DB.distributorName(o.distributorId).toLowerCase();
    const cmp = {
      az: (a, b) => nameOf(a).localeCompare(nameOf(b)),
      za: (a, b) => nameOf(b).localeCompare(nameOf(a)),
      date: (a, b) => dl(a) - dl(b) || (new Date(a.createdAt) - new Date(b.createdAt)),
    }[sortBy] || ((a, b) => (a.order || 0) - (b.order || 0));
    const ct = (o) => (o.createdAt ? new Date(o.createdAt).getTime() : 0);
    Object.entries(m).forEach(([key, arr]) => {
      // Rejalangan ustun — DOIM eng yaqin deadline birinchida (umumiy saralash ta'sir qilmaydi)
      if (key === 'planned') arr.sort((a, b) => dl(a) - dl(b) || (a.order || 0) - (b.order || 0));
      // Rejalanmagan ustun — DOIM eng eski kiritilgan zakaz tepada (vaqt bo'yicha, eskidan-yangiga)
      else if (key === 'unplanned') arr.sort((a, b) => ct(a) - ct(b));
      else arr.sort(cmp);
    });
    return m;
  }, [filtered, sortBy]);

  function canDropIn(targetKey) {
    const o = dragRef.current; if (!o) return false;
    if (o.status === targetKey) {
      // bir ustun ichida: faqat Rejalangan navbatini Generalniy Menejer o'zgartiradi
      return targetKey === 'planned' && perms.reorderQueue;
    }
    // Rejalanmagan → Rejalangan : faqat plan ruxsati borlar
    if (o.status === 'unplanned' && targetKey === 'planned') return perms.plan;
    // "Rejalangan"dan keyingi ustunlar (Yuklanayotgan/Yo'ldagi/Yetkazilgan)
    if (DB.COL_INDEX[targetKey] > DB.COL_INDEX['planned']) {
      if (!perms.moveBeyondPlanned) return false; // #3: regional menejer o'tkaza olmaydi
      if (!o.deadline) return false;              // #4: sanasi yo'q karta o'tmaydi
    }
    // boshqa ustunlar orasida ko'chirish
    return perms.moveAny;
  }

  function onDragStart(e, order) {
    dragRef.current = order; setDraggingId(order.id);
    e.dataTransfer.effectAllowed = 'move';
    try { e.dataTransfer.setData('text/plain', order.id); } catch (_) {}
  }
  function onDragEnd() { setDraggingId(null); setOverCol(null); setReorderCol(null); setReorderIndex(null); dragRef.current = null; }
  function setReorder(colKey, idx) { setReorderCol(colKey); setReorderIndex(idx); setOverCol(colKey); }

  function applyMove(orderId, targetKey, deadline) { applyMoveAt(orderId, targetKey, null, deadline); }

  function applyMoveAt(orderId, targetKey, index, deadline) {
    setOrders(prev => {
      const moving = prev.find(o => o.id === orderId);
      if (!moving) return prev;
      const list = prev.filter(o => o.status === targetKey && o.id !== orderId).sort((a, b) => (a.order || 0) - (b.order || 0));
      const idx = index == null ? list.length : Math.max(0, Math.min(index, list.length));
      const newMoving = { ...moving, status: targetKey,
        deadline: deadline !== undefined ? deadline : (targetKey === 'unplanned' ? null : moving.deadline) };
      list.splice(idx, 0, newMoving);
      const pos = {}; list.forEach((o, i) => pos[o.id] = i);
      return prev.map(o => {
        if (o.id === orderId) return { ...newMoving, order: pos[orderId] };
        if (o.status === targetKey && pos[o.id] != null) return { ...o, order: pos[o.id] };
        return o;
      });
    });
  }

  function onDrop(targetKey) {
    const o = dragRef.current;
    const rCol = reorderCol, rIdx = reorderIndex;
    setOverCol(null); setDraggingId(null); setReorderCol(null); setReorderIndex(null);
    if (!o) return;
    if (o.status === targetKey) {
      if (targetKey === 'planned' && perms.reorderQueue && rCol === 'planned' && rIdx != null) {
        const plannedSorted = orders.filter(x => x.status === 'planned').sort((a, b) => (a.order || 0) - (b.order || 0));
        const oldPos = plannedSorted.findIndex(x => x.id === o.id);
        if (rIdx !== oldPos) {
          applyMoveAt(o.id, 'planned', rIdx);
          showToast('Navbat yangilandi');
          queueMove(o.id, () => API.reorderOrder(o.id, rIdx), () => { if (reloadOrders) reloadOrders(); });
        }
      } else if (targetKey === 'planned' && !perms.reorderQueue) {
        showToast('Navbatni faqat Generalniy Menejer oʼzgartiradi');
      }
      dragRef.current = null; return;
    }

    if (!canDropIn(targetKey)) {
      const beyondPlanned = DB.COL_INDEX[targetKey] > DB.COL_INDEX['planned'];
      if (o.status === 'unplanned' && targetKey === 'planned') {
        showToast('Rejalashtirish faqat super adminlar uchun');
      } else if (beyondPlanned && !perms.moveBeyondPlanned) {
        showToast("Regional menejer 'Rejalangan'dan keyingi ustunga ko\u02bcchira olmaydi");
      } else if (beyondPlanned && !o.deadline) {
        showToast('Avval sanasini belgilang (rejalashtiring) \u2014 sanasiz bu ustunga o\u02bctmaydi');
      } else {
        showToast('Bu amal uchun ruxsatingiz yo\u02bcq');
      }
      dragRef.current = null; return;
    }

    // Rejalanmagan → Rejalangan : majburiy deadline
    if (o.status === 'unplanned' && targetKey === 'planned') {
      setDeadlineFor({ orderId: o.id });
      dragRef.current = null; return;
    }
    const fromStatus = o.status, fromDeadline = o.deadline;
    applyMove(o.id, targetKey);
    const col = DB.COLUMNS[DB.COL_INDEX[targetKey]];
    showToast(`${o.code} → ${col.title}`);
    queueMove(o.id, () => API.moveOrder(o.id, targetKey), () => revertCard(o.id, fromStatus, fromDeadline));
    dragRef.current = null;
  }

  function confirmDeadline(iso) {
    const oid = deadlineFor.orderId;
    const o = orders.find(x => x.id === oid);
    const fromStatus = o ? o.status : 'unplanned', fromDeadline = o ? o.deadline : null;
    applyMove(oid, 'planned', iso);
    showToast(`${o ? o.code : 'Zakaz'} rejalashtirildi`);
    queueMove(oid, () => API.moveOrder(oid, 'planned', iso), () => revertCard(oid, fromStatus, fromDeadline));
    setDeadlineFor(null);
  }

  const dnd = { draggingId, dragging: !!draggingId, overCol, setOver: setOverCol, onDragStart, onDragEnd, onDrop, canDropIn,
                dragSource: dragRef.current ? dragRef.current.status : null,
                reorderCol, reorderIndex, setReorder };

  return (
    <>
      <div style={{ display: 'flex', gap: 14, padding: '4px 22px 18px', height: '100%', overflowX: 'auto' }}>
        {DB.COLUMNS.map((col, i) => (
          <Column key={col.key} col={col} index={i} orders={byCol[col.key]} density={density}
            onOpen={setOpenOrder} onEditOrder={onEditOrder} onAdd={onAddOrder} perms={perms} dnd={dnd}
            canAddHere={col.key === 'unplanned' && perms.addOrder} />
        ))}
      </div>

      {openOrder && (
        <OrderDetail order={orders.find(o => o.id === openOrder.id) || openOrder}
          perms={perms} onClose={() => setOpenOrder(null)}
          onEdit={() => { const o = openOrder; setOpenOrder(null); onEditOrder(o); }}
          onSaveNote={async (id, note) => {
            try {
              const { order } = await API.updateOrderNote(id, note);
              setOrders(prev => prev.map(o => (o.id === order.id ? order : o)));
              showToast('Izoh saqlandi');
            } catch (ex) { onApiError(ex); throw ex; }
          }}
          onDelete={onDeleteOrder ? (() => { const o = openOrder; setOpenOrder(null); onDeleteOrder(o); }) : null} />
      )}

      {deadlineFor && (
        <DeadlineModal onClose={() => setDeadlineFor(null)} onConfirm={confirmDeadline}
          order={orders.find(o => o.id === deadlineFor.orderId)} />
      )}
    </>
  );
}

window.KanbanBoard = KanbanBoard;
