// Devices.jsx — Provision and manage iPad device codes.
//
// Each row is a single 6-digit code that one physical iPad consumes. Lifecycle:
//   unused  — owner generated it, code printed on screen, no iPad has bound to it yet
//   bound   — an iPad has entered the code and is now using the app
//   revoked — owner ended that iPad's session; the iPad is locked back out on next load
//
// To re-pair a revoked iPad: regenerate the code (rotates the value, returns it to 'unused')
// or delete the row entirely.

// Map a Supabase row to the in-app device shape (camelCase fields).
const deviceRowToDevice = (r) => ({
  id: r.id,
  label: r.label,
  code: r.code,
  status: r.status,
  boundAt: r.bound_at,
  lastSeen: r.last_seen,
});

const Devices = () => {
  const [devices, setDevices] = useState([]);
  const [toast, setToast] = useState('');
  const [creating, setCreating] = useState(false);
  const [newName, setNewName] = useState('');
  const [highlight, setHighlight] = useState(null); // device id whose code we just generated/rotated

  // Initial fetch + Realtime subscription scoped to this restaurant.
  useEffect(() => {
    if (!window.supa) return;
    let cancelled = false;
    window.supa
      .from('devices')
      .select('*')
      .eq('restaurant_id', window.RESTAURANT_ID)
      .order('created_at', { ascending: true })
      .then(({ data, error }) => {
        if (cancelled || error || !data) return;
        setDevices(data.map(deviceRowToDevice));
      });
    const channel = window.supa
      .channel('portal-devices:' + window.RESTAURANT_ID)
      .on('postgres_changes', {
        event: '*',
        schema: 'public',
        table: 'devices',
        filter: 'restaurant_id=eq.' + window.RESTAURANT_ID,
      }, (payload) => {
        if (payload.eventType === 'INSERT') {
          const d = deviceRowToDevice(payload.new);
          setDevices(prev => prev.some(x => x.id === d.id) ? prev : [...prev, d]);
        } else if (payload.eventType === 'UPDATE') {
          const d = deviceRowToDevice(payload.new);
          setDevices(prev => prev.map(x => x.id === d.id ? d : x));
        } else if (payload.eventType === 'DELETE') {
          setDevices(prev => prev.filter(x => x.id !== payload.old.id));
        }
      })
      .subscribe();
    return () => { cancelled = true; window.supa.removeChannel(channel); };
  }, []);

  const showToast = (msg) => { setToast(msg); setTimeout(() => setToast(''), 2200); };

  const genCode = () => {
    let c;
    const used = new Set(devices.map(d => d.code));
    do { c = String(Math.floor(100000 + Math.random() * 900000)); } while (used.has(c));
    return c;
  };

  const create = async () => {
    if (!window.supa) return;
    const label = (newName || '').trim() || `iPad ${devices.length + 1}`;
    const code = genCode();
    setCreating(false);
    setNewName('');
    const { data, error } = await window.supa
      .from('devices')
      .insert({ restaurant_id: window.RESTAURANT_ID, label, code, status: 'unused' })
      .select()
      .single();
    if (error) { showToast('Create failed: ' + error.message); return; }
    setHighlight(data.id);
    setTimeout(() => setHighlight(null), 4000);
    showToast(`Code ${code} created. Enter it on the iPad.`);
  };

  const signOut = async (id) => {
    if (!confirm("End this iPad's session? It will be kicked back to the device-code prompt and won't unlock again until you regenerate its code.")) return;
    const { error } = await window.supa.from('devices').update({ status: 'revoked' }).eq('id', id);
    if (error) { showToast('Revoke failed: ' + error.message); return; }
    showToast('Session ended. iPad will be locked out within a few seconds.');
  };

  const regenerate = async (id) => {
    const code = genCode();
    const { error } = await window.supa
      .from('devices')
      .update({ code, status: 'unused', bound_at: null })
      .eq('id', id);
    if (error) { showToast('Regenerate failed: ' + error.message); return; }
    setHighlight(id);
    setTimeout(() => setHighlight(null), 4000);
    showToast(`New code ${code} ready. Enter it on the iPad.`);
  };

  const remove = async (id) => {
    const d = devices.find(x => x.id === id);
    if (!d) return;
    if (!confirm(`Delete "${d.label}" entirely? This cannot be undone.`)) return;
    const { error } = await window.supa.from('devices').delete().eq('id', id);
    if (error) { showToast('Delete failed: ' + error.message); return; }
    showToast('Device deleted.');
  };

  const renameDevice = async (id, label) => {
    const { error } = await window.supa.from('devices').update({ label }).eq('id', id);
    if (error) showToast('Rename failed: ' + error.message);
  };

  const counts = {
    bound:   devices.filter(d => d.status === 'bound').length,
    unused:  devices.filter(d => d.status === 'unused').length,
    revoked: devices.filter(d => d.status === 'revoked').length,
  };

  return (
    <div className="portal-page-wide" style={{ maxWidth: 1180 }}>
      <div className="portal-page-header">
        <div>
          <h1 className="portal-page-title">Devices</h1>
          <div className="portal-page-subtitle">
            {devices.length} {devices.length === 1 ? 'device' : 'devices'} · {counts.bound} active · {counts.unused} waiting · {counts.revoked} revoked
          </div>
        </div>
        <PBtn variant="primary" icon="plus" onClick={() => setCreating(true)}>Generate code</PBtn>
      </div>

      {/* Explainer card */}
      <div style={{
        marginBottom: 18,
        padding: '14px 16px',
        background: 'var(--bg-sunken)',
        borderRadius: 10,
        border: '1px solid var(--border-1)',
        display: 'flex', gap: 12, alignItems: 'flex-start',
      }}>
        <div style={{
          width: 28, height: 28, borderRadius: 8,
          background: '#FFFFFF', border: '1px solid var(--border-1)',
          display: 'flex', alignItems: 'center', justifyContent: 'center',
          flexShrink: 0,
        }}>
          <PIcon name="info" size={15} color="var(--fg-2)" />
        </div>
        <div style={{ fontSize: 13, lineHeight: 1.55, color: 'var(--fg-2)' }}>
          <div style={{ fontWeight: 600, color: 'var(--fg-1)', marginBottom: 2 }}>How device codes work</div>
          Generate a code, then enter it once on the iPad. After that the iPad runs without prompts — staff don't sign in. To retire an iPad (lost, stolen, sold) press <span style={{ fontWeight: 600 }}>End session</span>; the iPad is dead until you regenerate its code.
        </div>
      </div>

      {creating && (
        <div className="portal-card" style={{ marginBottom: 16, padding: 16 }}>
          <div style={{ fontSize: 14, fontWeight: 600, marginBottom: 10 }}>New device</div>
          <div style={{ display: 'flex', gap: 10, alignItems: 'center' }}>
            <input
              className="portal-input"
              autoFocus
              placeholder="Name (e.g. Front Counter iPad)"
              value={newName}
              onChange={e => setNewName(e.target.value)}
              onKeyDown={e => { if (e.key === 'Enter') create(); }}
              style={{ flex: 1, maxWidth: 360 }}
            />
            <PBtn variant="primary" onClick={create}>Generate code</PBtn>
            <PBtn onClick={() => { setCreating(false); setNewName(''); }}>Cancel</PBtn>
          </div>
        </div>
      )}

      <div className="portal-card">
        <table className="portal-table">
          <thead>
            <tr>
              <th>Device</th>
              <th style={{ width: 170 }}>Code</th>
              <th style={{ width: 130 }}>Status</th>
              <th style={{ width: 170 }}>Bound</th>
              <th style={{ width: 150 }}>Last seen</th>
              <th style={{ width: 220 }}></th>
            </tr>
          </thead>
          <tbody>
            {devices.map(d => (
              <DeviceRow
                key={d.id}
                device={d}
                highlight={highlight === d.id}
                onRename={(label) => renameDevice(d.id, label)}
                onSignOut={() => signOut(d.id)}
                onRegenerate={() => regenerate(d.id)}
                onDelete={() => remove(d.id)}
                onCopyCode={() => {
                  try { navigator.clipboard.writeText(d.code); } catch {}
                  showToast(`Code ${d.code} copied`);
                }}
              />
            ))}
            {devices.length === 0 && (
              <tr>
                <td colSpan={6} style={{ textAlign: 'center', padding: 36, color: 'var(--fg-3)', fontSize: 13 }}>
                  No devices yet. Press <span style={{ fontWeight: 600, color: 'var(--fg-2)' }}>Generate code</span> to add one.
                </td>
              </tr>
            )}
          </tbody>
        </table>
      </div>

      {toast && (
        <div style={{
          position: 'fixed', bottom: 24, left: '50%', transform: 'translateX(-50%)',
          background: 'var(--fg-1)', color: '#FFFFFF',
          padding: '10px 16px', borderRadius: 999,
          fontSize: 13, fontWeight: 500,
          boxShadow: '0 8px 20px rgba(0,0,0,0.18)',
          zIndex: 1000,
        }}>{toast}</div>
      )}
    </div>
  );
};

