// ───── Servis — plne customizovateľná nástenka (Trello-style kanban) ─────
// Nástenky → stĺpce (voľne pomenovateľné/farebné/preraditeľné) → kartičky.
// Karta = servisný prípad (u koho prebieha servis, kontakt, technik, priorita…).
// Archív: kartu možno archivovať namiesto zmazania — zostáva v DB roky a je
// dostupná cez záložku „Archív" (vyhľadávanie + obnovenie).
// Backend: routes/servis.js  ·  práva: servis.view / servis.edit

const SERVIS_PALETTE = ['#3a6da0', '#f3a712', '#7b68ee', '#2a9d5f', '#d64545', '#0e2744', '#8a5a2b', '#16a34a', '#64748b', '#c084fc'];

const SERVIS_PRIORITY = {
  low:    { label: 'Nízka',     color: '#64748b' },
  normal: { label: 'Normálna',  color: '#3a6da0' },
  high:   { label: 'Vysoká',    color: '#f3a712' },
  urgent: { label: 'Urgentné',  color: '#d64545' },
};

function servisInitials(name) {
  return (name || '?').split(/\s+/).map(p => p[0]).filter(Boolean).join('').slice(0, 2).toUpperCase();
}
function servisFmtDate(ts) {
  if (!ts) return '';
  const d = new Date(ts * 1000);
  return d.toLocaleDateString('sk', { day: 'numeric', month: 'short', year: 'numeric' });
}
function servisDueMeta(due) {
  if (!due) return null;
  const today = new Date(); today.setHours(0, 0, 0, 0);
  const d = new Date(due + 'T00:00:00');
  const diff = Math.round((d - today) / 86400000);
  const color = diff < 0 ? '#d64545' : diff <= 2 ? '#f3a712' : '#64748b';
  const txt = d.toLocaleDateString('sk', { day: 'numeric', month: 'short' });
  return { color, txt, overdue: diff < 0 };
}

// JSON helpers — všetky write operácie cez jeden wrapper.
async function servisApi(method, path, body) {
  const opts = { method, credentials: 'same-origin' };
  if (body !== undefined) { opts.headers = { 'Content-Type': 'application/json' }; opts.body = JSON.stringify(body); }
  const r = await fetch('/api/servis' + path, opts);
  let j = {}; try { j = await r.json(); } catch {}
  return { ok: r.ok && j.ok !== false, status: r.status, body: j };
}

