// shared.jsx — shared UI atoms for Snap Operation.
// Avatar, Button, Chip, Icons, StaffPicker modal, NumPad.

const { useState, useEffect, useRef, useMemo } = React;

// ------------------------------------------------------------------
// Icons — minimal inline SVG set (outline stroke 1.75)
// ------------------------------------------------------------------
const Icon = ({ name, size = 22, color = 'currentColor', strokeWidth = 1.75, style }) => {
  const s = strokeWidth;
  const common = {
    width: size, height: size, viewBox: '0 0 24 24',
    fill: 'none', stroke: color, strokeWidth: s,
    strokeLinecap: 'round', strokeLinejoin: 'round',
    style,
  };
  const paths = {
    lock:     <><rect x="4.5" y="10.5" width="15" height="10" rx="2"/><path d="M8 10.5V7a4 4 0 018 0v3.5"/></>,
    check:    <path d="M4.5 12.5l5 5 10-11"/>,
    plus:     <><path d="M12 5v14"/><path d="M5 12h14"/></>,
    minus:    <path d="M5 12h14"/>,
    x:        <><path d="M6 6l12 12"/><path d="M18 6l-6 6-6 6"/></>,
    chevron:  <path d="M9 6l6 6-6 6"/>,
    chevronL: <path d="M15 6l-6 6 6 6"/>,
    chevronD: <path d="M6 9l6 6 6-6"/>,
    menu:     <><path d="M4 7h16"/><path d="M4 12h16"/><path d="M4 17h16"/></>,
    user:     <><circle cx="12" cy="8.5" r="3.5"/><path d="M5.5 20c0-3.5 3-6 6.5-6s6.5 2.5 6.5 6"/></>,
    users:    <><circle cx="9" cy="9" r="3"/><path d="M3 20c0-3 2.7-5.5 6-5.5s6 2.5 6 5.5"/><path d="M15 8a3 3 0 110-3"/><path d="M21 20c0-2.5-1.8-4.5-4-5"/></>,
    clipboard:<><rect x="6" y="5" width="12" height="16" rx="1.5"/><rect x="9" y="3" width="6" height="4" rx="1"/></>,
    broom:    <><path d="M14 3l7 7"/><path d="M12 5l7 7-5 5-7-7z"/><path d="M7 12l-4 8 8-4"/></>,
    box:      <><path d="M3 7l9-4 9 4v10l-9 4-9-4z"/><path d="M3 7l9 4 9-4"/><path d="M12 11v10"/></>,
    truck:    <><rect x="2.5" y="7" width="11" height="9" rx="1"/><path d="M13.5 10h4l3 3v3h-7z"/><circle cx="6.5" cy="18" r="1.75"/><circle cx="17.5" cy="18" r="1.75"/></>,
    clock:    <><circle cx="12" cy="12" r="8.5"/><path d="M12 7.5V12l3 2"/></>,
    search:   <><circle cx="11" cy="11" r="6.5"/><path d="M20 20l-4.5-4.5"/></>,
    filter:   <path d="M3 5h18l-7 9v6l-4-2v-4L3 5z"/>,
    pdf:      <><rect x="5" y="3" width="14" height="18" rx="1.5"/><path d="M9 13h6M9 16h4M9 10h6"/></>,
    download: <><path d="M12 4v12"/><path d="M7 11l5 5 5-5"/><path d="M5 20h14"/></>,
    eye:      <><path d="M2.5 12C5 7 8.5 5 12 5s7 2 9.5 7c-2.5 5-6 7-9.5 7s-7-2-9.5-7z"/><circle cx="12" cy="12" r="3"/></>,
    alert:    <><path d="M12 8v5"/><circle cx="12" cy="16" r="0.8" fill={color} stroke="none"/><circle cx="12" cy="12" r="9"/></>,
    flame:    <path d="M12 3c4 4 6 7 6 10.5a6 6 0 11-12 0c0-2 1-3 2.5-4 .5-.3.5.5 1 1 2-3 0-4.5 2.5-7.5z"/>,
    tag:      <><path d="M3 12l9-9h7v7l-9 9z"/><circle cx="15.5" cy="8.5" r="1.2" fill={color} stroke="none"/></>,
    coffee:   <><rect x="3" y="7" width="14" height="10" rx="2"/><path d="M17 9h2a2 2 0 010 4h-2"/><path d="M6 4c0 1-1 1-1 2s1 1 1 2M10 4c0 1-1 1-1 2s1 1 1 2"/></>,
    edit:     <><path d="M4 20h4l11-11-4-4L4 16v4z"/><path d="M14 5l4 4"/></>,
    settings: <><circle cx="12" cy="12" r="2.5"/><path d="M19.4 15a1.65 1.65 0 00.3 1.8l.1.1a2 2 0 11-2.8 2.8l-.1-.1a1.65 1.65 0 00-1.8-.3 1.65 1.65 0 00-1 1.5V21a2 2 0 01-4 0v-.1a1.65 1.65 0 00-1-1.5 1.65 1.65 0 00-1.8.3l-.1.1a2 2 0 11-2.8-2.8l.1-.1a1.65 1.65 0 00.3-1.8 1.65 1.65 0 00-1.5-1H3a2 2 0 010-4h.1a1.65 1.65 0 001.5-1 1.65 1.65 0 00-.3-1.8l-.1-.1a2 2 0 112.8-2.8l.1.1a1.65 1.65 0 001.8.3H9a1.65 1.65 0 001-1.5V3a2 2 0 014 0v.1a1.65 1.65 0 001 1.5 1.65 1.65 0 001.8-.3l.1-.1a2 2 0 112.8 2.8l-.1.1a1.65 1.65 0 00-.3 1.8V9a1.65 1.65 0 001.5 1H21a2 2 0 010 4h-.1a1.65 1.65 0 00-1.5 1z"/></>,
    wifi:     <><path d="M2 9c5-5 15-5 20 0"/><path d="M5 12c4-3 10-3 14 0"/><path d="M8.5 15c2-1.5 5-1.5 7 0"/><circle cx="12" cy="18.5" r="0.8" fill={color} stroke="none"/></>,
    battery:  <><rect x="2.5" y="8" width="17" height="8" rx="1.5"/><rect x="20" y="10" width="1.5" height="4"/><rect x="4" y="9.5" width="13" height="5" fill={color} stroke="none"/></>,
    backspace: <><path d="M20 5H9L3 12l6 7h11a1 1 0 001-1V6a1 1 0 00-1-1z"/><path d="M13 9l4 6M17 9l-4 6"/></>,
    camera:   <><path d="M3 7h4l2-2h6l2 2h4v12H3z"/><circle cx="12" cy="13" r="4"/></>,
    receipt:  <><path d="M5 3h14v18l-3-2-2 2-2-2-2 2-2-2-3 2z"/><path d="M8 8h8M8 12h8M8 16h5"/></>,
    dot:      <circle cx="12" cy="12" r="3" fill={color} stroke="none"/>,
    sparkle:  <><path d="M12 4v5M12 15v5M4 12h5M15 12h5M7 7l3 3M14 14l3 3M17 7l-3 3M10 14l-3 3"/></>,
    home:     <><path d="M3 11l9-7 9 7v9a1 1 0 01-1 1h-5v-6H10v6H4a1 1 0 01-1-1z"/></>,
    megaphone:<><path d="M4 10v4l10 4V6z"/><path d="M14 9a3 3 0 010 6"/><path d="M8 14v4a1 1 0 001 1h1.5a1 1 0 001-1v-2.2"/></>,
  };
  return <svg {...common}>{paths[name]}</svg>;
};

