// wh-atoms.jsx — Icons, Avatar, Badge, Modal, helpers, Supabase client

const { useState, useEffect, useRef } = React;

/* ── Supabase client (frontend) ─────────────────────────── */
const SUPABASE_URL      = 'https://npazqkjfnqnhyxatsycx.supabase.co';
const SUPABASE_ANON_KEY = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Im5wYXpxa2pmbnFuaHl4YXRzeWN4Iiwicm9sZSI6ImFub24iLCJpYXQiOjE3NzY5MzI2NDMsImV4cCI6MjA5MjUwODY0M30.ZgBObqB0mvRZTNEQ7skAKY4oAYUtj2asUezvJa8UrlI';
const sbClient = supabase.createClient(SUPABASE_URL, SUPABASE_ANON_KEY);

/* apiFetch: wrapper que incluye el token JWT en todas las llamadas al backend */
async function apiFetch(url, options = {}) {
  const { data: { session } } = await sbClient.auth.getSession();
  const isFormData = options?.body instanceof FormData;
  const defaultHeaders = isFormData ? {} : { 'Content-Type': 'application/json' };
  const headers = { ...defaultHeaders, ...(options.headers || {}) };
  if (session?.access_token) headers['Authorization'] = `Bearer ${session.access_token}`;
  return fetch(url, { ...options, headers });
}

/* ── Icons ─────────────────────────────────────────────── */
function Icon({ name, size = 18, strokeWidth = 2, style, className }) {
  const d = {
    wifi: <><path d="M5 12.55a11 11 0 0 1 14.08 0"/><path d="M1.42 9a16 16 0 0 1 21.16 0"/><path d="M8.53 16.11a6 6 0 0 1 6.95 0"/><circle cx="12" cy="20" r="1"/></>,
    'wifi-off': <><line x1="1" y1="1" x2="23" y2="23"/><path d="M16.72 11.06A10.94 10.94 0 0 1 19 12.55"/><path d="M5 12.55a10.94 10.94 0 0 1 5.17-2.39"/><path d="M10.71 5.05A16 16 0 0 1 22.56 9"/><path d="M1.42 9a15.91 15.91 0 0 1 4.7-2.88"/><path d="M8.53 16.11a6 6 0 0 1 6.95 0"/><line x1="12" y1="20" x2="12.01" y2="20"/></>,
    layers: <><polygon points="12 2 2 7 12 12 22 7 12 2"/><polyline points="2 17 12 22 22 17"/><polyline points="2 12 12 17 22 12"/></>,
    users: <><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M23 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/></>,
    'user-plus': <><path d="M16 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="8.5" cy="7" r="4"/><line x1="20" y1="8" x2="20" y2="14"/><line x1="23" y1="11" x2="17" y2="11"/></>,
    user: <><path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/></>,
    send: <><line x1="22" y1="2" x2="11" y2="13"/><polygon points="22 2 15 22 11 13 2 9 22 2"/></>,
    activity: <><polyline points="22 12 18 12 15 21 9 3 6 12 2 12"/></>,
    shield: <><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/></>,
    sun: <><circle cx="12" cy="12" r="5"/><line x1="12" y1="1" x2="12" y2="3"/><line x1="12" y1="21" x2="12" y2="23"/><line x1="4.22" y1="4.22" x2="5.64" y2="5.64"/><line x1="18.36" y1="18.36" x2="19.78" y2="19.78"/><line x1="1" y1="12" x2="3" y2="12"/><line x1="21" y1="12" x2="23" y2="12"/><line x1="4.22" y1="19.78" x2="5.64" y2="18.36"/><line x1="18.36" y1="5.64" x2="19.78" y2="4.22"/></>,
    moon: <><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/></>,
    menu: <><line x1="3" y1="12" x2="21" y2="12"/><line x1="3" y1="6" x2="21" y2="6"/><line x1="3" y1="18" x2="21" y2="18"/></>,
    x: <><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></>,
    check: <><polyline points="20 6 9 17 4 12"/></>,
    'check-circle': <><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/><polyline points="22 4 12 14.01 9 11.01"/></>,
    plus: <><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></>,
    trash: <><polyline points="3 6 5 6 21 6"/><path d="M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6"/><path d="M10 11v6"/><path d="M14 11v6"/><path d="M9 6V4a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v2"/></>,
    search: <><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></>,
    'refresh-cw': <><polyline points="23 4 23 10 17 10"/><polyline points="1 20 1 14 7 14"/><path d="M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15"/></>,
    eye: <><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/></>,
    'log-out': <><path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"/><polyline points="16 17 21 12 16 7"/><line x1="21" y1="12" x2="9" y2="12"/></>,
    list: <><line x1="8" y1="6" x2="21" y2="6"/><line x1="8" y1="12" x2="21" y2="12"/><line x1="8" y1="18" x2="21" y2="18"/><line x1="3" y1="6" x2="3.01" y2="6"/><line x1="3" y1="12" x2="3.01" y2="12"/><line x1="3" y1="18" x2="3.01" y2="18"/></>,
    zap: <><polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"/></>,
    'alert-circle': <><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></>,
    clock: <><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></>,
    paperclip: <><path d="M21.44 11.05l-9.19 9.19a6 6 0 0 1-8.49-8.49l9.19-9.19a4 4 0 0 1 5.66 5.66l-9.2 9.19a2 2 0 0 1-2.83-2.83l8.49-8.48"/></>,
    edit: <><path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"/><path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"/></>,
    'message-square': <><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 0 2 2z"/></>,
    key: <><path d="M21 2l-2 2m-7.61 7.61a5.5 5.5 0 1 1-7.778 7.778 5.5 5.5 0 0 1 7.777-7.777zm0 0L15.5 7.5m0 0l3 3L22 7l-3-3m-3.5 3.5L19 4"/></>,
  };
  return (
    <svg width={size} height={size} viewBox="0 0 24 24" fill="none"
      stroke="currentColor" strokeWidth={strokeWidth}
      strokeLinecap="round" strokeLinejoin="round"
      style={style} className={className}>
      {d[name] || <circle cx="12" cy="12" r="10"/>}
    </svg>
  );
}

