// Primitivas visuales de la integración multi-súper. Referencia visual:
// docs/design/multi-super/*.dc.html. Colores de cadena fijos
// (`StoresCore.CHAIN_META`), el resto sale del tema (`theme.c.*`).

// Oculta visualmente pero deja el texto a los lectores de pantalla.
const SR_ONLY = {
  position: 'absolute', width: 1, height: 1, padding: 0, margin: -1,
  overflow: 'hidden', clip: 'rect(0 0 0 0)', whiteSpace: 'nowrap', border: 0,
};

// Chapa cuadrada con la letra de la cadena. `ring` = color del aro exterior
// que la separa de la miniatura. En oscuro lleva además un aro interior
// blanco al 60 % para que no se funda con tarjetas oscuras (contraste ≥3:1,
// tests/unit/contrast.test.mjs).
function ChainBadge({ theme, chain, size = 18, ring }) {
  const meta = StoresCore.chainMeta(chain);
  if (!meta) return null;
  const two = meta.letter.length > 1;
  const shadows = [];
  if (ring) shadows.push(`0 0 0 2px ${ring}`);
  if (theme && theme.dark) shadows.push('inset 0 0 0 1.5px rgba(255,255,255,.6)');
  return (
    <span aria-hidden="true" data-testid={`chain-badge-${chain}`} style={{
      width: size, height: size, borderRadius: Math.round(size / 3),
      background: meta.color, color: '#fff',
      fontSize: Math.round(size * (two ? 0.45 : 0.55)), fontWeight: 800, lineHeight: 1,
      display: 'inline-flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0,
      boxShadow: shadows.length ? shadows.join(', ') : 'none',
    }}>{meta.letter}</span>
  );
}

// Interruptor accesible de 44px de zona táctil. `pending` = comprobando
// (pista más clara, sigue "encendido" visualmente).
function ChainSwitch({ theme, on, pending, label, onClick, testid }) {
  const c = theme.c;
  const visualOn = on || pending;
  return (
    <button type="button" role="switch" aria-checked={visualOn ? 'true' : 'false'} aria-label={label}
      aria-busy={pending ? 'true' : undefined} data-testid={testid} onClick={onClick}
      style={{
        width: 52, height: 44, margin: '-8px -2px', padding: '8px 2px',
        border: 'none', background: 'transparent', cursor: 'pointer', flexShrink: 0,
      }}>
      <span style={{
        display: 'block', width: 48, height: 28, padding: 2, borderRadius: 999, boxSizing: 'border-box',
        background: visualOn ? (pending ? c.accent + '80' : c.accent) : c.border, transition: 'background .2s',
      }}>
        <span style={{
          display: 'block', width: 24, height: 24, borderRadius: 999, background: '#fff',
          transform: `translateX(${visualOn ? 20 : 0}px)`,
          transition: 'transform .22s cubic-bezier(.2,1.3,.4,1)', boxShadow: '0 1px 3px rgba(0,0,0,0.25)',
        }} />
      </span>
    </button>
  );
}

// Control segmentado con pastilla deslizante. Botones de 44 px (contenedor
// con 2 px de relleno). `tone`: 'accent' (pastilla naranja: Ajustes, panel)
// o 'card' (pastilla blanca: modo compra). No roba el foco del campo.
function Segmented({ theme, value, options, onChange, label, testid, tone = 'accent' }) {
  const c = theme.c;
  const n = options.length;
  const idx = Math.max(0, options.findIndex(o => o.value === value));
  const thumbBg = tone === 'card' ? c.bgCard : c.accent;
  const onFg = tone === 'card' ? c.ink : c.accentInk;
  return (
    <div role="group" aria-label={label} data-testid={testid} style={{
      position: 'relative', display: 'grid', gridTemplateColumns: `repeat(${n}, minmax(0, 1fr))`,
      padding: 2, background: tone === 'card' ? c.border : c.bg, borderRadius: 999,
    }}>
      <span aria-hidden="true" style={{
        position: 'absolute', top: 2, left: 2, width: `calc(${100 / n}% - ${4 / n}px)`, height: 44,
        borderRadius: 999, background: thumbBg, boxShadow: c.shadowSoft,
        transform: `translateX(${idx * 100}%)`, transition: 'transform .34s cubic-bezier(.32,.72,0,1)',
      }} />
      {options.map(o => (
        <button key={o.value} type="button" className="sl-press" aria-pressed={o.value === value ? 'true' : 'false'}
          onMouseDown={e => e.preventDefault()}
          onClick={() => { if (o.value !== value) { SLMotion.haptic.selection(); onChange(o.value); } }}
          style={{
            position: 'relative', height: 44, border: 'none', background: 'transparent', borderRadius: 999,
            fontSize: 13, fontWeight: 700, fontFamily: theme.fontDisplay, cursor: 'pointer',
            color: o.value === value ? onFg : c.ink,
            transition: 'color .2s, transform .12s cubic-bezier(.32,.72,0,1)',
          }}>{o.label}</button>
      ))}
    </div>
  );
}