// ------------------------------------------------------------------
// Avatar
// ------------------------------------------------------------------
const Avatar = ({ staff, size = 36, style, ring = false }) => {
  if (!staff) return null;
  return (
    <div style={{
      width: size, height: size, borderRadius: 999,
      background: staff.color,
      color: '#fff',
      fontWeight: 500,
      fontSize: size * 0.38,
      display: 'flex', alignItems: 'center', justifyContent: 'center',
      flexShrink: 0,
      boxShadow: ring ? `0 0 0 3px #fff, 0 0 0 5px ${staff.color}` : 'none',
      fontFamily: 'var(--font-ui)',
      letterSpacing: '0.01em',
      ...style,
    }}>
      {staff.initials}
    </div>
  );
};

const AvatarStack = ({ ids, size = 28, max = 4 }) => {
  const staff = ids.map(id => window.SAMPLE_STAFF.find(s => s.id === id)).filter(Boolean);
  const shown = staff.slice(0, max);
  const extra = staff.length - max;
  return (
    <div style={{ display: 'flex' }}>
      {shown.map((s, i) => (
        <div key={s.id} style={{ marginLeft: i === 0 ? 0 : -size * 0.32 }}>
          <Avatar staff={s} size={size} style={{ boxShadow: '0 0 0 2px #fff' }} />
        </div>
      ))}
      {extra > 0 && (
        <div style={{
          width: size, height: size, borderRadius: 999,
          background: '#E5E5EA', color: '#6E6E73',
          fontWeight: 500, fontSize: size * 0.36,
          display: 'flex', alignItems: 'center', justifyContent: 'center',
          marginLeft: -size * 0.32,
          boxShadow: '0 0 0 2px #fff',
        }}>+{extra}</div>
      )}
    </div>
  );
};