// ----- Single row --------------------------------------------------

const DeviceRow = ({ device, highlight, onRename, onSignOut, onRegenerate, onDelete, onCopyCode }) => {
  const d = device;
  const [editing, setEditing] = useState(false);
  const [draft, setDraft] = useState(d.label);
  useEffect(() => { setDraft(d.label); }, [d.label]);

  const commit = () => {
    const v = (draft || '').trim();
    if (v && v !== d.label) onRename(v);
    setEditing(false);
  };

  const statusPill = {
    bound:   { bg: '#DCFCE7', fg: '#166534', dot: '#16A34A', label: 'Active' },
    unused:  { bg: '#FEF3C7', fg: '#92400E', dot: '#D97706', label: 'Waiting' },
    revoked: { bg: '#FEE2E2', fg: '#991B1B', dot: '#DC2626', label: 'Revoked' },
  }[d.status] || { bg: 'var(--bg-sunken)', fg: 'var(--fg-2)', dot: 'var(--fg-3)', label: d.status };

  const fmtDateTime = (iso) => {
    if (!iso) return '—';
    const dt = new Date(iso);
    return dt.toLocaleDateString(undefined, { month: 'short', day: 'numeric' }) + ', ' +
           dt.toLocaleTimeString(undefined, { hour: 'numeric', minute: '2-digit' });
  };

  return (
    <tr style={{
      transition: 'background 240ms',
      background: highlight ? 'rgba(217,119,87,0.08)' : 'transparent',
    }}>
      <td>
        <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
          <div style={{
            width: 32, height: 32, borderRadius: 8,
            background: 'var(--bg-sunken)',
            display: 'flex', alignItems: 'center', justifyContent: 'center',
            color: 'var(--fg-2)',
          }}>
            <PIcon name="tablet" size={16} />
          </div>
          {editing ? (
            <input
              autoFocus
              className="portal-input"
              value={draft}
              onChange={e => setDraft(e.target.value)}
              onBlur={commit}
              onKeyDown={e => {
                if (e.key === 'Enter') commit();
                if (e.key === 'Escape') { setDraft(d.label); setEditing(false); }
              }}
              style={{ height: 30, maxWidth: 240 }}
            />
          ) : (
            <button onClick={() => setEditing(true)} style={{
              background: 'none', border: 'none', padding: 0, cursor: 'text',
              fontSize: 14, fontWeight: 500, color: 'var(--fg-1)', textAlign: 'left',
            }}>{d.label}</button>
          )}
        </div>
      </td>
      <td>
        <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
          <span style={{
            fontFamily: "ui-monospace, 'SF Mono', Menlo, monospace",
            fontSize: 14, letterSpacing: 2,
            color: d.status === 'revoked' ? 'var(--fg-3)' : 'var(--fg-1)',
            textDecoration: d.status === 'revoked' ? 'line-through' : 'none',
            fontWeight: 600,
          }}>{d.code}</span>
          {d.status !== 'revoked' && (
            <button onClick={onCopyCode} title="Copy code" style={{
              width: 24, height: 24, borderRadius: 6,
              background: 'transparent', border: 'none',
              display: 'flex', alignItems: 'center', justifyContent: 'center',
              color: 'var(--fg-3)', cursor: 'pointer',
            }}><PIcon name="copy" size={13} /></button>
          )}
        </div>
      </td>
      <td>
        <span style={{
          display: 'inline-flex', alignItems: 'center', gap: 6,
          padding: '3px 9px',
          background: statusPill.bg, color: statusPill.fg,
          borderRadius: 999, fontSize: 11.5, fontWeight: 600,
        }}>
          <span style={{ width: 6, height: 6, borderRadius: 999, background: statusPill.dot }} />
          {statusPill.label}
        </span>
      </td>
      <td style={{ fontSize: 13, color: 'var(--fg-2)' }}>{fmtDateTime(d.boundAt)}</td>
      <td style={{ fontSize: 13, color: 'var(--fg-2)' }}>{fmtDateTime(d.lastSeen)}</td>
      <td>
        <div style={{ display: 'flex', gap: 6, justifyContent: 'flex-end' }}>
          {d.status === 'bound' && (
            <PBtn size="sm" onClick={onSignOut}>End session</PBtn>
          )}
          {d.status === 'revoked' && (
            <PBtn size="sm" icon="refresh" onClick={onRegenerate}>Regenerate</PBtn>
          )}
          {d.status === 'unused' && (
            <PBtn size="sm" icon="refresh" onClick={onRegenerate}>New code</PBtn>
          )}
          <button onClick={onDelete} title="Delete" style={{
            width: 30, height: 30, borderRadius: 6,
            background: 'transparent', border: '1px solid var(--border-1)',
            display: 'flex', alignItems: 'center', justifyContent: 'center',
            color: 'var(--fg-3)', cursor: 'pointer',
          }}><PIcon name="trash" size={13} /></button>
        </div>
      </td>
    </tr>
  );
};

window.Devices = Devices;