/* ── Avatar ─────────────────────────────────────────────── */
const AV_COLORS = [
  ['oklch(50% 0.18 162)', 'oklch(96% 0.05 162)'],
  ['oklch(50% 0.2 220)',  'oklch(96% 0.05 220)'],
  ['oklch(50% 0.18 280)', 'oklch(96% 0.05 280)'],
  ['oklch(54% 0.2 30)',   'oklch(96% 0.05 30)'],
  ['oklch(50% 0.18 190)', 'oklch(96% 0.05 190)'],
  ['oklch(50% 0.18 320)', 'oklch(96% 0.05 320)'],
];
function Avatar({ name = '?', size = 'md' }) {
  const initials = (name || '?').split(' ').map(n => n[0]).slice(0, 2).join('').toUpperCase();
  const [bg, fg] = AV_COLORS[(name.charCodeAt(0) || 0) % AV_COLORS.length];
  const cls = `av av-${size}`;
  // Tamaño lg no definido en CSS — lo manejamos con estilo inline
  const lgStyle = size === 'lg' ? { width:52, height:52, fontSize:20, borderRadius:'50%' } : {};
  return <div className={cls} style={{ background: bg, color: fg, ...lgStyle }}>{initials}</div>;
}

/* ── Badge ──────────────────────────────────────────────── */
function Badge({ children, color = 'gray', dot }) {
  return (
    <span className={`badge badge-${color}`}>
      {dot && <span className={`dot dot-${dot}`} style={{ width: 6, height: 6 }} />}
      {children}
    </span>
  );
}

/* ── Modal ──────────────────────────────────────────────── */
function Modal({ open, onClose, title, subtitle, children }) {
  if (!open) return null;
  return (
    <div className="overlay" onClick={e => e.target === e.currentTarget && onClose()}>
      <div className="modal">
        <div className="modal-head">
          <div>
            {subtitle && <div className="eyebrow">{subtitle}</div>}
            <div style={{ fontSize: 16, fontWeight: 800 }}>{title}</div>
          </div>
          <button className="btn btn-ghost btn-icon btn-sm" onClick={onClose}>
            <Icon name="x" size={15} />
          </button>
        </div>
        <div className="modal-body">{children}</div>
      </div>
    </div>
  );
}

/* ── Empty State ────────────────────────────────────────── */
function EmptyState({ icon = 'list', title = 'Sin datos', sub }) {
  return (
    <div className="empty-state">
      <Icon name={icon} size={38} />
      <div className="empty-ttl">{title}</div>
      {sub && <div className="t-sm t-muted">{sub}</div>}
    </div>
  );
}

/* ── Section Header ─────────────────────────────────────── */
function SecHead({ eyebrow, title, actions }) {
  return (
    <div className="sec-head">
      <div>
        {eyebrow && <div className="eyebrow">{eyebrow}</div>}
        <h2>{title}</h2>
      </div>
      {actions && <div className="flex-r">{actions}</div>}
    </div>
  );
}

/* ── Toast system ───────────────────────────────────────── */
const TOAST_CFG = {
  success: { icon:'check-circle', accent:'var(--ok)',     bg:'var(--ok-soft)',     border:'oklch(78% 0.13 145)' },
  error:   { icon:'alert-circle', accent:'var(--danger)', bg:'var(--danger-soft)', border:'oklch(80% 0.1 22)'   },
  warning: { icon:'alert-circle', accent:'var(--warn)',   bg:'var(--warn-soft)',   border:'oklch(83% 0.12 76)'  },
  info:    { icon:'zap',          accent:'var(--brand)',  bg:'var(--brand-soft)',  border:'var(--border-2)'     },
};