// ------------------------------------------------------------------
// Button
// ------------------------------------------------------------------
const Btn = ({ variant = 'primary', size = 'md', icon, trailing, children, onClick, disabled, style, fullWidth }) => {
  const sizes = {
    sm: { height: 32, padding: '0 12px', fs: 13, iconSz: 16, gap: 6, radius: 8 },
    md: { height: 40, padding: '0 16px', fs: 14, iconSz: 16, gap: 8, radius: 10 },
    lg: { height: 48, padding: '0 20px', fs: 15, iconSz: 18, gap: 8, radius: 12 },
    xl: { height: 56, padding: '0 24px', fs: 16, iconSz: 20, gap: 10, radius: 14 },
  }[size];
  const variants = {
    primary:  { bg: 'var(--fg-1)', fg: '#FFFFFF', border: 'transparent', shadow: 'none' },
    secondary:{ bg: '#FFFFFF', fg: 'var(--fg-1)', border: 'var(--border-1)', shadow: 'none' },
    ghost:    { bg: 'transparent', fg: 'var(--fg-1)', border: 'transparent', shadow: 'none' },
    danger:   { bg: 'var(--danger)', fg: '#FFFFFF', border: 'transparent', shadow: 'none' },
    success:  { bg: 'var(--success)', fg: '#FFFFFF', border: 'transparent', shadow: 'none' },
    tint:     { bg: 'var(--bg-sunken)', fg: 'var(--fg-1)', border: 'transparent', shadow: 'none' },
  }[variant];
  return (
    <button onClick={onClick} disabled={disabled} style={{
      height: sizes.height, padding: sizes.padding,
      background: variants.bg, color: variants.fg,
      borderRadius: sizes.radius, border: `1px solid ${variants.border}`,
      fontSize: sizes.fs, fontWeight: 500, letterSpacing: '-0.005em',
      display: 'inline-flex', alignItems: 'center', justifyContent: 'center', gap: sizes.gap,
      boxShadow: variants.shadow, opacity: disabled ? 0.45 : 1,
      transition: 'transform 120ms var(--ease-snap), box-shadow 120ms',
      width: fullWidth ? '100%' : undefined,
      ...style,
    }}
    onMouseDown={e => !disabled && (e.currentTarget.style.transform = 'translateY(1px)')}
    onMouseUp={e => (e.currentTarget.style.transform = '')}
    onMouseLeave={e => (e.currentTarget.style.transform = '')}
    >
      {icon && <Icon name={icon} size={sizes.iconSz} />}
      {children}
      {trailing && <Icon name={trailing} size={sizes.iconSz} />}
    </button>
  );
};