function ServisBoard() {
  const [boards, setBoards]   = React.useState([]);
  const [boardId, setBoardId] = React.useState(null);
  const [columns, setColumns] = React.useState([]);
  const [cards, setCards]     = React.useState([]);
  const [assignees, setAssignees] = React.useState([]);
  const [loading, setLoading] = React.useState(true);
  const [view, setView]       = React.useState('board');   // board | archive
  const [toast, setToast]     = React.useState(null);
  const [editCard, setEditCard]   = React.useState(null);  // celá karta (detail modal)
  const [newCardCol, setNewCardCol] = React.useState(null); // column id pre rýchle pridanie
  const [colMenu, setColMenu]     = React.useState(null);  // column id s otvoreným menu
  const [boardMenu, setBoardMenu] = React.useState(false);

  const canEdit = window.hasPerm ? window.hasPerm('servis.edit') : false;
  const dragId = React.useRef(null);
  const notify = (kind, text) => setToast({ kind, text });

  // ── load ──
  React.useEffect(() => { boot(); /* eslint-disable-next-line */ }, []);
  async function boot() {
    setLoading(true);
    const [b, a] = await Promise.all([servisApi('GET', '/boards'), servisApi('GET', '/assignees')]);
    if (a.ok) setAssignees(a.body.users || []);
    const list = (b.body && b.body.boards) || [];
    setBoards(list);
    const first = list[0] ? list[0].id : null;
    setBoardId(first);
    if (first) await loadBoard(first);
    else setLoading(false);
  }
  async function loadBoard(id) {
    setLoading(true);
    const r = await servisApi('GET', `/boards/${id}`);
    if (r.ok) { setColumns(r.body.columns || []); setCards(r.body.cards || []); }
    setLoading(false);
  }
  function switchBoard(id) { setBoardId(id); setView('board'); loadBoard(id); }
  async function reloadBoards() {
    const b = await servisApi('GET', '/boards');
    if (b.ok) setBoards(b.body.boards || []);
  }

  // ── boards ──
  async function createBoard() {
    const name = prompt('Názov novej nástenky:'); if (!name || !name.trim()) return;
    const r = await servisApi('POST', '/boards', { name: name.trim() });
    if (r.ok) { await reloadBoards(); switchBoard(r.body.board.id); notify('success', 'Nástenka vytvorená.'); }
    else notify('error', 'Nepodarilo sa vytvoriť nástenku.');
  }
  async function renameBoard() {
    setBoardMenu(false);
    const cur = boards.find(b => b.id === boardId);
    const name = prompt('Nový názov nástenky:', cur ? cur.name : ''); if (!name || !name.trim()) return;
    const r = await servisApi('PATCH', `/boards/${boardId}`, { name: name.trim() });
    if (r.ok) { await reloadBoards(); notify('success', 'Premenované.'); }
  }
  async function deleteBoard() {
    setBoardMenu(false);
    if (boards.length <= 1) return notify('error', 'Musí ostať aspoň jedna nástenka.');
    if (!confirm('Zmazať celú nástenku vrátane všetkých stĺpcov a kariet (aj archivovaných)? Túto akciu nie je možné vrátiť.')) return;
    const r = await servisApi('DELETE', `/boards/${boardId}`);
    if (r.ok) { const rest = boards.filter(b => b.id !== boardId); setBoards(rest); switchBoard(rest[0].id); notify('success', 'Nástenka zmazaná.'); }
  }

  // ── columns ──
  async function addColumn() {
    const name = prompt('Názov stĺpca:'); if (!name || !name.trim()) return;
    const color = SERVIS_PALETTE[columns.length % SERVIS_PALETTE.length];
    const r = await servisApi('POST', `/boards/${boardId}/columns`, { name: name.trim(), color });
    if (r.ok) setColumns(c => [...c, r.body.column]);
    else notify('error', 'Chyba pri pridávaní stĺpca.');
  }
  async function renameColumn(col) {
    setColMenu(null);
    const name = prompt('Premenovať stĺpec:', col.name); if (!name || !name.trim()) return;
    const r = await servisApi('PATCH', `/columns/${col.id}`, { name: name.trim() });
    if (r.ok) setColumns(cs => cs.map(c => c.id === col.id ? r.body.column : c));
  }
  async function recolorColumn(col, color) {
    setColMenu(null);
    const r = await servisApi('PATCH', `/columns/${col.id}`, { color });
    if (r.ok) setColumns(cs => cs.map(c => c.id === col.id ? r.body.column : c));
  }
  async function deleteColumn(col) {
    setColMenu(null);
    const n = cards.filter(c => c.column_id === col.id).length;
    const msg = n > 0
      ? `Zmazať stĺpec „${col.name}"? Jeho ${n} kariet sa presunie do archívu (nestratia sa).`
      : `Zmazať prázdny stĺpec „${col.name}"?`;
    if (!confirm(msg)) return;
    const r = await servisApi('DELETE', `/columns/${col.id}`);
    if (r.ok) { setColumns(cs => cs.filter(c => c.id !== col.id)); setCards(cs => cs.filter(c => c.column_id !== col.id)); notify('success', n > 0 ? `Stĺpec zmazaný, ${n} kariet v archíve.` : 'Stĺpec zmazaný.'); }
  }

  // ── cards: drag & drop ──
  function onDropOnColumn(colId, beforeCardId) {
    const id = dragId.current; dragId.current = null;
    if (!id) return;
    const moving = cards.find(c => c.id === id); if (!moving) return;
    // poradie kariet v cieľovom stĺpci (bez presúvanej)
    const rest = cards.filter(c => c.column_id === colId && c.id !== id).sort((a, b) => a.sort_order - b.sort_order);
    const idx = beforeCardId ? rest.findIndex(c => c.id === beforeCardId) : rest.length;
    const arranged = [...rest.slice(0, idx < 0 ? rest.length : idx), { ...moving, column_id: colId }, ...rest.slice(idx < 0 ? rest.length : idx)];
    const orderedIds = arranged.map(c => c.id);
    // optimistický update
    setCards(prev => prev.map(c => {
      if (c.id === id) return { ...c, column_id: colId, sort_order: orderedIds.indexOf(id) };
      if (c.column_id === colId || arranged.some(a => a.id === c.id)) { const oi = orderedIds.indexOf(c.id); if (oi >= 0) return { ...c, sort_order: oi }; }
      return c;
    }));
    servisApi('POST', `/cards/${id}/move`, { to_column_id: colId, ordered_ids: orderedIds })
      .then(r => { if (!r.ok) { notify('error', 'Presun zlyhal.'); loadBoard(boardId); } });
  }

  // ── card create / detail handled by sub-components below ──
  function onCardSaved(saved) {
    setCards(prev => prev.some(c => c.id === saved.id) ? prev.map(c => c.id === saved.id ? saved : c) : [...prev, saved]);
  }
  async function archiveCard(card) {
    const r = await servisApi('POST', `/cards/${card.id}/archive`);
    if (r.ok) { setCards(cs => cs.filter(c => c.id !== card.id)); setEditCard(null); notify('success', 'Presunuté do archívu.'); }
    else notify('error', 'Chyba pri archivácii.');
  }
  async function deleteCard(card) {
    if (!confirm('Trvalo zmazať túto kartu? Nedá sa vrátiť. (Tip: použi radšej archiváciu.)')) return;
    const r = await servisApi('DELETE', `/cards/${card.id}`);
    if (r.ok) { setCards(cs => cs.filter(c => c.id !== card.id)); setEditCard(null); notify('success', 'Karta zmazaná.'); }
  }

  const cardsOf = (colId) => cards.filter(c => c.column_id === colId).sort((a, b) => a.sort_order - b.sort_order);
  const curBoard = boards.find(b => b.id === boardId);

  return (
    <AppShell active="servis" crumbs={['ERP', 'Servis']}>
      {toast && <Toast kind={toast.kind} onClose={() => setToast(null)}>{toast.text}</Toast>}

      <div className="page-head">
        <div>
          <div className="hstack" style={{ gap: 8 }}>
            <h1 style={{ margin: 0 }}>Servis</h1>
            {/* prepínač násteniek */}
            {boards.length > 1 && (
              <select className="select" value={boardId || ''} onChange={e => switchBoard(Number(e.target.value))} style={{ width: 'auto' }}>
                {boards.map(b => <option key={b.id} value={b.id}>{b.name}</option>)}
              </select>
            )}
            {canEdit && (
              <div style={{ position: 'relative' }}>
                <button className="btn btn-ghost btn-xs" onClick={() => setBoardMenu(v => !v)} title="Nastavenia nástenky"><Ico.dots /></button>
                {boardMenu && (
                  <div className="servis-menu" onMouseLeave={() => setBoardMenu(false)}>
                    <button onClick={renameBoard}>Premenovať nástenku</button>
                    <button onClick={createBoard}>+ Nová nástenka</button>
                    <button className="danger" onClick={deleteBoard}>Zmazať nástenku</button>
                  </div>
                )}
              </div>
            )}
          </div>
          <p>Customizovateľná nástenka servisných prípadov · {curBoard ? curBoard.name : '—'}</p>
        </div>
        <div className="page-head-actions">
          <div className="seg">
            <button className={view === 'board' ? 'active' : ''} onClick={() => setView('board')}>Nástenka</button>
            <button className={view === 'archive' ? 'active' : ''} onClick={() => setView('archive')}>Archív</button>
          </div>
        </div>
      </div>

      {loading && <div className="muted" style={{ padding: 40, textAlign: 'center' }}>Načítavam…</div>}

      {!loading && view === 'board' && (
        <div className="servis-board">
          {columns.map(col => (
            <ServisColumn
              key={col.id}
              col={col}
              cards={cardsOf(col.id)}
              canEdit={canEdit}
              menuOpen={colMenu === col.id}
              onMenu={() => setColMenu(colMenu === col.id ? null : col.id)}
              onRename={() => renameColumn(col)}
              onRecolor={(c) => recolorColumn(col, c)}
              onDelete={() => deleteColumn(col)}
              onAddCard={() => setNewCardCol(col.id)}
              onOpenCard={(c) => setEditCard(c)}
              dragId={dragId}
              onDrop={onDropOnColumn}
            />
          ))}
          {canEdit && (
            <div className="servis-col-add">
              <button className="btn btn-ghost btn-block" onClick={addColumn}><Ico.plus /> Pridať stĺpec</button>
            </div>
          )}
          {columns.length === 0 && !canEdit && <div className="muted" style={{ padding: 40 }}>Nástenka zatiaľ nemá žiadne stĺpce.</div>}
        </div>
      )}

      {!loading && view === 'archive' && (
        <ServisArchive boardId={boardId} canEdit={canEdit} columns={columns}
          onChanged={() => loadBoard(boardId)} notify={notify} onOpenCard={(c) => setEditCard(c)} />
      )}

      {/* rýchle pridanie karty */}
      {newCardCol && (
        <ServisCardModal
          mode="create" columnId={newCardCol} assignees={assignees}
          onClose={() => setNewCardCol(null)}
          onSaved={(card) => { onCardSaved(card); setNewCardCol(null); notify('success', 'Karta pridaná.'); }}
          notify={notify}
        />
      )}

      {/* detail / editácia karty */}
      {editCard && (
        <ServisCardModal
          mode="edit" card={editCard} assignees={assignees} canEdit={canEdit}
          onClose={() => setEditCard(null)}
          onSaved={(card) => { onCardSaved(card); setEditCard(card); }}
          onArchive={() => archiveCard(editCard)}
          onDelete={() => deleteCard(editCard)}
          notify={notify}
        />
      )}

      <ServisStyles />
    </AppShell>
  );
}

