/* POS — seatiq.ooniq.app/pos
   Touch-first point-of-sale: layout your floor plan from scratch, tap a
   table to open its bill, add items by category, see the running total.

   Builds on the same Firebase tenant as the dashboard: shares the
   tables collection so booking and POS see the same physical tables,
   and stores active bills under /tenants/{id}/orders/{tableId}.

   Login is the standard manager email/password (AuthGate). On top of
   that, an optional PIN identifies which staff member is taking the
   order — purely for audit, not security. PIN management lives under
   Settings on the dashboard. */

const { useState: posS, useEffect: posE, useMemo: posM, useRef: posR } = React;

function PosApp() {
  const fb = window.fb;
  const auth = window.useAuth();
  const tenantId = auth?.tenantId;
  const [view, setView] = posS('floor'); // 'floor' | 'editor' | 'order'
  const [activeTable, setActiveTable] = posS(null);
  const [staffMember, setStaffMember] = posS(() => {
    try { return JSON.parse(localStorage.getItem('seatiq.pos.staff') || 'null'); } catch (e) { return null; }
  });

  posE(() => {
    document.documentElement.dataset.theme = 'light';
  }, []);

  posE(() => {
    if (staffMember) {
      localStorage.setItem('seatiq.pos.staff', JSON.stringify(staffMember));
    } else {
      localStorage.removeItem('seatiq.pos.staff');
    }
  }, [staffMember]);

  // If no staff member is logged in, show the PIN screen first.
  if (!staffMember) {
    return <PosStaffLogin onLogin={setStaffMember}/>;
  }

  return (
    <div className="pos-shell">
      <PosTopBar
        staffMember={staffMember}
        onLogoutStaff={() => setStaffMember(null)}
        onSignOut={auth?.signOut}
        view={view}
        onView={setView}
        tenantName={auth?.tenantDoc?.name}/>

      <div className="pos-main">
        {view === 'floor' && (
          <PosFloor onTapTable={(t) => { setActiveTable(t); setView('order'); }}/>
        )}
        {view === 'editor' && <PosLayoutEditor onDone={() => setView('floor')}/>}
        {view === 'order' && activeTable && (
          <PosOrder table={activeTable} staffMember={staffMember}
            onClose={() => { setActiveTable(null); setView('floor'); }}/>
        )}
      </div>
    </div>
  );
}