// Miniatura del producto con la chapa de su cadena en la esquina. Si la
// imagen falla (antibots, 404) se ve el glifo de bolsa en su lugar.
function ProductThumb({ theme, product, size = 44, badge = true, badgeSize }) {
  const c = theme.c;
  const [broken, setBroken] = React.useState(false);
  React.useEffect(() => { setBroken(false); }, [product && product.thumbnail]);
  const bs = badgeSize || Math.max(16, Math.round(size * 0.45));
  return (
    <span style={{ position: 'relative', width: size, height: size, flexShrink: 0, display: 'inline-block' }}>
      <span style={{
        display: 'flex', width: size, height: size, borderRadius: Math.round(size * 0.27),
        background: '#fff', border: `1px solid ${c.border}`, overflow: 'hidden', boxSizing: 'border-box',
        alignItems: 'center', justifyContent: 'center', color: c.accent2,
      }}>
        {product && product.thumbnail && !broken
          ? <img src={product.thumbnail} alt="" loading="lazy" onError={() => setBroken(true)}
              style={{ width: '100%', height: '100%', objectFit: 'cover' }} />
          : <Icon name="cart" size={Math.round(size * 0.5)} stroke={1.8} />}
      </span>
      {badge && product && (
        <span style={{ position: 'absolute', right: -5, bottom: -5, display: 'flex' }}>
          <ChainBadge theme={theme} chain={product.chain} size={bs} ring={c.bgCard} />
        </span>
      )}
    </span>
  );
}

// Aro giratorio + texto «Buscando…». El texto solo se ve cuando no hay
// movimiento (animaciones apagadas o «reducir movimiento»): un aro quieto
// no comunica nada; con movimiento queda para lectores de pantalla.
function StoreSpinner({ theme, label, motion }) {
  const c = theme.c;
  return (
    <span style={{ display: 'inline-flex', alignItems: 'center', gap: 6 }}>
      <span aria-hidden="true" className="sl-spinner" style={{
        width: 12, height: 12, borderRadius: 999, flexShrink: 0, boxSizing: 'border-box',
        border: `2px solid ${c.border}`, borderTopColor: c.accent,
      }} />
      <span style={motion ? SR_ONLY : undefined}>{label}</span>
    </span>
  );
}

// Chips de filtro: «Todos» + una por cadena con su contador. Borde derecho
// difuminado como pista de que la fila se desplaza.
function ChainChips({ theme, chains, counts, value, onChange, allLabel, label }) {
  const c = theme.c;
  const chip = (id, text, count) => {
    const on = value === id;
    const meta = StoresCore.CHAIN_META[id];
    return (
      <button key={id} type="button" className="sl-press" aria-pressed={on ? 'true' : 'false'} data-testid={`chain-chip-${id}`}
        onMouseDown={e => e.preventDefault()}
        onClick={() => { if (!on) { SLMotion.haptic.selection(); onChange(id); } }}
        style={{
          flexShrink: 0, height: 44, display: 'flex', alignItems: 'center', gap: 7,
          padding: meta ? '0 12px 0 8px' : '0 14px', borderRadius: 999,
          border: `1.5px solid ${on ? c.ink : c.border}`, background: on ? c.ink : c.bgCard,
          color: on ? c.bg : c.ink, fontSize: 13, fontWeight: 700, fontFamily: theme.fontDisplay,
          cursor: 'pointer', whiteSpace: 'nowrap',
        }}>
        {meta && <ChainBadge theme={theme} chain={id} size={24} />}
        <span>{text}</span>
        {count != null && <span style={{ fontFamily: theme.fontMono, fontSize: 11, opacity: 0.7 }}>{count}</span>}
      </button>
    );
  };
  const total = counts ? chains.reduce((a, id) => a + (counts[id] || 0), 0) : null;
  const fade = 'linear-gradient(to right, #000 calc(100% - 24px), transparent)';
  return (
    <div role="group" aria-label={label} className="sl-scroll" style={{
      display: 'flex', gap: 6, overflowX: 'auto', paddingRight: 24,
      maskImage: fade, WebkitMaskImage: fade,
    }}>
      {chip('all', allLabel, total)}
      {chains.map(id => chip(id, StoresCore.chainName(id), counts ? (counts[id] || 0) : null))}
    </div>
  );
}

// Etiqueta verde «Mejor €/kg» (texto `okInk`, ≥4.5:1 en todos los temas).
function BestTag({ theme, children }) {
  const c = theme.c;
  return (
    <span data-testid="best-tag" style={{
      flexShrink: 0, padding: '2px 7px', borderRadius: 999, background: c.successBg,
      color: c.okInk, fontSize: 10, fontWeight: 700, fontFamily: theme.fontBody,
    }}>{children}</span>
  );
}