// ───── Stĺpec ─────
function ServisColumn({ col, cards, canEdit, menuOpen, onMenu, onRename, onRecolor, onDelete, onAddCard, onOpenCard, dragId, onDrop }) {
  const [dragOver, setDragOver] = React.useState(false);
  return (
    <div className="servis-col">
      <div className="servis-col-head" style={{ borderTopColor: col.color || '#cbd5e1' }}>
        <span className="dot" style={{ background: col.color || '#cbd5e1' }} />
        <span className="servis-col-name">{col.name}</span>
        <span className="servis-col-count">{cards.length}</span>
        {canEdit && (
          <div style={{ position: 'relative', marginLeft: 'auto' }}>
            <button className="btn btn-ghost btn-xs" onClick={onMenu}><Ico.dots /></button>
            {menuOpen && (
              <div className="servis-menu" onMouseLeave={onMenu}>
                <button onClick={onRename}>Premenovať</button>
                <div className="servis-swatches">
                  {SERVIS_PALETTE.map(c => <span key={c} style={{ background: c }} onClick={() => onRecolor(c)} />)}
                </div>
                <button className="danger" onClick={onDelete}>Zmazať stĺpec</button>
              </div>
            )}
          </div>
        )}
      </div>

      <div
        className={'servis-col-body' + (dragOver ? ' drag-over' : '')}
        onDragOver={e => { if (dragId.current) { e.preventDefault(); setDragOver(true); } }}
        onDragLeave={() => setDragOver(false)}
        onDrop={e => { e.preventDefault(); setDragOver(false); onDrop(col.id, null); }}
      >
        {cards.map(card => (
          <ServisCard key={card.id} card={card} canEdit={canEdit} dragId={dragId}
            onOpen={() => onOpenCard(card)} onDropBefore={() => onDrop(col.id, card.id)} />
        ))}
        {canEdit && <button className="servis-add-card" onClick={onAddCard}><Ico.plus /> Pridať kartu</button>}
      </div>
    </div>
  );
}

