// Ajustes → Supermercados / Resultados / Próximamente. Sustituye a la
// antigua sección «Mercadona». Referencia visual:
// docs/design/multi-super/Ajustes.dc.html.

function SupermarketsSettings({ app, theme }) {
  const c = theme.c;
  const t = app.t;
  const ts = t.stores;
  const stores = app.stores;
  const [cpDraft, setCpDraft] = React.useState(stores.cp || '');
  // status[chain]: null | 'checking' | { error }
  const [status, setStatus] = React.useState({});
  const setOne = (id, v) => setStatus(s => ({ ...s, [id]: v }));
  // Filas con key estable (no se remontan: no se pierde el foco). La
  // sacudida se relanza quitando y poniendo la clase sobre el nodo.
  const rowRefs = React.useRef({});
  // CP de la última validación pedida: resultados de un CP anterior se ignoran.
  const cpRef = React.useRef(stores.cp || '');
  // Última petición por cadena: si llega obsoleta, solo limpia 'checking'
  // cuando nadie ha lanzado ya una comprobación más nueva para esa cadena.
  const reqRef = React.useRef({});

  function shakeRow(id) {
    const el = rowRefs.current[id];
    if (!el) return;
    el.classList.remove('sl-anim-shake');
    void el.offsetWidth;
    el.classList.add('sl-anim-shake');
  }

  // Activa una cadena sin código postal: modo «precios generales», sin
  // llamar a `locate` (Mercadona usa el almacén por defecto, Consum busca
  // sin zona — ver `StoresCore.genericEnablePatch`).
  function enableGeneric(id, batch) {
    app.setStores(s => StoresCore.withChain(s, id, { ...StoresCore.genericEnablePatch(id), enabled: true }));
    setOne(id, null);
    if (!batch) SLMotion.haptic.success();
  }

  // Valida una cadena contra `cp`. Devuelve true/false; con `batch` no hace
  // háptica (el llamador la hace una sola vez por lote).
  async function enableChain(id, cp, batch) {
    // Sin CP válido, o cadena de catálogo (Dia): se activa en modo genérico
    // sin preguntar a /api/stores/locate (bloqueado desde Vercel para Dia).
    if (!/^\d{5}$/.test(cp) || StoresCore.isCatalogChain(id)) {
      enableGeneric(id, batch);
      return true;
    }
    setOne(id, 'checking');
    const token = {};
    reqRef.current[id] = token;
    const r = await Stores.locate(id, cp);
    if (cpRef.current !== cp) {
      // CP obsoleto: si nadie relanzó ya la comprobación de esta cadena,
      // apaga el spinner (si no, el `toggleChain` se queda bloqueado).
      if (reqRef.current[id] === token) setOne(id, null);
      return true;
    }
    if (r.ok) {
      app.setStores(s => StoresCore.withChain({ ...s, cp }, id, { ...r.patch, enabled: true }));
      setOne(id, null);
      if (!batch) SLMotion.haptic.success();
      return true;
    }
    if (r.code === 'not_served') {
      // No reparte en este CP, pero eso no es peor que no tener CP: la
      // cadena se activa igual en modo genérico (mismo parche que
      // `enableGeneric`). Información, no un fallo: sin sacudida ni háptica
      // de error.
      app.setStores(s => StoresCore.withChain({ ...s, cp }, id, { ...StoresCore.genericEnablePatch(id), enabled: true }));
      setOne(id, null);
      if (!batch) SLMotion.haptic.success();
      return true;
    }
    app.setStores(s => StoresCore.withChain(s, id, { enabled: false }));
    setOne(id, { error: r.code });
    shakeRow(id);
    if (!batch) SLMotion.haptic.error();
    return false;
  }

  function toggleChain(id) {
    if (status[id] === 'checking') return;
    if (stores.chains[id].enabled) {
      app.setStores(s => StoresCore.withChain(s, id, { enabled: false }));
      setOne(id, null);
      SLMotion.haptic.light();
      return;
    }
    cpRef.current = stores.cp;
    enableChain(id, stores.cp, false);
  }

  // Nuevo CP válido: se guarda y se revalidan las cadenas activas (una sola
  // háptica para todo el lote). Borrar el CP no apaga las cadenas activas:
  // vuelven a modo genérico (Mercadona, al almacén por defecto).
  async function commitCp(value) {
    const cp = value.replace(/\D/g, '').slice(0, 5);
    if (cp === stores.cp) return;
    if (cp === '') {
      cpRef.current = '';
      const ids = StoresCore.enabledChains(stores);
      app.setStores(s => ids.reduce((acc, id) => StoresCore.withChain(acc, id, StoresCore.genericEnablePatch(id)), { ...s, cp: '' }));
      return;
    }
    if (!/^\d{5}$/.test(cp)) return;
    cpRef.current = cp;
    app.setStores(s => ({ ...s, cp }));
    const ids = StoresCore.enabledChains(stores);
    if (!ids.length) return;
    const results = await Promise.all(ids.map(id => enableChain(id, cp, true)));
    if (cpRef.current !== cp) return;
    if (results.every(Boolean)) SLMotion.haptic.success(); else SLMotion.haptic.error();
  }

  const subColor = (tone) => tone === 'error' ? c.errorInk : tone === 'ok' ? c.okInk : c.inkSub;
  const cpIncomplete = cpDraft.length > 0 && cpDraft.length < 5;

  return (
    <>
      <Section theme={theme} title={ts.title}>
        <Row theme={theme} last={false}>
          <div style={{ flex: 1, minWidth: 0 }}>
            <div style={{ fontWeight: 700, fontFamily: theme.fontDisplay, fontSize: rem(15) }}>{ts.cpTitle}</div>
            <div id="stores-cp-hint" data-testid="stores-cp-hint" style={{ fontSize: 12, color: cpIncomplete ? c.errorInk : c.inkSub, marginTop: 2 }}>
              {cpIncomplete ? ts.cpHint : ts.cpDesc}
            </div>
          </div>
          <input data-testid="stores-cp" value={cpDraft} inputMode="numeric" pattern="[0-9]*" maxLength={5}
            aria-label={ts.cpTitle} aria-describedby="stores-cp-hint" aria-invalid={cpIncomplete ? 'true' : undefined}
            placeholder={ts.cpPlaceholder}
            onChange={e => { const v = e.target.value.replace(/\D/g, '').slice(0, 5); setCpDraft(v); if (v.length === 5) commitCp(v); }}
            onBlur={() => commitCp(cpDraft)}
            onKeyDown={e => { if (e.key === 'Enter') e.currentTarget.blur(); }}
            style={{
              width: 92, height: 44, padding: '0 12px', boxSizing: 'border-box',
              border: `1.5px solid ${cpIncomplete ? c.errorInk : c.border}`, borderRadius: theme.radius.md, background: c.bg,
              fontFamily: theme.fontMono, fontSize: 15, color: c.ink, outline: 'none',
            }} />
        </Row>
        {StoresCore.CHAIN_IDS.map((id, i) => {
          const meta = StoresCore.CHAIN_META[id];
          const pref = stores.chains[id];
          const st = status[id] || null;
          const sub = StoresCore.chainSubtitle(id, pref, st, stores.cp || cpDraft);
          return (
            <div key={id} ref={el => { rowRefs.current[id] = el; }} data-testid={`store-row-${id}`} style={{
              padding: '12px 16px', minHeight: 64, boxSizing: 'border-box',
              borderBottom: i === StoresCore.CHAIN_IDS.length - 1 ? 'none' : `1px solid ${c.border}`,
              display: 'flex', alignItems: 'center', gap: 12, fontFamily: theme.fontBody, color: c.ink,
            }}>
              <ChainBadge theme={theme} chain={id} size={29} />
              <div style={{ flex: 1, minWidth: 0 }}>
                <div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
                  <span style={{ fontWeight: 700, fontSize: rem(15), fontFamily: theme.fontDisplay }}>{meta.name}</span>
                  {meta.beta && (
                    <span style={{
                      padding: '1px 6px', borderRadius: 999, border: `1px solid ${c.border}`,
                      fontSize: 10, fontWeight: 700, color: c.inkSub, fontFamily: theme.fontMono,
                    }}>{ts.beta}</span>
                  )}
                </div>
                <div data-testid={`store-sub-${id}`} aria-live="polite" style={{
                  display: 'flex', alignItems: 'center', gap: 6, marginTop: 2, fontSize: 12, color: subColor(sub.tone),
                }}>
                  {sub.spinner && (
                    <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>{tpl(ts.sub[sub.key], sub.vars)}</span>
                </div>
              </div>
              <ChainSwitch theme={theme} on={!!pref.enabled} pending={st === 'checking'} label={meta.name}
                testid={`store-switch-${id}`} onClick={() => toggleChain(id)} />
            </div>
          );
        })}
      </Section>
      <div style={{ fontSize: 12, color: c.inkSub, padding: '0 6px', margin: '-14px 0 22px', lineHeight: 1.4, fontFamily: theme.fontBody }}>
        {ts.footnote}
      </div>

      <Section theme={theme} title={ts.resultsTitle}>
        <div style={{ padding: '14px 16px', display: 'flex', flexDirection: 'column', gap: 10 }}>
          <div style={{ fontWeight: 700, fontSize: rem(15), fontFamily: theme.fontDisplay, color: c.ink }}>{ts.defaultSort}</div>
          <Segmented theme={theme} testid="stores-sort" label={ts.defaultSort} value={stores.sort}
            options={[{ value: 'store', label: ts.sortStore }, { value: 'price', label: ts.sortPrice }]}
            onChange={v => app.setStores(s => ({ ...s, sort: v }))} />
        </div>
      </Section>

      <Section theme={theme} title={ts.soonTitle}>
        {StoresCore.SOON_CHAINS.map((s, i) => (
          <div key={s.id} aria-disabled="true" data-testid={`store-soon-${s.id}`} style={{
            padding: '12px 16px', minHeight: 56, boxSizing: 'border-box',
            borderBottom: i === StoresCore.SOON_CHAINS.length - 1 ? 'none' : `1px solid ${c.border}`,
            display: 'flex', alignItems: 'center', gap: 12, fontFamily: theme.fontBody,
          }}>
            <span aria-hidden="true" style={{
              width: 29, height: 29, borderRadius: 7, background: c.bg, border: `1.5px solid ${c.border}`,
              color: c.inkSub, fontSize: s.letter.length > 1 ? 12 : 14, fontWeight: 800, boxSizing: 'border-box',
              display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0,
            }}>{s.letter}</span>
            <div style={{ flex: 1, minWidth: 0 }}>
              <div style={{ fontWeight: 700, fontSize: rem(15), color: c.inkSub, fontFamily: theme.fontDisplay }}>{s.name}</div>
              <div style={{ fontSize: 12, color: c.inkSub, marginTop: 2 }}>{ts.soon[s.id]}</div>
            </div>
          </div>
        ))}
      </Section>
    </>
  );
}

window.SupermarketsSettings = SupermarketsSettings;