// ------------------------------------------------------------------
// Chip / Pill
// ------------------------------------------------------------------
const CategoryChip = ({ category, small }) => {
  const map = {
    Sauce:     { bg: 'var(--cat-sauce)',     fg: 'var(--cat-sauce-fg)' },
    Vegetable: { bg: 'var(--cat-vegetable)', fg: 'var(--cat-vegetable-fg)' },
    Meat:      { bg: 'var(--cat-meat)',      fg: 'var(--cat-meat-fg)' },
    Other:     { bg: 'var(--cat-other)',     fg: 'var(--cat-other-fg)' },
    'Cleaning & Fixing': { bg: '#FCE7F3', fg: '#9D174D' },
    Dry:       { bg: 'var(--cat-dry)',       fg: 'var(--cat-dry-fg)' },
    Dairy:     { bg: 'var(--cat-dairy)',     fg: 'var(--cat-dairy-fg)' },
  };
  const c = map[category] || { bg: '#E2E8F0', fg: '#475569' };
  return (
    <span className="pill" style={{
      background: c.bg, color: c.fg,
      fontSize: small ? 11 : 12,
      padding: small ? '3px 8px' : '4px 10px',
    }}>{category}</span>
  );
};

const PriorityPill = ({ priority, small }) => {
  const isPrim = priority === 'primary';
  return (
    <span className="pill" style={{
      background: isPrim ? 'var(--fg-1)' : 'transparent',
      color: isPrim ? '#FFFFFF' : 'var(--fg-2)',
      border: isPrim ? 'none' : '1px solid var(--border-1)',
      fontSize: small ? 10 : 11,
      padding: small ? '2px 7px' : '3px 9px',
      letterSpacing: '0.04em', textTransform: 'uppercase', fontWeight: 500,
    }}>{isPrim ? 'Primary' : 'Secondary'}</span>
  );
};

// ------------------------------------------------------------------
// Card
// ------------------------------------------------------------------
const Card = ({ children, padding = 20, style }) => (
  <div style={{
    background: '#fff',
    borderRadius: 'var(--r-lg)',
    boxShadow: 'var(--shadow-1)',
    border: '1px solid var(--border-2)',
    padding,
    ...style,
  }}>{children}</div>
);

// ------------------------------------------------------------------
// Modal / sheet
// ------------------------------------------------------------------
const Modal = ({ open, onClose, children, width = 520, title }) => {
  if (!open) return null;
  return (
    <div
      onClick={onClose}
      style={{
        position: 'fixed', inset: 0,
        background: 'rgba(0, 0, 0, 0.35)',
        display: 'flex', alignItems: 'center', justifyContent: 'center',
        zIndex: 1000, padding: 24,
        animation: 'fade-in 200ms var(--ease-out)',
      }}>
      <div
        onClick={e => e.stopPropagation()}
        style={{
          width, maxWidth: '100%', maxHeight: '92vh',
          background: '#FFFFFF', borderRadius: 18,
          boxShadow: 'var(--shadow-pop)',
          overflow: 'hidden',
          display: 'flex', flexDirection: 'column',
          animation: 'pop-in 260ms var(--ease-snap)',
        }}>
        {title && (
          <div style={{
            display: 'flex', alignItems: 'center', justifyContent: 'space-between',
            padding: '18px 22px', borderBottom: '1px solid var(--border-2)',
          }}>
            <div style={{ fontSize: 17, fontWeight: 600, letterSpacing: '-0.015em', color: 'var(--fg-1)' }}>{title}</div>
            <button onClick={onClose} className="tap" style={{
              width: 32, height: 32, borderRadius: 999,
              background: 'var(--bg-sunken)',
              display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
            }}>
              <Icon name="x" size={18} />
            </button>
          </div>
        )}
        <div style={{ overflow: 'auto', flex: 1 }}>
          {children}
        </div>
      </div>
    </div>
  );
};