// ───── Kartička ─────
function ServisCard({ card, canEdit, dragId, onOpen, onDropBefore }) {
  const prio = card.priority ? SERVIS_PRIORITY[card.priority] : null;
  const due = servisDueMeta(card.due_date);
  return (
    <div
      className="servis-card"
      draggable={canEdit}
      onDragStart={() => { dragId.current = card.id; }}
      onDragEnd={() => { dragId.current = null; }}
      onDragOver={e => { if (dragId.current && dragId.current !== card.id) e.preventDefault(); }}
      onDrop={e => { e.preventDefault(); e.stopPropagation(); onDropBefore(); }}
      onClick={onOpen}
    >
      {card.labels && card.labels.length > 0 && (
        <div className="servis-labels">
          {card.labels.map((l, i) => <span key={i} style={{ background: (l.color || '#64748b') + '22', color: l.color || '#64748b' }}>{l.text}</span>)}
        </div>
      )}
      <div className="servis-card-title">{card.title}</div>
      {card.customer && <div className="servis-card-sub"><Ico.users style={{ width: 12, height: 12 }} /> {card.customer}</div>}
      {card.location && <div className="servis-card-sub">📍 {card.location}</div>}
      <div className="servis-card-foot">
        {prio && <span className="servis-prio" style={{ background: prio.color + '22', color: prio.color }}>{prio.label}</span>}
        {due && <span className="servis-due" style={{ color: due.color }}>{due.overdue ? '⚠ ' : '🗓 '}{due.txt}</span>}
        <span style={{ flex: 1 }} />
        {card.comments_count > 0 && <span className="servis-meta">💬 {card.comments_count}</span>}
        {card.assignee_name && <span className="servis-avatar" title={card.assignee_name}>{servisInitials(card.assignee_name)}</span>}
      </div>
    </div>
  );
}