// Fila de producto de súper (panel de resultados y hoja «Elegir producto»).
// `sub` = texto secundario; `right2` = línea bajo el precio (€/kg o
// diferencia); `picked` = sello ✓ en vez del precio; `active` = relleno de
// acento; `dim` = atenuada mientras su cadena recarga; `index` escalona la
// entrada (28 ms por fila, máx. 7). `role`/`checked` para usarla como radio.
function StoreProductRow({ theme, product, sub, best, bestLabel, right2, right2Color, picked, active, dim, index = 0, animate, onPick, ariaLabel, role, checked, disabled, testid = 'store-result' }) {
  const c = theme.c;
  const delay = Math.min(index, 7) * 28;
  return (
    <button type="button" data-testid={testid} role={role} aria-label={ariaLabel}
      aria-checked={role === 'radio' ? (checked ? 'true' : 'false') : undefined}
      aria-pressed={!role && active ? 'true' : undefined} aria-disabled={disabled ? 'true' : undefined}
      onMouseDown={e => e.preventDefault()} onClick={() => onPick(product)}
      className={'sl-row-press' + (animate ? ' sl-anim-row' : '')}
      style={{
        '--sl-press-bg': c.bg,
        display: 'flex', alignItems: 'center', gap: 12, width: '100%', minHeight: 64,
        padding: '10px 14px', border: 'none', textAlign: 'left', cursor: 'pointer',
        background: active ? c.accent : picked ? c.bg : 'transparent',
        color: active ? c.accentInk : c.ink, fontFamily: theme.fontBody,
        opacity: dim ? 0.6 : 1, transition: 'opacity .2s ease, background-color .18s ease',
        animationDelay: animate ? `${delay}ms` : undefined,
      }}>
      <ProductThumb theme={theme} product={product} size={44} />
      <span style={{ flex: 1, minWidth: 0 }}>
        <span style={{
          display: '-webkit-box', WebkitLineClamp: 2, WebkitBoxOrient: 'vertical', overflow: 'hidden',
          fontSize: 14, fontWeight: 700, fontFamily: theme.fontDisplay, lineHeight: 1.2,
        }}>{product.name}</span>
        <span style={{ display: 'flex', alignItems: 'center', gap: 6, marginTop: 3, minWidth: 0 }}>
          <span style={{
            fontSize: 11, color: active ? c.accentInk : c.inkSub, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis',
          }}>{sub}</span>
          {best && <BestTag theme={theme}>{bestLabel}</BestTag>}
        </span>
      </span>
      {picked ? (
        <span className="sl-anim-stamp" style={{
          width: 32, height: 32, borderRadius: 999, background: c.success, color: '#fff', flexShrink: 0,
          display: 'flex', alignItems: 'center', justifyContent: 'center',
        }}><Icon name="check" size={18} stroke={3} /></span>
      ) : (
        <span style={{ display: 'flex', flexDirection: 'column', alignItems: 'flex-end', flexShrink: 0 }}>
          <span style={{ fontSize: 14, fontWeight: 800, fontFamily: theme.fontMono }}>{StoresCore.fmtEur(product.price)}</span>
          {right2 && <span style={{ fontSize: 10.5, fontWeight: 700, fontFamily: theme.fontMono, color: right2Color || (active ? c.accentInk : c.inkSub) }}>{right2}</span>}
        </span>
      )}
    </button>
  );
}

// Fila de marcador de carga (sin animación: no distrae ni necesita
// alternativa de «reducir movimiento»).
function SkeletonRow({ theme }) {
  const c = theme.c;
  const bar = (w, h) => <span style={{ display: 'block', width: w, height: h, borderRadius: 6, background: c.border }} />;
  return (
    <div aria-hidden="true" data-testid="store-skeleton" style={{ display: 'flex', alignItems: 'center', gap: 12, minHeight: 64, padding: '10px 14px', boxSizing: 'border-box' }}>
      <span style={{ width: 44, height: 44, borderRadius: 12, background: c.border, flexShrink: 0 }} />
      <span style={{ flex: 1, display: 'flex', flexDirection: 'column', gap: 6 }}>{bar('70%', 12)}{bar('40%', 10)}</span>
    </div>
  );
}

// Fila de mensaje (sin resultados, sin conexión, todas fallan).
function MessageRow({ theme, testid, children }) {
  const c = theme.c;
  return (
    <div data-testid={testid} style={{ padding: '18px 16px', fontSize: 13, color: c.inkSub, fontFamily: theme.fontBody, lineHeight: 1.4 }}>
      {children}
    </div>
  );
}

Object.assign(window, { SR_ONLY, ChainBadge, ChainSwitch, Segmented, ProductThumb, StoreSpinner, ChainChips, BestTag, StoreProductRow, SkeletonRow, MessageRow });