// ============================================================
// STAFF LOGIN
// ============================================================
function PosStaffLogin({ onLogin }) {
  const fb = window.fb;
  const auth = window.useAuth();
  const tenantId = auth?.tenantId;
  const [staff, setStaff] = posS([]);
  const [pin, setPin] = posS('');
  const [error, setError] = posS('');
  const [loading, setLoading] = posS(true);

  posE(() => {
    if (!tenantId) return;
    const unsub = fb.onSnapshot(
      fb.collection(fb.db, 'tenants', tenantId, 'staff'),
      (snap) => {
        const out = [];
        snap.forEach(d => out.push({ id: d.id, ...d.data() }));
        setStaff(out.sort((a, b) => (a.name || '').localeCompare(b.name || '')));
        setLoading(false);
      },
      () => setLoading(false)
    );
    return () => unsub();
  }, [tenantId]);

  const slug = auth?.tenantDoc?.slug || 'restaurant';
  // Username = restaurant slug + underscore + staff slug. Compare
  // case-insensitively, ignore extra whitespace.
  const usernameSlug = (s) => `${slug}_${(s.username || s.name || '').toLowerCase().trim().replace(/\s+/g, '')}`;

  const tryLogin = () => {
    setError('');
    const wantUser = username.trim().toLowerCase();
    if (!wantUser) { setError('Indtast brugernavn'); return; }
    if (pin.length !== 4) { setError('PIN skal være 4 cifre'); return; }
    const match = staff.find(s => usernameSlug(s) === wantUser && s.pin === pin);
    if (match) {
      onLogin({ id: match.id, name: match.name, role: match.role });
      setPin('');
      setUsername('');
    } else {
      setError('Forkert brugernavn eller PIN');
      setTimeout(() => setError(''), 1800);
      setPin('');
    }
  };

  const addDigit = (d) => {
    if (pin.length >= 4) return;
    setPin(pin + d);
  };

  const [username, setUsername] = posS('');

  // Allow physical keyboards too. Ignore keystrokes that are happening
  // inside the username input or other form fields.
  posE(() => {
    const onKey = (e) => {
      const target = e.target;
      const inField = target && (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA' || target.isContentEditable);
      if (inField) return;
      if (e.metaKey || e.ctrlKey || e.altKey) return;
      if (/^[0-9]$/.test(e.key)) {
        e.preventDefault();
        if (pin.length < 4) setPin(prev => (prev.length < 4 ? prev + e.key : prev));
      } else if (e.key === 'Backspace') {
        e.preventDefault();
        setPin(prev => prev.slice(0, -1));
      } else if (e.key === 'Escape') {
        e.preventDefault();
        setPin('');
      } else if (e.key === 'Enter') {
        e.preventDefault();
        // tryLogin reads current pin from state via closure — it's
        // recomputed each render but we use a ref-style read here.
        if (username.trim() && pin.length === 4) tryLogin();
      }
    };
    window.addEventListener('keydown', onKey);
    return () => window.removeEventListener('keydown', onKey);
  }, [pin, username, staff]);

  return (
    <div className="pos-login">
      <div className="pos-login-card">
        <div className="pos-login-brand">SEATIQ POS<span style={{color: 'var(--accent)'}}>.</span></div>
        <div className="pos-login-tenant">{auth?.tenantDoc?.name || 'Restaurant'}</div>

        {loading ? (
          <div className="pos-login-loading">Indlæser personale…</div>
        ) : staff.length === 0 ? (
          <div className="pos-login-empty">
            <h3>Ingen POS-brugere endnu</h3>
            <p>Opret medarbejdere under Indstillinger → POS-brugere på dashboardet, så de kan logge ind her med deres PIN.</p>
            <div style={{display: 'flex', gap: 8, justifyContent: 'center', marginTop: 14}}>
              <a href="/" className="btn btn-soft">← Til dashboard</a>
              <button className="btn btn-soft" onClick={() => window.fb.signOut(window.fb.auth)}>Frakobl enhed</button>
            </div>
          </div>
        ) : (
          <>
            <div className="pos-login-username">
              <label>Brugernavn</label>
              <div className="pos-login-username-row">
                <span className="pos-login-prefix">{slug}_</span>
                <input
                  type="text"
                  autoComplete="off"
                  autoCapitalize="none"
                  spellCheck={false}
                  value={username.replace(new RegExp(`^${slug}_`, 'i'), '')}
                  onChange={e => setUsername(`${slug}_${e.target.value}`)}
                  onKeyDown={e => { if (e.key === 'Enter') tryLogin(); }}
                  placeholder="brugernavn"/>
              </div>
            </div>

            <div className="pos-login-prompt">PIN-kode <span style={{opacity: 0.5, fontSize: 11, marginLeft: 4}}>· tryk på tasterne eller brug tastaturet</span></div>
            <div className={`pos-pin-dots ${error ? 'error' : ''}`}>
              {[0,1,2,3].map(i => <span key={i} className={pin.length > i ? 'filled' : ''}/>)}
            </div>
            {error && <div className="pos-pin-error">{error}</div>}
            <div className="pos-keypad">
              {[1,2,3,4,5,6,7,8,9].map(n => (
                <button key={n} className="pos-key" onClick={() => addDigit(String(n))}>{n}</button>
              ))}
              <button className="pos-key ghost" onClick={() => setPin('')}>C</button>
              <button className="pos-key" onClick={() => addDigit('0')}>0</button>
              <button className="pos-key ghost" onClick={() => setPin(pin.slice(0, -1))}>⌫</button>
            </div>
            <button className="btn pos-pairing-cta" style={{width: '100%', justifyContent: 'center', marginBottom: 14}}
              onClick={tryLogin} disabled={pin.length !== 4 || !username.trim()}>
              Log ind
            </button>
            <div className="pos-login-hint">
              Brugernavn er <strong>{slug}_dit-navn</strong>. Spørg en manager hvis du ikke har et.
            </div>
            <div style={{marginTop: 14, paddingTop: 14, borderTop: '1px solid var(--pos-line)'}}>
              <button className="btn btn-soft" style={{width: '100%', justifyContent: 'center', fontSize: 11}}
                onClick={() => {
                  if (confirm('Frakobl denne enhed fra restauranten? En manager skal logge ind igen næste gang POS bruges.')) {
                    window.fb.signOut(window.fb.auth);
                  }
                }}>
                Frakobl enhed
              </button>
            </div>
          </>
        )}
      </div>

    </div>
  );
}

// ============================================================
// TOP BAR
// ============================================================
function PosTopBar({ staffMember, onLogoutStaff, onSignOut, view, onView, tenantName }) {
  return (
    <div className="pos-topbar">
      <div className="pos-topbar-left">
        <div className="pos-brandmark">SEATIQ POS<span style={{color: 'var(--accent)'}}>.</span></div>
        <span className="pos-tenant-name">{tenantName}</span>
      </div>
      <div className="pos-topbar-tabs">
        <button className={`pos-tab ${view === 'floor' ? 'active' : ''}`} onClick={() => onView('floor')}>
          <Icon name="grid" size={16}/> Bordplan
        </button>
        <button className={`pos-tab ${view === 'editor' ? 'active' : ''}`} onClick={() => onView('editor')}>
          <Icon name="edit" size={16}/> Rediger layout
        </button>
      </div>
      <div className="pos-topbar-right">
        <div className="pos-staff-badge" onClick={onLogoutStaff} title="Skift bruger">
          <span className="pos-staff-initials">{(staffMember.name || '?').slice(0, 2).toUpperCase()}</span>
          <span className="pos-staff-name">{staffMember.name}</span>
        </div>
      </div>
    </div>
  );
}

// ============================================================
// FLOOR — read-only, tap a table to open its bill
// ============================================================
function PosFloor({ onTapTable }) {
  const fb = window.fb;
  const auth = window.useAuth();
  const tenantId = auth?.tenantId;
  const [tables, setTables] = posS([]);
  const [orders, setOrders] = posS({}); // tableId -> order doc
  const [areaFilter, setAreaFilter] = posS(null);
  const [rooms, setRooms] = posS([]);

  posE(() => {
    if (!tenantId) return;
    const u1 = fb.onSnapshot(
      fb.collection(fb.db, 'tenants', tenantId, 'tables'),
      (snap) => { const out = []; snap.forEach(d => out.push({ id: d.id, ...d.data() })); setTables(out); },
      () => {}
    );
    const u2 = fb.onSnapshot(
      fb.collection(fb.db, 'tenants', tenantId, 'rooms'),
      (snap) => { const out = []; snap.forEach(d => out.push({ id: d.id, ...d.data() })); setRooms(out); },
      () => {}
    );
    const u3 = fb.onSnapshot(
      fb.query(
        fb.collection(fb.db, 'tenants', tenantId, 'orders'),
        fb.where('status', '==', 'open'),
      ),
      (snap) => {
        const m = {};
        snap.forEach(d => { const data = d.data(); m[data.tableId] = { id: d.id, ...data }; });
        setOrders(m);
      },
      () => {}
    );
    return () => { u1(); u2(); u3(); };
  }, [tenantId]);

  const canvasW = auth?.tenantDoc?.canvasW || 1080;
  const canvasH = auth?.tenantDoc?.canvasH || 720;
  const visibleTables = areaFilter ? tables.filter(t => t.room === areaFilter) : tables;

  return (
    <>
      <div className="pos-areas">
        <button className={`pos-area-chip ${!areaFilter ? 'active' : ''}`} onClick={() => setAreaFilter(null)}>
          Alle <span className="pos-area-count">{tables.length}</span>
        </button>
        {rooms.map(r => {
          const count = tables.filter(t => t.room === r.id).length;
          if (count === 0) return null;
          return (
            <button key={r.id}
              className={`pos-area-chip ${areaFilter === r.id ? 'active' : ''}`}
              onClick={() => setAreaFilter(r.id)}>
              {r.label || r.id} <span className="pos-area-count">{count}</span>
            </button>
          );
        })}
      </div>

      <div className="pos-floor-wrap">
        {tables.length === 0 ? (
          <div className="pos-empty">
            <Icon name="grid" size={48} stroke={1.5}/>
            <h2>Ingen borde endnu</h2>
            <p>Skift til <strong>Rediger layout</strong> for at placere borde på din plantegning.</p>
          </div>
        ) : (
          <div className="pos-floor" style={{width: canvasW, height: canvasH}}>
            {visibleTables.map(t => {
              const order = orders[t.id];
              const state = order ? 'occupied' : 'free';
              const total = order?.items?.reduce((a, i) => a + (i.price || 0) * (i.qty || 1), 0) || 0;
              return (
                <button key={t.id}
                  className={`pos-table ${t.shape || 'rect'} ${state}`}
                  style={{
                    left: t.x, top: t.y,
                    width: t.w || 90, height: t.h || 90,
                  }}
                  onClick={() => onTapTable(t)}>
                  <div className="pos-table-name">{t.name?.replace('Bord ', '') || '?'}</div>
                  {order ? (
                    <div className="pos-table-total">{total.toLocaleString('da-DK')} kr</div>
                  ) : (
                    <div className="pos-table-cap">{t.cap?.[0]}–{t.cap?.[1]}</div>
                  )}
                </button>
              );
            })}
          </div>
        )}
      </div>
    </>
  );
}

// ============================================================
// LAYOUT EDITOR — clean rewrite, drag-and-drop only
// ============================================================
function PosLayoutEditor({ onDone }) {
  const fb = window.fb;
  const auth = window.useAuth();
  const tenantId = auth?.tenantId;
  const [tables, setTables] = posS([]);
  const [rooms, setRooms] = posS([]);
  const [selId, setSelId] = posS(null);
  const [drag, setDrag] = posS(null);
  const canvasRef = posR(null);

  posE(() => {
    if (!tenantId) return;
    const u1 = fb.onSnapshot(
      fb.collection(fb.db, 'tenants', tenantId, 'tables'),
      (snap) => { const out = []; snap.forEach(d => out.push({ id: d.id, ...d.data() })); setTables(out); },
      () => {}
    );
    const u2 = fb.onSnapshot(
      fb.collection(fb.db, 'tenants', tenantId, 'rooms'),
      (snap) => { const out = []; snap.forEach(d => out.push({ id: d.id, ...d.data() })); setRooms(out); },
      () => {}
    );
    return () => { u1(); u2(); };
  }, [tenantId]);

  const canvasW = auth?.tenantDoc?.canvasW || 1080;
  const canvasH = auth?.tenantDoc?.canvasH || 720;
  const snap = (n) => Math.round(n / 10) * 10;

  // Pointer drag — works for mouse and touch.
  const pt = (e) => {
    if (e.touches?.length) return { x: e.touches[0].clientX, y: e.touches[0].clientY };
    if (e.changedTouches?.length) return { x: e.changedTouches[0].clientX, y: e.changedTouches[0].clientY };
    return { x: e.clientX, y: e.clientY };
  };

  const startDrag = (e, table) => {
    if (e.cancelable) e.preventDefault();
    e.stopPropagation();
    const { x, y } = pt(e);
    setSelId(table.id);
    setDrag({ id: table.id, startX: x, startY: y, origX: table.x || 0, origY: table.y || 0 });
  };

  posE(() => {
    if (!drag) return;
    const onMove = (e) => {
      const { x, y } = pt(e);
      const dx = x - drag.startX;
      const dy = y - drag.startY;
      setTables(prev => prev.map(t => t.id === drag.id ? { ...t, x: Math.max(0, snap(drag.origX + dx)), y: Math.max(0, snap(drag.origY + dy)) } : t));
      if (e.touches && e.cancelable) e.preventDefault();
    };
    const onUp = async () => {
      const final = tables.find(t => t.id === drag.id);
      if (final) {
        await fb.updateDoc(
          fb.doc(fb.db, 'tenants', tenantId, 'tables', drag.id),
          { x: final.x, y: final.y }
        );
      }
      setDrag(null);
    };
    window.addEventListener('mousemove', onMove);
    window.addEventListener('mouseup', onUp);
    window.addEventListener('touchmove', onMove, { passive: false });
    window.addEventListener('touchend', onUp);
    return () => {
      window.removeEventListener('mousemove', onMove);
      window.removeEventListener('mouseup', onUp);
      window.removeEventListener('touchmove', onMove);
      window.removeEventListener('touchend', onUp);
    };
  }, [drag, tenantId, tables]);

  const addTable = async (shape) => {
    const lastNum = Math.max(0, ...tables
      .filter(t => /^Bord \d+$/.test(t.name || ''))
      .map(t => parseInt((t.name || '').replace('Bord ', ''), 10) || 0));
    const id = 'nt' + Math.random().toString(36).slice(2, 7);
    const newT = {
      name: `Bord ${lastNum + 1}`,
      cap: [2, 4],
      room: rooms[0]?.id || null,
      shape,
      x: Math.round(canvasW / 2 - 50),
      y: Math.round(canvasH / 2 - 50),
      w: shape === 'round' ? 100 : 90,
      h: shape === 'round' ? 100 : 90,
    };
    await fb.setDoc(fb.doc(fb.db, 'tenants', tenantId, 'tables', id), newT);
    setSelId(id);
  };

  const updateTable = async (id, patch) => {
    await fb.updateDoc(fb.doc(fb.db, 'tenants', tenantId, 'tables', id), patch);
  };

  const deleteTable = async (id) => {
    if (!window.confirm('Slet dette bord?')) return;
    await fb.deleteDoc(fb.doc(fb.db, 'tenants', tenantId, 'tables', id));
    setSelId(null);
  };

  const addRoom = async () => {
    const name = window.prompt('Navn på nyt område:');
    if (!name?.trim()) return;
    const id = 'rm' + Math.random().toString(36).slice(2, 6);
    await fb.setDoc(fb.doc(fb.db, 'tenants', tenantId, 'rooms', id), {
      label: name.trim(),
      labelX: 30, labelY: 80,
    });
  };

  const sel = tables.find(t => t.id === selId);

  return (
    <div className="pos-editor">
      <div className="pos-editor-toolbar">
        <button className="btn btn-soft" onClick={onDone}>
          <Icon name="chev-left" size={14}/> Færdig
        </button>
        <button className="btn btn-primary" onClick={() => addTable('rect')}>
          <Icon name="plus" size={14}/> Firkantet bord
        </button>
        <button className="btn btn-soft" onClick={() => addTable('round')}>
          <Icon name="plus" size={14}/> Rundt bord
        </button>
        <button className="btn btn-soft" onClick={addRoom}>
          <Icon name="plus" size={14}/> Nyt område
        </button>
        <div style={{flex: 1}}/>
        <span className="floor-stat">{tables.length} borde</span>
      </div>

      <div className="pos-editor-body">
        <div className="pos-editor-canvas-wrap">
          <div className="pos-editor-canvas" ref={canvasRef}
            style={{ width: canvasW, height: canvasH }}
            onClick={() => setSelId(null)}>
            {tables.map(t => {
              const isSel = selId === t.id;
              return (
                <div key={t.id}
                  className={`pos-table editor ${t.shape || 'rect'} ${isSel ? 'selected' : ''}`}
                  style={{
                    left: t.x || 0, top: t.y || 0,
                    width: t.w || 90, height: t.h || 90,
                    cursor: drag?.id === t.id ? 'grabbing' : 'grab',
                  }}
                  onMouseDown={(e) => startDrag(e, t)}
                  onTouchStart={(e) => startDrag(e, t)}
                  onClick={(e) => { e.stopPropagation(); setSelId(t.id); }}>
                  <div className="pos-table-name">{t.name?.replace('Bord ', '') || '?'}</div>
                  <div className="pos-table-cap">{t.cap?.[0]}–{t.cap?.[1]}</div>
                </div>
              );
            })}
            {tables.length === 0 && (
              <div className="pos-editor-hint">
                <Icon name="plus" size={40} stroke={1.5}/>
                <h3>Tom plantegning</h3>
                <p>Tryk „Firkantet bord“ eller „Rundt bord“ for at tilføje dit første bord.</p>
              </div>
            )}
          </div>
        </div>

        {sel && (
          <aside className="pos-editor-side">
            <div style={{fontSize: 11, color: 'var(--muted)', textTransform: 'uppercase', letterSpacing: '0.1em', fontWeight: 700, marginBottom: 12}}>
              Bordets egenskaber
            </div>
            <div className="field">
              <label>Navn</label>
              <input value={sel.name || ''} onChange={e => updateTable(sel.id, { name: e.target.value })}/>
            </div>
            <div className="field">
              <label>Område</label>
              <select value={sel.room || ''} onChange={e => updateTable(sel.id, { room: e.target.value || null })}>
                <option value="">Intet område</option>
                {rooms.map(r => <option key={r.id} value={r.id}>{r.label || r.id}</option>)}
              </select>
            </div>
            <div className="field">
              <label>Kapacitet (min – max)</label>
              <div style={{display: 'flex', gap: 8}}>
                <input type="number" value={sel.cap?.[0] || 1} min={1}
                  onChange={e => updateTable(sel.id, { cap: [Math.max(1, +e.target.value || 1), sel.cap?.[1] || 4] })}/>
                <input type="number" value={sel.cap?.[1] || 4} min={1}
                  onChange={e => updateTable(sel.id, { cap: [sel.cap?.[0] || 1, Math.max(sel.cap?.[0] || 1, +e.target.value || 4)] })}/>
              </div>
            </div>
            <div className="field">
              <label>Størrelse (px)</label>
              <div style={{display: 'flex', gap: 8}}>
                <input type="number" value={sel.w || 90} min={40} step={10}
                  onChange={e => updateTable(sel.id, { w: Math.max(40, +e.target.value || 40) })}/>
                <input type="number" value={sel.h || 90} min={40} step={10}
                  onChange={e => updateTable(sel.id, { h: Math.max(40, +e.target.value || 40) })}/>
              </div>
            </div>
            <button className="btn btn-ghost"
              style={{color: 'var(--danger)', borderColor: 'rgba(224,83,58,0.3)', width: '100%', justifyContent: 'center', marginTop: 12}}
              onClick={() => deleteTable(sel.id)}>
              <Icon name="x" size={14}/> Slet bord
            </button>
          </aside>
        )}
      </div>
    </div>
  );
}

// ============================================================
// ORDER — tap on table opens this, add items by category
// ============================================================
function PosOrder({ table, staffMember, onClose }) {
  const fb = window.fb;
  const auth = window.useAuth();
  const tenantId = auth?.tenantId;
  const [items, setItems] = posS([]);
  const [order, setOrder] = posS(null);
  const [activeCat, setActiveCat] = posS(null);

  // Load menu items
  posE(() => {
    if (!tenantId) return;
    const unsub = fb.onSnapshot(
      fb.collection(fb.db, 'tenants', tenantId, 'items'),
      (snap) => {
        const out = [];
        snap.forEach(d => out.push({ id: d.id, ...d.data() }));
        setItems(out);
      },
      () => {}
    );
    return () => unsub();
  }, [tenantId]);

  // Load (or create) open order for this table
  posE(() => {
    if (!tenantId || !table) return;
    const orderId = table.id; // one open order per table at a time
    const ref = fb.doc(fb.db, 'tenants', tenantId, 'orders', orderId);
    const unsub = fb.onSnapshot(ref, (snap) => {
      if (snap.exists()) {
        setOrder({ id: snap.id, ...snap.data() });
      } else {
        setOrder(null);
      }
    }, () => {});
    return () => unsub();
  }, [tenantId, table?.id]);

  const categories = posM(() => {
    const present = new Set();
    items.forEach(i => present.add(i.category || 'Ukategoriseret'));
    // Respect the manual ordering set on the dashboard
    // (tenant.itemCategoryOrder) so POS and dashboard stay in sync.
    const manualOrder = auth?.tenantDoc?.itemCategoryOrder || [];
    const ordered = [];
    manualOrder.forEach(c => { if (present.has(c)) ordered.push(c); });
    Array.from(present)
      .filter(c => !ordered.includes(c) && c !== 'Ukategoriseret')
      .sort((a, b) => a.localeCompare(b))
      .forEach(c => ordered.push(c));
    if (present.has('Ukategoriseret') && !ordered.includes('Ukategoriseret')) {
      ordered.push('Ukategoriseret');
    }
    return ordered;
  }, [items, auth?.tenantDoc?.itemCategoryOrder]);

  posE(() => {
    if (!activeCat && categories.length > 0) setActiveCat(categories[0]);
  }, [categories]);

  // Items inside a category keep oldest-first ordering so POS matches
  // the dashboard view exactly. Items without a createdAt (legacy data)
  // sort AFTER the timestamped ones — same tie-breaker as MenuPage so
  // the two screens never disagree on order.
  const itemsInCat = items
    .filter(i => (i.category || 'Ukategoriseret') === activeCat)
    .sort((a, b) => {
      const aT = a.createdAt || '';
      const bT = b.createdAt || '';
      if (aT && bT) return aT.localeCompare(bT);
      if (aT) return -1;
      if (bT) return 1;
      return (a.name || '').localeCompare(b.name || '');
    });

  const addItem = async (it) => {
    const orderId = table.id;
    const ref = fb.doc(fb.db, 'tenants', tenantId, 'orders', orderId);
    const existing = order?.items || [];
    const idx = existing.findIndex(x => x.itemId === it.id);
    let newItems;
    if (idx >= 0) {
      newItems = existing.map((x, i) => i === idx ? { ...x, qty: (x.qty || 1) + 1 } : x);
    } else {
      newItems = [...existing, {
        itemId: it.id,
        name: it.name,
        price: it.price || 0,
        qty: 1,
        category: it.category || null,
        addedBy: staffMember.name,
        addedAt: new Date().toISOString(),
      }];
    }
    await fb.setDoc(ref, {
      tableId: table.id,
      tableName: table.name,
      status: 'open',
      items: newItems,
      openedAt: order?.openedAt || new Date().toISOString(),
      openedBy: order?.openedBy || staffMember.name,
      lastUpdatedAt: new Date().toISOString(),
    });
    // Increment popularity counter on the menu item (non-blocking).
    fb.updateDoc(fb.doc(fb.db, 'tenants', tenantId, 'items', it.id), {
      orderCount: (it.orderCount || 0) + 1,
    }).catch(() => {});
  };

  const changeQty = async (idx, delta) => {
    const existing = order?.items || [];
    let newItems = existing.map((x, i) => i === idx ? { ...x, qty: (x.qty || 1) + delta } : x);
    newItems = newItems.filter(x => (x.qty || 0) > 0);
    const ref = fb.doc(fb.db, 'tenants', tenantId, 'orders', table.id);
    if (newItems.length === 0) {
      await fb.deleteDoc(ref);
    } else {
      await fb.setDoc(ref, { ...order, items: newItems, lastUpdatedAt: new Date().toISOString() }, { merge: true });
    }
  };

  const closeBill = async (paymentMethod) => {
    if (!order?.items?.length) return;
    if (!window.confirm(`Luk regning på ${total.toLocaleString('da-DK')} kr (${paymentMethod})?`)) return;
    const ref = fb.doc(fb.db, 'tenants', tenantId, 'orders', table.id);
    await fb.setDoc(ref, {
      ...order,
      status: 'closed',
      paymentMethod,
      closedAt: new Date().toISOString(),
      closedBy: staffMember.name,
    }, { merge: true });
    // Save to history under a unique id so the table can be re-opened.
    const histId = 'h' + Date.now() + Math.random().toString(36).slice(2, 5);
    await fb.setDoc(
      fb.doc(fb.db, 'tenants', tenantId, 'orderHistory', histId),
      { ...order, status: 'closed', paymentMethod, closedAt: new Date().toISOString(), closedBy: staffMember.name }
    );
    await fb.deleteDoc(ref);
    onClose();
  };

  const subtotal = (order?.items || []).reduce((a, x) => a + (x.price || 0) * (x.qty || 1), 0);
  const discountTotal = (order?.discounts || []).reduce((a, d) => a + (d.amount || 0), 0);
  const total = Math.max(0, subtotal - discountTotal);

  // Manager-gate for the ✕ "remove discount" button. Mirrors the CF check
  // in voidGiftRedemption — only managers/admins/listed managerEmails can
  // void a redemption. v1 ships with the remove button so a waiter who
  // applies a card to the wrong table can be corrected by a manager on
  // shift, instead of having to wait for back-office intervention.
  const userDoc = auth?.userDoc;
  const tenantDoc = auth?.tenantDoc;
  const canManagerVoid = !!(
    userDoc && (
      userDoc.role === 'admin'
      || userDoc.role === 'manager'
      || (Array.isArray(tenantDoc?.managerEmails)
          && userDoc.email
          && tenantDoc.managerEmails.includes(userDoc.email))
    )
  );

  const removeDiscount = async (d) => {
    if (!d?.redemptionId || !d?.code) return;
    if (!window.confirm(`Fjern gavekort ${d.code}? Beløbet sættes tilbage på kortet.`)) return;
    try {
      const voidFn = fb.httpsCallable(fb.functions, 'voidGiftRedemption');
      await voidFn({ tenantId, code: d.code, redemptionId: d.redemptionId });
    } catch (e) {
      alert(e?.message || 'Kunne ikke fjerne gavekortet.');
    }
  };

  return (
    <div className="pos-order">
      <div className="pos-order-left">
        <header className="pos-order-header">
          <button className="btn btn-soft" onClick={onClose}>
            <Icon name="chev-left" size={14}/> Bordplan
          </button>
          <div>
            <div className="pos-order-table-name">{table.name}</div>
            <div className="pos-order-meta">
              {order ? `Åbnet af ${order.openedBy}` : 'Ny regning'}
            </div>
          </div>
        </header>

        {items.length === 0 ? (
          <div className="pos-empty" style={{padding: 60}}>
            <Icon name="menu-book" size={40} stroke={1.5}/>
            <h3>Ingen retter på menuen</h3>
            <p>Tilføj retter under Menu → Items på dashboardet, så kan personalet vælge dem her.</p>
          </div>
        ) : (
          <>
            <div className="pos-cat-tabs">
              {categories.map(c => (
                <button key={c}
                  className={`pos-cat-tab ${activeCat === c ? 'active' : ''}`}
                  onClick={() => setActiveCat(c)}>{c}</button>
              ))}
            </div>
            <div className="pos-items-grid">
              {itemsInCat.map(it => (
                <button key={it.id} className="pos-item-card" onClick={() => addItem(it)}>
                  <div className="pos-item-name">{it.name}</div>
                  <div className="pos-item-price">{it.price || 0} kr</div>
                </button>
              ))}
              {itemsInCat.length === 0 && (
                <div style={{gridColumn: '1 / -1', textAlign: 'center', color: 'var(--muted)', padding: 30}}>
                  Ingen retter i kategorien „{activeCat}“.
                </div>
              )}
            </div>
          </>
        )}
      </div>

      <aside className="pos-bill">
        <header className="pos-bill-header">
          <div>
            <div className="pos-bill-title">Regning</div>
            <div className="pos-bill-sub">{table.name}</div>
          </div>
        </header>

        <div className="pos-bill-items">
          {(!order || !order.items?.length) && (
            <div style={{textAlign: 'center', color: 'var(--muted)', padding: 30, fontSize: 14}}>
              Ingen items endnu. Tryk på en ret for at tilføje den.
            </div>
          )}
          {order?.items?.map((x, i) => (
            <div key={i} className="pos-bill-row">
              <div style={{flex: 1, minWidth: 0}}>
                <div className="pos-bill-row-name">{x.name}</div>
                <div className="pos-bill-row-price">{x.price} kr</div>
              </div>
              <div className="pos-qty">
                <button onClick={() => changeQty(i, -1)}>−</button>
                <span>{x.qty}</span>
                <button onClick={() => changeQty(i, 1)}>+</button>
              </div>
              <div className="pos-bill-row-total">{(x.price * x.qty).toLocaleString('da-DK')} kr</div>
            </div>
          ))}
        </div>

        {(order?.discounts || []).length > 0 && (
          <div className="pos-bill-discounts">
            <div className="pos-bill-subtotal">
              <span>Subtotal</span>
              <strong>{subtotal.toLocaleString('da-DK')} kr</strong>
            </div>
            {(order.discounts || []).map((d, i) => (
              <div key={d.redemptionId || i} className="pos-bill-discount-row">
                <Icon name="bolt" size={14}/>
                <div style={{flex: 1, minWidth: 0}}>
                  <div className="pos-bill-discount-name">Gavekort {d.code}</div>
                  <div className="pos-bill-discount-meta">Anvendt af {d.appliedBy}</div>
                </div>
                <div className="pos-bill-discount-amount">−{(d.amount || 0).toLocaleString('da-DK')} kr</div>
                {canManagerVoid && (
                  <button className="pos-bill-discount-remove"
                    title="Fjern gavekort (manager)"
                    onClick={() => removeDiscount(d)}>×</button>
                )}
              </div>
            ))}
          </div>
        )}

        <footer className="pos-bill-footer">
          <div className="pos-bill-total">
            <span>I alt</span>
            <strong>{total.toLocaleString('da-DK')} kr</strong>
          </div>
          <div className="pos-bill-actions">
            {total === 0 && (order?.items?.length > 0) ? (
              <button className="btn btn-accent" style={{gridColumn: '1 / -1'}} onClick={() => closeBill('Gavekort')}>
                Luk gratis (Gavekort)
              </button>
            ) : (
              <>
                <button className="btn btn-soft" disabled={!order?.items?.length} onClick={() => closeBill('Kontant')}>
                  Kontant
                </button>
                <button className="btn btn-accent" disabled={!order?.items?.length} onClick={() => closeBill('Kort')}>
                  Kort
                </button>
              </>
            )}
          </div>
          <a className="btn btn-soft pos-bill-qr-link" href="/qr">
            <Icon name="bolt" size={14}/> Scan gavekort
          </a>
        </footer>
      </aside>
    </div>
  );
}

window.PosApp = PosApp;
window.PosStaffLogin = PosStaffLogin;