// ───── Modal: vytvorenie / detail karty ─────
function ServisCardModal({ mode, card, columnId, assignees, canEdit = true, onClose, onSaved, onArchive, onDelete, notify }) {
  const isEdit = mode === 'edit';
  const [f, setF] = React.useState(() => ({
    title: card?.title || '', description: card?.description || '',
    customer: card?.customer || '', location: card?.location || '', contact: card?.contact || '',
    assignee_id: card?.assignee_id || '', priority: card?.priority || '', due_date: card?.due_date || '',
    labels: card?.labels ? [...card.labels] : [],
  }));
  const [busy, setBusy] = React.useState(false);
  const [comments, setComments] = React.useState([]);
  const [newComment, setNewComment] = React.useState('');
  const [newLabel, setNewLabel] = React.useState('');
  const [labelColor, setLabelColor] = React.useState(SERVIS_PALETTE[1]);
  const set = (k, v) => setF(prev => ({ ...prev, [k]: v }));
  const me = (window.currentSession && window.currentSession.user) || {};

  React.useEffect(() => {
    if (isEdit && card) {
      servisApi('GET', `/cards/${card.id}/comments`).then(r => { if (r.ok) setComments(r.body.comments || []); });
    }
  }, [isEdit, card && card.id]);

  function payload() {
    return {
      title: f.title, description: f.description, customer: f.customer, location: f.location, contact: f.contact,
      assignee_id: f.assignee_id || null, priority: f.priority || null, due_date: f.due_date || null, labels: f.labels,
    };
  }
  async function save() {
    if (!f.title.trim()) return notify('error', 'Zadajte názov karty.');
    setBusy(true);
    const r = isEdit
      ? await servisApi('PATCH', `/cards/${card.id}`, payload())
      : await servisApi('POST', `/columns/${columnId}/cards`, payload());
    setBusy(false);
    if (r.ok) onSaved(r.body.card);
    else notify('error', 'Uloženie zlyhalo.');
  }
  function addLabel() {
    if (!newLabel.trim()) return;
    set('labels', [...f.labels, { text: newLabel.trim(), color: labelColor }]);
    setNewLabel('');
  }
  async function postComment() {
    if (!newComment.trim()) return;
    const r = await servisApi('POST', `/cards/${card.id}/comments`, { body: newComment.trim() });
    if (r.ok) { setComments(cs => [...cs, r.body.comment]); setNewComment(''); }
  }
  async function delComment(id) {
    const r = await servisApi('DELETE', `/comments/${id}`);
    if (r.ok) setComments(cs => cs.filter(c => c.id !== id));
  }

  const readOnly = isEdit && !canEdit;
  const footer = (
    <div className="hstack" style={{ width: '100%' }}>
      {isEdit && canEdit && <button className="btn btn-sm" onClick={onArchive}><Ico.download /> Archivovať</button>}
      {isEdit && canEdit && <button className="btn btn-sm btn-ghost danger" onClick={onDelete}>Zmazať</button>}
      <span style={{ flex: 1 }} />
      <button className="btn btn-sm btn-ghost" onClick={onClose}>Zavrieť</button>
      {!readOnly && <button className="btn btn-sm btn-primary" onClick={save} disabled={busy}>{busy ? 'Ukladám…' : 'Uložiť'}</button>}
    </div>
  );

  return (
    <Modal title={isEdit ? 'Detail servisného prípadu' : 'Nový servisný prípad'} onClose={onClose} footer={footer} width={620}>
      <div className="vstack" style={{ gap: 12 }}>
        <div className="field">
          <label>Názov *</label>
          <input className="input" value={f.title} onChange={e => set('title', e.target.value)} disabled={readOnly} autoFocus placeholder="napr. Výmena meniča — RD Kučera" />
        </div>
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 10 }}>
          <div className="field"><label>Zákazník</label><input className="input" value={f.customer} onChange={e => set('customer', e.target.value)} disabled={readOnly} placeholder="u koho prebieha servis" /></div>
          <div className="field"><label>Miesto / adresa</label><input className="input" value={f.location} onChange={e => set('location', e.target.value)} disabled={readOnly} /></div>
        </div>
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', gap: 10 }}>
          <div className="field"><label>Kontakt</label><input className="input" value={f.contact} onChange={e => set('contact', e.target.value)} disabled={readOnly} placeholder="telefón / e-mail" /></div>
          <div className="field">
            <label>Technik</label>
            <select className="select" value={f.assignee_id} onChange={e => set('assignee_id', e.target.value)} disabled={readOnly}>
              <option value="">— nikto —</option>
              {assignees.map(u => <option key={u.id} value={u.id}>{u.name}</option>)}
            </select>
          </div>
          <div className="field">
            <label>Priorita</label>
            <select className="select" value={f.priority} onChange={e => set('priority', e.target.value)} disabled={readOnly}>
              <option value="">—</option>
              {Object.entries(SERVIS_PRIORITY).map(([k, v]) => <option key={k} value={k}>{v.label}</option>)}
            </select>
          </div>
        </div>
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 2fr', gap: 10 }}>
          <div className="field"><label>Termín</label><input className="input" type="date" value={f.due_date} onChange={e => set('due_date', e.target.value)} disabled={readOnly} /></div>
          <div className="field">
            <label>Štítky</label>
            <div className="servis-labels" style={{ marginBottom: 6 }}>
              {f.labels.map((l, i) => (
                <span key={i} style={{ background: (l.color || '#64748b') + '22', color: l.color || '#64748b' }}>
                  {l.text}{!readOnly && <b onClick={() => set('labels', f.labels.filter((_, j) => j !== i))} style={{ cursor: 'pointer', marginLeft: 4 }}>×</b>}
                </span>
              ))}
            </div>
            {!readOnly && (
              <div className="hstack" style={{ gap: 6 }}>
                <input className="input" style={{ flex: 1 }} value={newLabel} placeholder="nový štítok" onChange={e => setNewLabel(e.target.value)} onKeyDown={e => e.key === 'Enter' && (e.preventDefault(), addLabel())} />
                <input type="color" value={labelColor} onChange={e => setLabelColor(e.target.value)} style={{ width: 34, height: 34, padding: 2, border: '1px solid var(--border)', borderRadius: 6 }} />
                <button className="btn btn-sm" onClick={addLabel}>+</button>
              </div>
            )}
          </div>
        </div>
        <div className="field">
          <label>Popis / poznámky</label>
          <textarea className="input" rows={4} value={f.description} onChange={e => set('description', e.target.value)} disabled={readOnly} placeholder="Čo treba vykonať, postup, čo sa zistilo…" />
        </div>

        {/* Komentáre / aktivita — len v detaile uloženej karty */}
        {isEdit && (
          <div className="field">
            <label>Aktivita ({comments.length})</label>
            <div className="vstack" style={{ gap: 8, marginBottom: 8 }}>
              {comments.length === 0 && <div className="muted small">Zatiaľ žiadne poznámky.</div>}
              {comments.map(c => (
                <div key={c.id} className="servis-comment">
                  <span className="servis-avatar">{servisInitials(c.user_name)}</span>
                  <div style={{ flex: 1 }}>
                    <div className="small"><b>{c.user_name || 'Neznámy'}</b> <span className="muted">· {servisFmtDate(c.created_at)}</span></div>
                    <div style={{ whiteSpace: 'pre-wrap' }}>{c.body}</div>
                  </div>
                  {(c.user_id === me.id || me.role === 'admin') && <b className="servis-comment-del" onClick={() => delComment(c.id)}>×</b>}
                </div>
              ))}
            </div>
            {canEdit && (
              <div className="hstack" style={{ gap: 6 }}>
                <input className="input" style={{ flex: 1 }} value={newComment} placeholder="Pridať poznámku…" onChange={e => setNewComment(e.target.value)} onKeyDown={e => e.key === 'Enter' && (e.preventDefault(), postComment())} />
                <button className="btn btn-sm" onClick={postComment}>Pridať</button>
              </div>
            )}
          </div>
        )}
      </div>
    </Modal>
  );
}