function ToastItem({ toast, onRemove }) {
  const [leaving, setLeaving] = useState(false);
  const cfg = TOAST_CFG[toast.type] || TOAST_CFG.info;

  const close = () => {
    setLeaving(true);
    setTimeout(() => onRemove(toast.id), 250);
  };

  useEffect(() => {
    if (!toast.duration) return;
    const t = setTimeout(close, toast.duration);
    return () => clearTimeout(t);
  }, []);

  return (
    <div style={{
      display:'flex', alignItems:'flex-start', gap:11,
      background: cfg.bg,
      border: `1px solid ${cfg.border}`,
      borderRadius: 10,
      padding:'12px 14px',
      boxShadow:'var(--shadow-md)',
      minWidth: 280, maxWidth: 380,
      animation: leaving
        ? 'toastOut 250ms cubic-bezier(.4,0,1,1) forwards'
        : 'toastIn 280ms cubic-bezier(.34,1.4,.64,1)',
      pointerEvents:'all',
    }}>
      <Icon name={cfg.icon} size={17} style={{ color:cfg.accent, flexShrink:0, marginTop:1 }}/>
      <span style={{ flex:1, fontSize:13.5, fontWeight:600, color:'var(--ink)', lineHeight:1.5 }}>
        {toast.msg}
      </span>
      <button onClick={close}
        style={{ background:'none', border:'none', cursor:'pointer', color:'var(--muted)', padding:0, flexShrink:0, display:'flex', alignItems:'center' }}>
        <Icon name="x" size={14}/>
      </button>
    </div>
  );
}

function Toaster() {
  const [toasts, setToasts] = useState([]);

  useEffect(() => {
    window.showToast = (msg, type = 'info', duration = 4500) => {
      const id = Date.now() + Math.random();
      setToasts(prev => [...prev.slice(-4), { id, msg, type, duration }]);
    };
    return () => { delete window.showToast; };
  }, []);

  const remove = id => setToasts(prev => prev.filter(t => t.id !== id));

  if (!toasts.length) return null;
  return (
    <div style={{
      position:'fixed', top:70, right:18, zIndex:500,
      display:'flex', flexDirection:'column', gap:8,
      pointerEvents:'none',
    }}>
      {toasts.map(t => <ToastItem key={t.id} toast={t} onRemove={remove}/>)}
    </div>
  );
}

/* ── Confirm Dialog ─────────────────────────────────────── */
function ConfirmDialog() {
  const [state, setState] = useState(null); // { msg, title, danger, resolve }

  useEffect(() => {
    window.showConfirm = (msg, { title = 'Confirmar acción', danger = true } = {}) =>
      new Promise(resolve => setState({ msg, title, danger, resolve }));
    return () => { delete window.showConfirm; };
  }, []);

  if (!state) return null;

  const handle = result => {
    state.resolve(result);
    setState(null);
  };

  return (
    <div className="overlay" onClick={() => handle(false)}>
      <div className="modal" style={{ width:'min(420px, 100%)' }}
        onClick={e => e.stopPropagation()}>
        <div className="modal-head">
          <div style={{ fontSize:16, fontWeight:800 }}>{state.title}</div>
          <button className="btn btn-ghost btn-icon btn-sm" onClick={() => handle(false)}>
            <Icon name="x" size={15}/>
          </button>
        </div>
        <div className="modal-body">
          <p style={{ fontSize:14, color:'var(--ink-2)', lineHeight:1.6 }}>{state.msg}</p>
          <div className="flex-r" style={{ justifyContent:'flex-end', gap:10, marginTop:8 }}>
            <button className="btn btn-ghost" onClick={() => handle(false)}>Cancelar</button>
            <button
              className={state.danger ? 'btn btn-danger' : 'btn btn-primary'}
              onClick={() => handle(true)}>
              Confirmar
            </button>
          </div>
        </div>
      </div>
    </div>
  );
}

/* ── Mock Data (solo usuarios — los demás datos vienen del backend) ── */
const MOCK = {
  users: [
    { id: 'u1', name: 'Admin Principal', email: 'admin@empresa.com',  role: 'admin',    lastActive: '2025-04-23T10:30:00Z', status: 'active'   },
    { id: 'u2', name: 'Operador 1',      email: 'op1@empresa.com',    role: 'operator', lastActive: '2025-04-22T18:00:00Z', status: 'active'   },
    { id: 'u3', name: 'Operador 2',      email: 'op2@empresa.com',    role: 'operator', lastActive: '2025-04-20T11:00:00Z', status: 'inactive' },
  ],
};

Object.assign(window, { Icon, Avatar, Badge, Modal, EmptyState, SecHead, Toaster, ConfirmDialog, MOCK, sbClient, apiFetch });