// ------------------------------------------------------------------
// StaffPicker — shown as a sheet of avatars
// ------------------------------------------------------------------
const StaffPicker = ({ open, onClose, onPick, title = 'Who are you?', subtitle }) => (
  <Modal open={open} onClose={onClose} width={560} title={title}>
    {subtitle && (
      <div style={{ padding: '12px 24px 0', color: 'var(--fg-2)', fontSize: 14 }}>
        {subtitle}
      </div>
    )}
    <div style={{
      padding: 24,
      display: 'grid',
      gridTemplateColumns: 'repeat(3, 1fr)',
      gap: 12,
    }}>
      {window.SAMPLE_STAFF.map(s => (
        <button key={s.id} onClick={() => onPick(s)} style={{
          display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 10,
          padding: '16px 12px',
          background: 'var(--bg-sunken)', borderRadius: 12,
          transition: 'transform 140ms var(--ease-snap)',
        }}
        onMouseDown={e => (e.currentTarget.style.transform = 'scale(0.97)')}
        onMouseUp={e => (e.currentTarget.style.transform = '')}
        onMouseLeave={e => (e.currentTarget.style.transform = '')}
        >
          <Avatar staff={s} size={56} />
          <div style={{ textAlign: 'center' }}>
            <div style={{ fontSize: 14, fontWeight: 500, color: 'var(--fg-1)' }}>{s.name}</div>
            <div style={{ fontSize: 11, color: 'var(--fg-3)', fontWeight: 400, letterSpacing: '0.04em', textTransform: 'uppercase' }}>
              {s.role}
            </div>
          </div>
        </button>
      ))}
    </div>
  </Modal>
);

// ------------------------------------------------------------------
// StaffMultiPicker — multi-select for PIC assignment
// ------------------------------------------------------------------
const StaffMultiPicker = ({ open, onClose, onSave, selectedIds = [], lockedIds = [], title = 'Assign PIC', subtitle = 'Select one or more people', saveLabel = 'Save' }) => {
  const [picked, setPicked] = useState(selectedIds);
  useEffect(() => { if (open) setPicked(selectedIds); }, [open]);
  const toggle = (id) => {
    if (lockedIds.includes(id)) return;
    setPicked(p => p.includes(id) ? p.filter(x => x !== id) : [...p, id]);
  };
  return (
    <Modal open={open} onClose={onClose} width={520} title={title}>
      <div style={{ padding: '4px 24px 0', color: 'var(--fg-3)', fontSize: 12, letterSpacing: '0.04em', textTransform: 'uppercase', fontWeight: 500 }}>
        {subtitle}
      </div>
      <div style={{
        padding: '16px 24px 8px',
        display: 'grid',
        gridTemplateColumns: 'repeat(2, 1fr)',
        gap: 8,
      }}>
        {window.SAMPLE_STAFF.map(s => {
          const on = picked.includes(s.id);
          const locked = lockedIds.includes(s.id);
          return (
            <button key={s.id} onClick={() => toggle(s.id)} disabled={locked} style={{
              display: 'flex', alignItems: 'center', gap: 10,
              padding: '10px 14px',
              background: on ? 'var(--fg-1)' : 'var(--bg-sunken)',
              borderRadius: 10,
              border: on ? '1px solid var(--fg-1)' : '1px solid transparent',
              transition: 'all 120ms var(--ease-snap)',
              textAlign: 'left',
              cursor: locked ? 'default' : 'pointer',
              opacity: locked ? 0.85 : 1,
            }}>
              <div style={{
                width: 18, height: 18, borderRadius: 4,
                background: on ? '#FFFFFF' : 'transparent',
                border: on ? 'none' : '1.5px solid var(--border-2)',
                display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
                flex: '0 0 auto',
              }}>
                {on && <Icon name="check" size={12} strokeWidth={2.5} color="var(--fg-1)" />}
              </div>
              <div style={{ flex: 1, minWidth: 0 }}>
                <div style={{ fontSize: 14, fontWeight: 500, color: on ? '#FFFFFF' : 'var(--fg-1)', letterSpacing: '-0.005em' }}>
                  {s.name}
                </div>
                <div style={{ fontSize: 11, color: on ? 'rgba(255,255,255,0.65)' : 'var(--fg-3)', fontWeight: 400, letterSpacing: '0.04em', textTransform: 'uppercase' }}>
                  {locked ? 'Already acknowledged' : s.role}
                </div>
              </div>
            </button>
          );
        })}
      </div>
      <div style={{
        padding: '12px 24px 20px',
        display: 'flex', justifyContent: 'flex-end', gap: 8,
        borderTop: '1px solid var(--border-1)',
        marginTop: 4,
      }}>
        <Btn variant="secondary" onClick={onClose}>Cancel</Btn>
        <Btn variant="primary" onClick={() => { onSave(picked); onClose(); }}>
          {saveLabel} {picked.length > 0 && `(${picked.length})`}
        </Btn>
      </div>
    </Modal>
  );
};