// ───── Archív ─────
function ServisArchive({ boardId, canEdit, columns, onChanged, notify, onOpenCard }) {
  const [q, setQ] = React.useState('');
  const [rows, setRows] = React.useState([]);
  const [loading, setLoading] = React.useState(true);

  async function load() {
    setLoading(true);
    const r = await servisApi('GET', `/archive?board_id=${boardId}&q=${encodeURIComponent(q)}`);
    if (r.ok) setRows(r.body.cards || []);
    setLoading(false);
  }
  React.useEffect(() => { const t = setTimeout(load, 250); return () => clearTimeout(t); /* eslint-disable-next-line */ }, [q, boardId]);

  async function restore(card) {
    const r = await servisApi('POST', `/cards/${card.id}/restore`, {});
    if (r.ok) { setRows(rs => rs.filter(c => c.id !== card.id)); onChanged(); notify('success', 'Obnovené na nástenku.'); }
    else notify('error', 'Obnovenie zlyhalo.');
  }
  async function remove(card) {
    if (!confirm('Trvalo zmazať z archívu? Nedá sa vrátiť.')) return;
    const r = await servisApi('DELETE', `/cards/${card.id}`);
    if (r.ok) setRows(rs => rs.filter(c => c.id !== card.id));
  }

  return (
    <div className="card">
      <div className="card-head">
        <h3>Archív servisných prípadov</h3>
        <input className="input" placeholder="Hľadať v archíve (zákazník, názov, miesto…)" value={q} onChange={e => setQ(e.target.value)} style={{ width: 320 }} />
      </div>
      <div className="card-body">
        {loading && <div className="muted" style={{ padding: 20 }}>Načítavam…</div>}
        {!loading && rows.length === 0 && <div className="muted" style={{ padding: 20 }}>Archív je prázdny{q ? ' pre tento filter' : ''}.</div>}
        {!loading && rows.length > 0 && (
          <table className="tbl">
            <thead><tr><th>Názov</th><th>Zákazník</th><th>Miesto</th><th>Technik</th><th>Archivované</th><th></th></tr></thead>
            <tbody>
              {rows.map(c => (
                <tr key={c.id} style={{ cursor: 'pointer' }}>
                  <td onClick={() => onOpenCard(c)}><b>{c.title}</b></td>
                  <td onClick={() => onOpenCard(c)}>{c.customer || '—'}</td>
                  <td onClick={() => onOpenCard(c)} className="small muted">{c.location || '—'}</td>
                  <td className="small">{c.assignee_name || '—'}</td>
                  <td className="small muted">{servisFmtDate(c.archived_at)}</td>
                  <td>
                    {canEdit && <button className="btn btn-xs" onClick={() => restore(c)}>Obnoviť</button>}
                    {canEdit && <button className="btn btn-xs btn-ghost danger" onClick={() => remove(c)} style={{ marginLeft: 6 }}>Zmazať</button>}
                  </td>
                </tr>
              ))}
            </tbody>
          </table>
        )}
      </div>
    </div>
  );
}

// ───── Štýly špecifické pre Servis ─────
function ServisStyles() {
  return <style>{`
    .servis-board { display:flex; gap:14px; align-items:flex-start; overflow-x:auto; padding-bottom:14px; min-height:60vh; }
    .servis-col { flex:0 0 290px; width:290px; background:var(--surface-2,#f1f4f9); border:1px solid var(--border,#e2e8f0); border-radius:12px; display:flex; flex-direction:column; max-height:calc(100vh - 220px); }
    .servis-col-head { display:flex; align-items:center; gap:8px; padding:10px 12px; border-top:3px solid #cbd5e1; border-radius:12px 12px 0 0; }
    .servis-col-head .dot { width:9px; height:9px; border-radius:50%; flex:0 0 auto; }
    .servis-col-name { font-weight:700; font-size:13.5px; color:var(--ink-900,#0f172a); }
    .servis-col-count { font-size:11px; background:var(--border,#e2e8f0); color:var(--ink-500,#64748b); border-radius:20px; padding:1px 7px; font-weight:600; }
    .servis-col-body { padding:0 10px 10px; overflow-y:auto; display:flex; flex-direction:column; gap:8px; min-height:40px; }
    .servis-col-body.drag-over { background:rgba(58,109,160,0.08); border-radius:8px; outline:2px dashed var(--navy-400,#7da0c4); outline-offset:-4px; }
    .servis-card { background:#fff; border:1px solid var(--border,#e2e8f0); border-radius:9px; padding:10px; cursor:pointer; box-shadow:0 1px 2px rgba(15,23,42,0.04); transition:box-shadow .12s,transform .12s; }
    .servis-card:hover { box-shadow:0 4px 12px rgba(15,23,42,0.10); transform:translateY(-1px); }
    .servis-card-title { font-weight:600; font-size:13.5px; line-height:1.35; color:var(--ink-900,#0f172a); }
    .servis-card-sub { font-size:12px; color:var(--ink-500,#64748b); margin-top:3px; display:flex; align-items:center; gap:4px; }
    .servis-card-foot { display:flex; align-items:center; gap:6px; margin-top:8px; flex-wrap:wrap; }
    .servis-labels { display:flex; flex-wrap:wrap; gap:4px; margin-bottom:6px; }
    .servis-labels span { font-size:10.5px; font-weight:600; padding:1px 7px; border-radius:20px; }
    .servis-prio { font-size:10.5px; font-weight:700; padding:1px 7px; border-radius:20px; }
    .servis-due { font-size:11px; font-weight:600; }
    .servis-meta { font-size:11px; color:var(--ink-500,#64748b); }
    .servis-avatar { width:22px; height:22px; border-radius:50%; background:var(--navy-800,#0e2744); color:#fff; font-size:9.5px; font-weight:700; display:inline-flex; align-items:center; justify-content:center; flex:0 0 auto; }
    .servis-add-card { background:transparent; border:1px dashed var(--border,#cbd5e1); color:var(--ink-500,#64748b); border-radius:8px; padding:7px; font-size:12.5px; cursor:pointer; display:flex; align-items:center; justify-content:center; gap:5px; margin-top:2px; }
    .servis-add-card:hover { background:#fff; color:var(--ink-900,#0f172a); }
    .servis-col-add { flex:0 0 230px; width:230px; }
    .servis-menu { position:absolute; top:100%; right:0; z-index:50; background:#fff; border:1px solid var(--border,#e2e8f0); border-radius:9px; box-shadow:var(--shadow-lg,0 10px 30px rgba(0,0,0,.15)); padding:6px; min-width:180px; display:flex; flex-direction:column; gap:2px; }
    .servis-menu button { text-align:left; background:transparent; border:none; padding:7px 9px; border-radius:6px; font-size:13px; cursor:pointer; color:var(--ink-900,#0f172a); }
    .servis-menu button:hover { background:var(--surface-2,#f1f4f9); }
    .servis-menu button.danger { color:var(--red-500,#d64545); }
    .servis-swatches { display:flex; flex-wrap:wrap; gap:5px; padding:6px 9px; }
    .servis-swatches span { width:18px; height:18px; border-radius:5px; cursor:pointer; border:1px solid rgba(0,0,0,.1); }
    .servis-swatches span:hover { transform:scale(1.15); }
    .servis-comment { display:flex; gap:8px; align-items:flex-start; font-size:13px; }
    .servis-comment-del { cursor:pointer; color:var(--ink-300,#cbd5e1); }
    .servis-comment-del:hover { color:var(--red-500,#d64545); }
    .btn.danger { color:var(--red-500,#d64545); }
  `}</style>;
}

Object.assign(window, { ServisBoard });