// ------------------------------------------------------------------
// Number Pad (reusable)
// ------------------------------------------------------------------
const NumPad = ({ value = '', onChange, onEnter, maxLen = 4, big = false }) => {
  const keys = ['1','2','3','4','5','6','7','8','9','','0','⌫'];
  const tap = (k) => {
    if (k === '') return;
    if (k === '⌫') return onChange(value.slice(0, -1));
    if (value.length >= maxLen) return;
    const next = value + k;
    onChange(next);
    if (next.length === maxLen && onEnter) setTimeout(() => onEnter(next), 100);
  };
  const sz = big ? 84 : 70;
  return (
    <div style={{
      display: 'grid',
      gridTemplateColumns: `repeat(3, ${sz}px)`,
      gap: big ? 18 : 12,
      justifyContent: 'center',
    }}>
      {keys.map((k, i) => (
        <button key={i} onClick={() => tap(k)} disabled={k === ''} style={{
          width: sz, height: sz,
          background: k === '' ? 'transparent' : 'var(--bg-sunken)',
          border: 'none',
          borderRadius: 999,
          fontSize: big ? 30 : 24,
          fontWeight: 300,
          color: k === '⌫' ? 'var(--fg-2)' : 'var(--fg-1)',
          display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
          boxShadow: 'none',
          cursor: k === '' ? 'default' : 'pointer',
          transition: 'background 100ms, transform 120ms',
          letterSpacing: '-0.02em',
        }}
        onMouseDown={e => { if (k) { e.currentTarget.style.background = '#E5E5EA'; e.currentTarget.style.transform = 'scale(0.95)'; } }}
        onMouseUp={e => { e.currentTarget.style.background = k ? 'var(--bg-sunken)' : 'transparent'; e.currentTarget.style.transform = ''; }}
        onMouseLeave={e => { e.currentTarget.style.background = k ? 'var(--bg-sunken)' : 'transparent'; e.currentTarget.style.transform = ''; }}
        >
          {k === '⌫' ? <Icon name="backspace" size={big ? 26 : 22} /> : k}
        </button>
      ))}
    </div>
  );
};

// ------------------------------------------------------------------
// Progress bar
// ------------------------------------------------------------------
const ProgressBar = ({ pct, height = 6, color = 'var(--blue-500)', bg = 'var(--bg-sunken)' }) => (
  <div style={{
    width: '100%', height, background: bg, borderRadius: 999, overflow: 'hidden',
  }}>
    <div style={{
      height: '100%', width: `${Math.min(100, Math.max(0, pct))}%`,
      background: color, borderRadius: 999,
      transition: 'width 400ms var(--ease-out)',
    }} />
  </div>
);

// ------------------------------------------------------------------
// Toast
// ------------------------------------------------------------------
const Toast = ({ message, open, onClose, staff, icon = 'check' }) => {
  useEffect(() => {
    if (!open) return;
    const t = setTimeout(() => onClose && onClose(), 2400);
    return () => clearTimeout(t);
  }, [open]);
  if (!open) return null;
  return (
    <div style={{
      position: 'fixed', bottom: 32, left: '50%',
      transform: 'translateX(-50%)',
      zIndex: 2000,
      padding: '12px 18px',
      background: 'var(--bg-ink)', color: '#FFFFFF',
      borderRadius: 999, fontSize: 14, fontWeight: 500,
      display: 'flex', alignItems: 'center', gap: 12,
      boxShadow: 'var(--shadow-pop)',
      animation: 'slide-up 220ms var(--ease-snap)',
    }}>
      {staff ? <Avatar staff={staff} size={28} /> : (
        <div style={{
          width: 28, height: 28, borderRadius: 999,
          background: 'var(--blue-500)',
          display: 'flex', alignItems: 'center', justifyContent: 'center',
        }}>
          <Icon name={icon} size={16} color="#fff" strokeWidth={2.4} />
        </div>
      )}
      {message}
    </div>
  );
};

Object.assign(window, {
  Icon, Avatar, AvatarStack, Btn, CategoryChip, PriorityPill,
  Card, Modal, StaffPicker, StaffMultiPicker, NumPad, ProgressBar, Toast,
});
