/* Configuración: cuenta administrador, tarifas y bancos */

/** Sección principal (tarjeta) o subsección interna — contenido oculto hasta expandir. */
const ConfigAccordionSection = ({
  theme,
  title,
  sub,
  children,
  defaultOpen = false,
  variant = 'card',
}) => {
  const [open, setOpen] = React.useState(defaultOpen);
  const isCard = variant === 'card';
  const headerPad = isCard ? '20px 24px' : '14px 16px';
  const bodyPad = isCard ? '0 24px 24px' : '0 16px 16px';

  return (
    <div style={{
      marginBottom: isCard ? 20 : 10,
      borderRadius: 12,
      border: `1px solid ${theme.border}`,
      background: isCard ? theme.bgCard : theme.bgElev,
      overflow: 'hidden',
    }}>
      <button
        type="button"
        onClick={() => setOpen((v) => !v)}
        aria-expanded={open}
        style={{
          width: '100%',
          display: 'flex',
          alignItems: 'flex-start',
          justifyContent: 'space-between',
          gap: 16,
          padding: headerPad,
          border: 'none',
          background: open ? `${theme.primary}08` : 'transparent',
          cursor: 'pointer',
          textAlign: 'left',
          fontFamily: 'inherit',
          transition: 'background 0.2s ease',
        }}
      >
        <div style={{ flex: 1, minWidth: 0 }}>
          <div style={{
            fontFamily: isCard ? 'Bebas Neue, sans-serif' : 'Inter, sans-serif',
            fontSize: isCard ? 22 : 12,
            fontWeight: isCard ? 400 : 700,
            letterSpacing: isCard ? 1 : 1.2,
            textTransform: isCard ? 'none' : 'uppercase',
            color: isCard ? theme.text : theme.primary,
            lineHeight: 1.2,
          }}>
            {title}
          </div>
          {sub && (
            <p style={{
              color: theme.textDim,
              fontSize: isCard ? 13 : 12,
              margin: '6px 0 0',
              fontFamily: 'Inter, sans-serif',
              lineHeight: 1.5,
              fontWeight: 400,
              textTransform: 'none',
              letterSpacing: 0,
            }}>
              {sub}
            </p>
          )}
        </div>
        <span style={{
          flexShrink: 0,
          width: 32,
          height: 32,
          borderRadius: 8,
          border: `1px solid ${theme.border}`,
          background: theme.bgInput,
          display: 'grid',
          placeItems: 'center',
          color: theme.primary,
          transform: open ? 'rotate(180deg)' : 'rotate(0deg)',
          transition: 'transform 0.2s ease',
        }} aria-hidden>
          <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round">
            <path d="M6 9l6 6 6-6" />
          </svg>
        </span>
      </button>
      {open && (
        <div style={{ padding: bodyPad, borderTop: `1px solid ${theme.border}` }}>
          {children}
        </div>
      )}
    </div>
  );
};

const dispatchTecosDataRefresh = () => {
  [
    'tecos:academy-data-sync',
    'tecos:payments-changed',
    'tecos:comprobantes-changed',
    'tecos:orders-changed',
    'tecos:students-changed',
    'tecos:finance-changed',
    'tecos:products-changed',
    'tecos:inventory-history-reset',
    'tecos:settings-changed',
  ].forEach((name) => window.dispatchEvent(new CustomEvent(name)));
  if (typeof window.clearTecosHistorialDismissedStorage === 'function') {
    window.clearTecosHistorialDismissedStorage();
  }
};

const AdminClearBillingHistoryPanel = ({ theme }) => {
  const [open, setOpen] = React.useState(false);
  const [password, setPassword] = React.useState('');
  const [confirmText, setConfirmText] = React.useState('');
  const [busy, setBusy] = React.useState(false);
  const [err, setErr] = React.useState('');
  const [ok, setOk] = React.useState('');

  const hasPassword = !!password.trim();
  const confirmOk = confirmText.trim().toUpperCase() === 'LIMPIAR HISTORIAL';
  const canRun = hasPassword && confirmOk;
  const clearHint = !hasPassword && !confirmOk
    ? 'Completa los dos campos: contraseña arriba y la frase LIMPIAR HISTORIAL abajo.'
    : !hasPassword
      ? 'Falta la contraseña de administrador (primer campo).'
      : !confirmOk
        ? 'En el segundo campo escribe exactamente LIMPIAR HISTORIAL — no es tu contraseña.'
        : '';

  const runClear = async () => {
    if (!canRun) return;
    if (!window.confirm(
      'Se borrarán pagos, órdenes de tienda, nómina pagada, gastos operativos, retiros de caja e historial de inventario. Ingresos y egresos del dashboard quedarán en cero. ¿Continuar?'
    )) return;
    setBusy(true);
    setErr('');
    setOk('');
    try {
      await verifyAdminSessionPassword(password);
      if (typeof adminClearBillingStoreHistory !== 'function') {
        throw new Error('Función no disponible. Ejecuta migración 070 en Supabase (SQL Editor).');
      }
      await adminClearBillingStoreHistory(confirmText);
      dispatchTecosDataRefresh();
      setPassword('');
      setConfirmText('');
      setOpen(false);
      setOk('Historial de ingresos, egresos y tienda borrado. Recarga el dashboard (F5) para ver todo en ceros.');
    } catch (e) {
      setErr(e.message || 'No se pudo limpiar el historial.');
    }
    setBusy(false);
  };

  return (
    <ConfigAccordionSection
      theme={theme}
      variant="card"
      title="LIMPIAR HISTORIAL FINANCIERO Y TIENDA"
      sub="Ingresos y egresos acumulados en cero, órdenes recientes, Historial, nómina pagada, gastos y retiros. No borra alumnos ni productos."
      defaultOpen={false}
    >
      {!open ? (
        <Btn theme={theme} kind="ghost" size="sm" onClick={() => { setErr(''); setOk(''); setOpen(true); }}
          style={{ color: theme.warning, borderColor: `${theme.warning}66` }}>
          Vaciar historial financiero (dashboard en ceros)
        </Btn>
      ) : (
        <div style={{
          padding: 16, borderRadius: 12,
          border: `1px solid ${theme.warning}55`, background: `${theme.warning}10`,
        }}>
          <p style={{ margin: '0 0 12px', fontSize: 13, color: theme.textDim, fontFamily: 'Inter, sans-serif', lineHeight: 1.55 }}>
            Usa esto para <strong>ceros en ingresos y egresos acumulados</strong>, órdenes recientes, pagos, tienda y movimientos de Nómina y gastos, sin borrar alumnos, galería ni eventos.
          </p>
          <ol style={{ margin: '0 0 14px', paddingLeft: 20, fontSize: 13, color: theme.textDim, fontFamily: 'Inter, sans-serif', lineHeight: 1.6 }}>
            <li><strong>Contraseña</strong> — la misma con la que entras al panel admin.</li>
            <li><strong>Confirmación</strong> — escribe la frase <code style={{ color: theme.warning }}>LIMPIAR HISTORIAL</code> (texto fijo, no tu contraseña).</li>
          </ol>
          <Input theme={theme} label="1. Contraseña de administrador" type="password" value={password}
            onChange={(e) => setPassword(e.target.value)} autoComplete="current-password"
            placeholder="Tu contraseña de sesión" />
          <div style={{ marginTop: 12 }}>
            <Input theme={theme} label="2. Confirmación (frase fija)" value={confirmText}
              onChange={(e) => setConfirmText(e.target.value)} autoComplete="off"
              placeholder="LIMPIAR HISTORIAL" spellCheck={false} />
          </div>
          {!canRun && clearHint && (
            <p style={{ margin: '10px 0 0', fontSize: 12, color: theme.warning, fontFamily: 'Inter, sans-serif' }}>{clearHint}</p>
          )}
          {err && <p style={{ margin: '12px 0 0', fontSize: 12, color: theme.danger, fontFamily: 'Inter, sans-serif' }}>{err}</p>}
          {ok && <p style={{ margin: '12px 0 0', fontSize: 12, color: theme.success, fontFamily: 'Inter, sans-serif' }}>{ok}</p>}
          <div style={{ display: 'flex', gap: 10, marginTop: 16, flexWrap: 'wrap' }}>
            <Btn theme={theme} kind="ghost" size="sm" onClick={() => !busy && setOpen(false)} disabled={busy}>Ocultar</Btn>
            <Btn theme={theme} kind="danger" size="sm" icon="trash" onClick={runClear} disabled={!canRun || busy}
              title={canRun ? '' : clearHint}>
              {busy ? 'Limpiando…' : 'Limpiar historial'}
            </Btn>
          </div>
        </div>
      )}
    </ConfigAccordionSection>
  );
};

const AdminFactoryResetPanel = ({ theme }) => {
  const [open, setOpen] = React.useState(false);
  const [password, setPassword] = React.useState('');
  const [confirmText, setConfirmText] = React.useState('');
  const [busy, setBusy] = React.useState(false);
  const [err, setErr] = React.useState('');
  const [ok, setOk] = React.useState('');

  const hasPassword = !!password.trim();
  const confirmOk = confirmText.trim().toUpperCase() === 'BORRAR TODO';
  const canRun = hasPassword && confirmOk;
  const factoryHint = !hasPassword && !confirmOk
    ? 'Completa contraseña y la frase BORRAR TODO en el segundo campo.'
    : !hasPassword
      ? 'Falta la contraseña de administrador.'
      : !confirmOk
        ? 'En el segundo campo escribe exactamente BORRAR TODO — no es tu contraseña.'
        : '';

  const runFactoryReset = async () => {
    if (!canRun) return;
    if (!window.confirm(
      'Última confirmación: se borrarán TODOS los alumnos, pagos, órdenes, inventario, galería, eventos, leads, nómina, gastos, notificaciones y archivos subidos. ¿Continuar?'
    )) return;
    setBusy(true);
    setErr('');
    setOk('');
    try {
      if (typeof verifyAdminSessionPassword !== 'function') {
        throw new Error('Verificación no disponible. Recarga la página.');
      }
      await verifyAdminSessionPassword(password);
      if (typeof adminFactoryReset !== 'function') {
        throw new Error('Reinicio no disponible. Ejecuta migración 068 en Supabase.');
      }
      await adminFactoryReset(confirmText);
      if (typeof saveAcademySettings === 'function' && typeof DEFAULT_ACADEMY_SETTINGS === 'object') {
        try {
          await saveAcademySettings({ ...DEFAULT_ACADEMY_SETTINGS });
        } catch (settingsErr) {
          console.warn('[Tecos] factory reset: academy settings', settingsErr);
        }
      }
      dispatchTecosDataRefresh();
      if (typeof window.clearInventoryResetUnlockedSession === 'function') window.clearInventoryResetUnlockedSession();
      setPassword('');
      setConfirmText('');
      setOpen(false);
      setOk('Reinicio completado. La academia quedó sin registros operativos; tu cuenta de administrador se conservó.');
    } catch (e) {
      setErr(e.message || 'No se pudo completar el reinicio.');
    }
    setBusy(false);
  };

  return (
    <ConfigAccordionSection
      theme={theme}
      variant="card"
      title="REINICIO TOTAL (ZONA PELIGROSA)"
      sub="Borra todos los datos de prueba o producción: alumnos, pagos, tienda, inventario, galería, eventos, finanzas, WhatsApp y archivos. No elimina tu cuenta admin."
      defaultOpen={false}
    >
      {!open ? (
        <Btn theme={theme} kind="ghost" size="sm" onClick={() => { setErr(''); setOk(''); setOpen(true); }}
          style={{ color: theme.danger, borderColor: `${theme.danger}55` }}>
          Mostrar opciones de reinicio total
        </Btn>
      ) : (
        <div style={{
          padding: 16, borderRadius: 12,
          border: `1px solid ${theme.danger}55`, background: `${theme.danger}0c`,
        }}>
          <p style={{ margin: '0 0 12px', fontSize: 13, color: theme.textDim, fontFamily: 'Inter, sans-serif', lineHeight: 1.55 }}>
            Esto es equivalente a <strong>empezar de cero</strong>: sin historial, sin registros en ningún módulo del panel.
            Se conservan tu sesión de administrador, las categorías base de galería/gastos y la fila de configuración (tarifas y textos del sitio se restauran a valores por defecto).
          </p>
          <ul style={{ margin: '0 0 14px', paddingLeft: 18, fontSize: 12, color: theme.textMute, fontFamily: 'Inter, sans-serif', lineHeight: 1.5 }}>
            <li>Alumnos, pagos, comprobantes, órdenes de tienda, productos e inventario</li>
            <li>Galería, eventos, avisos, coaches, leads interesados</li>
            <li>Nómina, gastos, retiros, notificaciones, WhatsApp (logs y campañas)</li>
            <li>Archivos en Storage (comprobantes, fotos, productos)</li>
            <li>Cuentas bancarias configuradas (deberás volver a darlas de alta)</li>
          </ul>
          <Input theme={theme} label="1. Contraseña de administrador" type="password" value={password}
            onChange={(e) => setPassword(e.target.value)} autoComplete="current-password"
            placeholder="Tu contraseña de sesión" />
          <div style={{ marginTop: 12 }}>
            <Input theme={theme} label="2. Confirmación (frase fija)" value={confirmText}
              onChange={(e) => setConfirmText(e.target.value)} autoComplete="off"
              placeholder="BORRAR TODO" spellCheck={false} />
          </div>
          {!canRun && factoryHint && (
            <p style={{ margin: '10px 0 0', fontSize: 12, color: theme.warning, fontFamily: 'Inter, sans-serif' }}>{factoryHint}</p>
          )}
          {err && <p style={{ margin: '12px 0 0', fontSize: 12, color: theme.danger, fontFamily: 'Inter, sans-serif' }}>{err}</p>}
          {ok && <p style={{ margin: '12px 0 0', fontSize: 12, color: theme.success, fontFamily: 'Inter, sans-serif' }}>{ok}</p>}
          <div style={{ display: 'flex', gap: 10, marginTop: 16, flexWrap: 'wrap' }}>
            <Btn theme={theme} kind="ghost" size="sm" onClick={() => !busy && setOpen(false)} disabled={busy}>Ocultar</Btn>
            <Btn theme={theme} kind="danger" size="sm" icon="trash" onClick={runFactoryReset} disabled={!canRun || busy}
              title={canRun ? '' : factoryHint}>
              {busy ? 'Borrando todo…' : 'Borrar todos los datos'}
            </Btn>
          </div>
        </div>
      )}
    </ConfigAccordionSection>
  );
};

const AdminWhatsAppCloudPanel = ({ theme, settings, onSaved }) => {
  const [url, setUrl] = React.useState('');
  const [saving, setSaving] = React.useState(false);
  const [err, setErr] = React.useState('');
  const [ok, setOk] = React.useState('');

  React.useEffect(() => {
    setUrl(String(settings?.wa_bridge_url || '').trim());
  }, [settings]);

  const save = async () => {
    setSaving(true);
    setErr('');
    setOk('');
    try {
      if (typeof saveAcademySettings !== 'function') throw new Error('Guardado no disponible.');
      await saveAcademySettings({
        ...(settings || {}),
        wa_bridge_url: url.trim(),
      });
      setOk('URL guardada. También puedes usar el secret WA_SERVICE_URL en Supabase (tiene prioridad).');
      if (typeof onSaved === 'function') onSaved();
    } catch (e) {
      setErr(e.message || 'No se pudo guardar.');
    }
    setSaving(false);
  };

  const cloudMode = typeof window !== 'undefined'
    && window.location.hostname !== 'localhost'
    && window.location.hostname !== '127.0.0.1';

  return (
    <ConfigAccordionSection
      theme={theme}
      variant="card"
      title="BOT WHATSAPP EN LA PÁGINA (NUBE)"
      sub="Para usar WhatsApp desde www.tecoseliteacademy.com sin npm en tu Mac."
      defaultOpen={cloudMode}
    >
      <p style={{ margin: '0 0 12px', fontSize: 13, color: theme.textDim, fontFamily: 'Inter, sans-serif', lineHeight: 1.55 }}>
        El panel en producción se conecta por <strong>Supabase Edge</strong> a un servidor que corre OpenWA 24/7 (Railway, VPS, etc.).
        Despliega <code>whatsapp-service</code>, pega aquí su URL HTTPS y ejecuta la migración <code>071</code> + función <code>wa-bridge</code>.
      </p>
      <ol style={{ margin: '0 0 14px', paddingLeft: 20, fontSize: 12, color: theme.textMute, fontFamily: 'Inter, sans-serif', lineHeight: 1.6 }}>
        <li>Railway: nuevo proyecto → Docker → carpeta <code>whatsapp-service</code></li>
        <li>Supabase → Edge Functions → deploy <code>wa-bridge</code> → Secret <code>WA_SERVICE_URL</code> = misma URL</li>
        <li>Admin → WhatsApp → Dashboard → escanear QR</li>
      </ol>
      <Input theme={theme} label="URL del servicio WhatsApp (HTTPS)" placeholder="https://tu-bot.up.railway.app"
        value={url} onChange={(e) => setUrl(e.target.value)} icon="wa" />
      {err && <p style={{ margin: '10px 0 0', fontSize: 12, color: theme.danger, fontFamily: 'Inter, sans-serif' }}>{err}</p>}
      {ok && <p style={{ margin: '10px 0 0', fontSize: 12, color: theme.success, fontFamily: 'Inter, sans-serif' }}>{ok}</p>}
      <Btn theme={theme} size="sm" style={{ marginTop: 12 }} onClick={save} disabled={saving}>
        {saving ? 'Guardando…' : 'Guardar URL del bot'}
      </Btn>
    </ConfigAccordionSection>
  );
};

const AdminAccountSettingsForm = ({ theme }) => {
  const { data: profile, loading, reload } = useLiveData(() => fetchMyProfile(), []);
  const [fullName, setFullName] = React.useState('');
  const [email, setEmail] = React.useState('');
  const [newPassword, setNewPassword] = React.useState('');
  const [confirmPassword, setConfirmPassword] = React.useState('');
  const [saving, setSaving] = React.useState('');
  const [err, setErr] = React.useState('');
  const [ok, setOk] = React.useState('');

  React.useEffect(() => {
    if (profile) {
      setFullName(profile.full_name || '');
      setEmail(profile.email || '');
    }
  }, [profile]);

  const run = async (key, fn) => {
    setSaving(key);
    setErr('');
    setOk('');
    try {
      await fn();
      setOk('Cambios guardados correctamente.');
      reload();
      window.dispatchEvent(new CustomEvent('tecos:admin-profile-changed'));
    } catch (e) {
      setErr(e.message || 'No se pudo guardar.');
    }
    setSaving('');
  };

  return (
    <ConfigAccordionSection
      theme={theme}
      variant="card"
      title="CUENTA ADMINISTRADOR"
      sub="Nombre visible en el panel, correo de acceso y contraseña (Supabase Auth)."
    >
      {loading ? <LoadingBlock theme={theme} label="Cargando perfil…" /> : (
        <>
          <div style={{ display: 'grid', gridTemplateColumns: '1fr auto', gap: 12, alignItems: 'end', marginBottom: 16 }}>
            <Input theme={theme} label="Nombre en el panel" placeholder="Ej. Carlos Méndez" icon="user"
              value={fullName} onChange={e => setFullName(e.target.value)} />
            <Btn theme={theme} size="sm" onClick={() => run('name', () => updateAdminProfileName(fullName))} disabled={saving === 'name'}>
              {saving === 'name' ? 'Guardando…' : 'Guardar nombre'}
            </Btn>
          </div>
          <div style={{ display: 'grid', gridTemplateColumns: '1fr auto', gap: 12, alignItems: 'end', marginBottom: 12 }}>
            <Input theme={theme} label="Correo de acceso" type="email" placeholder="admin@tecoselite.mx" icon="user"
              value={email} onChange={e => setEmail(e.target.value)} />
            <Btn theme={theme} size="sm" onClick={() => run('email', () => updateAdminAuthEmail(email))} disabled={saving === 'email'}>
              {saving === 'email' ? 'Guardando…' : 'Cambiar correo'}
            </Btn>
          </div>
          <p style={{ fontSize: 11, color: theme.textMute, margin: '0 0 16px', fontFamily: 'Inter, sans-serif' }}>
            Al cambiar el correo, Supabase puede pedir confirmación en el nuevo email antes de activarlo.
          </p>
          <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr auto', gap: 12, alignItems: 'end' }}>
            <Input theme={theme} label="Nueva contraseña" type="password" placeholder="Mínimo 8 caracteres" icon="settings"
              value={newPassword} onChange={e => setNewPassword(e.target.value)} />
            <Input theme={theme} label="Confirmar contraseña" type="password" placeholder="Repite la contraseña" icon="settings"
              value={confirmPassword} onChange={e => setConfirmPassword(e.target.value)} />
            <Btn theme={theme} size="sm" onClick={() => {
              if (newPassword !== confirmPassword) { setErr('Las contraseñas no coinciden.'); return; }
              run('password', async () => {
                await updateAdminAuthPassword(newPassword);
                setNewPassword('');
                setConfirmPassword('');
              });
            }} disabled={saving === 'password'}>
              {saving === 'password' ? 'Guardando…' : 'Cambiar contraseña'}
            </Btn>
          </div>
        </>
      )}
      {err && <div style={{ color: theme.danger, fontSize: 13, marginTop: 12, fontFamily: 'Inter, sans-serif' }}>{err}</div>}
      {ok && <div style={{ color: theme.success, fontSize: 13, marginTop: 12, fontFamily: 'Inter, sans-serif' }}>{ok}</div>}
      <div style={{ marginTop: 20, display: 'grid', gap: 16 }}>
        <AdminClearBillingHistoryPanel theme={theme} />
        <AdminFactoryResetPanel theme={theme} />
      </div>
    </ConfigAccordionSection>
  );
};

/** Resumen rápido de tarifas activas (parte superior de Configuración). */
const ConfigTariffSummary = ({ theme, settings }) => {
  const s = typeof normalizeAcademySettings === 'function' ? normalizeAcademySettings(settings) : settings;
  if (!s) return null;
  const base = Number(s.monthly_fee) || 0;
  const fmt = (n) => (typeof formatMoneyMX === 'function' ? formatMoneyMX(n) : n);
  const chips = [
    {
      label: 'Tarifa base',
      value: `$${fmt(base)} MXN`,
      color: theme.primary,
    },
    {
      label: 'Sin recargo',
      value: typeof formatDayRangeLabel === 'function'
        ? formatDayRangeLabel(s.billing_period_start_day, s.billing_period_end_day)
        : `Días ${s.billing_period_start_day}–${s.billing_period_end_day}`,
      color: theme.success,
    },
    {
      label: 'Recargo 1',
      value: `${typeof formatDayRangeLabel === 'function' ? formatDayRangeLabel(s.overdue_from_day, s.late_until_day) : `Días ${s.overdue_from_day}–${s.late_until_day}`} · +${s.late_fee_percent}%`,
      color: theme.warning,
    },
    {
      label: 'Recargo 2',
      value: `${typeof formatDayRangeLabel === 'function' ? formatDayRangeLabel(s.severe_late_from_day, s.severe_late_until_day) : `Días ${s.severe_late_from_day}–${s.severe_late_until_day}`} · +${s.severe_late_fee_percent}%`,
      color: theme.danger,
    },
  ];
  return (
    <div style={{
      marginBottom: 20,
      padding: '20px 24px',
      borderRadius: 14,
      background: `linear-gradient(135deg, ${theme.primary}18 0%, ${theme.bgCard} 55%)`,
      border: `1px solid ${theme.primary}44`,
      display: 'grid',
      gap: 16,
    }}>
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 12, flexWrap: 'wrap' }}>
        <div>
          <div style={{ fontSize: 10, letterSpacing: 2, fontWeight: 700, textTransform: 'uppercase', color: theme.primary, fontFamily: 'Inter, sans-serif' }}>
            Tarifas en vigor
          </div>
          <div style={{ fontFamily: 'Bebas Neue, sans-serif', fontSize: 36, color: theme.text, letterSpacing: 1, lineHeight: 1.1, marginTop: 4 }}>
            ${fmt(base)} <span style={{ fontSize: 18, color: theme.textDim, fontFamily: 'Inter, sans-serif', fontWeight: 600 }}>mensualidad</span>
          </div>
        </div>
        <Icon name="money" size={40} color={theme.primary} />
      </div>
      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(160px, 1fr))', gap: 10 }}>
        {chips.map((c) => (
          <div key={c.label} style={{
            padding: '12px 14px',
            borderRadius: 10,
            background: theme.bgElev,
            border: `1px solid ${theme.border}`,
            borderLeft: `4px solid ${c.color}`,
          }}>
            <div style={{ fontSize: 10, fontWeight: 700, letterSpacing: 1, textTransform: 'uppercase', color: theme.textMute, fontFamily: 'Inter, sans-serif' }}>{c.label}</div>
            <div style={{ fontSize: 13, fontWeight: 600, color: theme.text, marginTop: 4, fontFamily: 'Inter, sans-serif' }}>{c.value}</div>
          </div>
        ))}
      </div>
      <BillingTierBar theme={theme} form={s} />
    </div>
  );
};

/** Barra visual de tramos por día del mes (1–31). */
const BillingTierBar = ({ theme, form }) => {
  const s = typeof normalizeAcademySettings === 'function' ? normalizeAcademySettings(form) : form;
  const colorForDay = (day) => {
    if (typeof getBillingTierForDate !== 'function' || typeof dateWithDayOfMonth !== 'function') {
      return theme.textMute;
    }
    const tier = getBillingTierForDate(s, dateWithDayOfMonth(day));
    if (tier.tier === 'normal') return theme.success;
    if (tier.tier === 'late') return theme.warning;
    return theme.danger;
  };
  const legend = [
    { label: 'Sin recargo', bg: theme.success, range: formatDayRangeLabel?.(s.billing_period_start_day, s.billing_period_end_day) },
    { label: `Recargo 1 (+${s.late_fee_percent}%)`, bg: theme.warning, range: formatDayRangeLabel?.(s.overdue_from_day, s.late_until_day) },
    { label: `Recargo 2 (+${s.severe_late_fee_percent}%)`, bg: theme.danger, range: formatDayRangeLabel?.(s.severe_late_from_day, s.severe_late_until_day) },
  ];
  return (
    <div>
      <div style={{ fontSize: 10, fontWeight: 700, letterSpacing: 1, textTransform: 'uppercase', color: theme.textMute, marginBottom: 8, fontFamily: 'Inter, sans-serif' }}>
        Calendario del mes (día 1 → 31) — prioridad: sin recargo, luego 2.º recargo, luego 1.er recargo
      </div>
      <div style={{ display: 'flex', height: 28, borderRadius: 8, overflow: 'hidden', border: `1px solid ${theme.border}` }}>
        {Array.from({ length: 31 }, (_, i) => {
          const day = i + 1;
          const bg = colorForDay(day);
          const tier = typeof getBillingTierForDate === 'function' ? getBillingTierForDate(s, dateWithDayOfMonth(day)) : null;
          return (
            <div
              key={day}
              title={`Día ${day}: ${tier?.label || '—'}`}
              style={{
                flex: 1,
                minWidth: 2,
                background: `${bg}99`,
                borderRight: day < 31 ? `1px solid ${theme.bgCard}` : 'none',
              }}
            />
          );
        })}
      </div>
      <div style={{ display: 'flex', gap: 16, marginTop: 8, flexWrap: 'wrap', fontSize: 11, color: theme.textDim, fontFamily: 'Inter, sans-serif' }}>
        {legend.map((seg) => (
          <span key={seg.label} style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
            <span style={{ width: 10, height: 10, borderRadius: 2, background: seg.bg }} />
            {seg.range}: {seg.label}
          </span>
        ))}
      </div>
    </div>
  );
};

const BillingCalculationTable = ({ theme, form }) => {
  const base = Number(form.monthly_fee) || 0;
  const rows = typeof getBillingPreviewRows === 'function' ? getBillingPreviewRows(form, base) : [];
  const overlap = typeof billingConfigOverlapWarning === 'function' ? billingConfigOverlapWarning(form) : '';
  const todayRow = rows.find(r => r.isToday);

  const thStyle = {
    textAlign: 'left', padding: '10px 12px', fontSize: 10, fontWeight: 700,
    letterSpacing: 1, textTransform: 'uppercase', color: theme.textMute,
    borderBottom: `1px solid ${theme.border}`, fontFamily: 'Inter, sans-serif',
  };
  const tdStyle = {
    padding: '12px', fontSize: 12, color: theme.textDim,
    borderBottom: `1px solid ${theme.border}`, fontFamily: 'Inter, sans-serif', verticalAlign: 'top',
  };

  return (
    <div>
      <p style={{ fontSize: 12, color: theme.textDim, margin: '0 0 12px', fontFamily: 'Inter, sans-serif', lineHeight: 1.5 }}>
        Al registrar o ver un pago, el monto se calcula con la <strong>tarifa base</strong> del alumno y el <strong>día del mes</strong> en que se consulta o cobra.
        Los totales de abajo coinciden con Ventas y pagos y el portal del alumno.
      </p>
      {overlap && (
        <div style={{ marginBottom: 12, padding: 12, borderRadius: 8, background: `${theme.danger}18`, border: `1px solid ${theme.danger}44`, color: theme.danger, fontSize: 12, fontFamily: 'Inter, sans-serif' }}>
          {overlap}
        </div>
      )}
      <div className="tecos-table-scroll" style={{ overflowX: 'auto', borderRadius: 10, border: `1px solid ${theme.border}` }}>
        <table style={{ width: '100%', borderCollapse: 'collapse', minWidth: 640 }}>
          <thead>
            <tr style={{ background: theme.bgInput }}>
              <th style={thStyle}>Día del mes</th>
              <th style={thStyle}>Tramo</th>
              <th style={thStyle}>Cálculo</th>
              <th style={thStyle}>Base</th>
              <th style={thStyle}>Recargo</th>
              <th style={thStyle}>Total</th>
            </tr>
          </thead>
          <tbody>
            {rows.map(r => (
              <tr key={r.day} style={{
                background: r.isToday ? `${theme.primary}14` : 'transparent',
              }}>
                <td style={{ ...tdStyle, color: theme.text, fontWeight: r.isToday ? 700 : 400 }}>
                  Día {r.day}{r.isToday ? ' (hoy)' : ''}
                </td>
                <td style={tdStyle}>
                  <div style={{ color: theme.text, fontWeight: 600 }}>{r.tierLabel}</div>
                  <div style={{ fontSize: 11, marginTop: 2 }}>{r.tramo}</div>
                </td>
                <td style={{ ...tdStyle, lineHeight: 1.6, maxWidth: 280 }}>
                  {r.surchargeLines?.length ? r.surchargeLines.map((l, i) => (
                    <div key={i}>{l.label}: ${formatMoneyMX ? formatMoneyMX(l.amount) : l.amount}</div>
                  )) : (
                    <span>Sin recargo</span>
                  )}
                  <div style={{ marginTop: 6, color: theme.text, fontSize: 11 }}>{r.formula}</div>
                </td>
                <td style={{ ...tdStyle, color: theme.text }}>${formatMoneyMX ? formatMoneyMX(r.base) : r.base}</td>
                <td style={{ ...tdStyle, color: r.surcharge > 0 ? theme.warning : theme.textMute }}>
                  {r.surcharge > 0 ? `+$${formatMoneyMX ? formatMoneyMX(r.surcharge) : r.surcharge}` : '$0'}
                </td>
                <td style={{ ...tdStyle, color: theme.text, fontWeight: 700, fontSize: 13 }}>
                  ${formatMoneyMX ? formatMoneyMX(r.total) : r.total}
                </td>
              </tr>
            ))}
          </tbody>
        </table>
      </div>
      {todayRow && (
        <div style={{ marginTop: 12, padding: 12, borderRadius: 8, background: theme.bgInput, border: `1px solid ${theme.border}`, fontSize: 12, color: theme.textDim, fontFamily: 'Inter, sans-serif' }}>
          <strong style={{ color: theme.text }}>Hoy (día {todayRow.day}):</strong> {todayRow.formula}
          <div style={{ marginTop: 4 }}>
            Fecha límite al crear pago este mes: <strong style={{ color: theme.text }}>{defaultPaymentDueDate(form)}</strong>
            {' '}(último día sin recargo: día {form.billing_period_end_day})
          </div>
        </div>
      )}
    </div>
  );
};

const BillingSettingsForm = ({ theme, settings, onSaved }) => {
  const [form, setForm] = React.useState(settings || DEFAULT_ACADEMY_SETTINGS);
  const [saving, setSaving] = React.useState(false);
  const [err, setErr] = React.useState('');
  const [ok, setOk] = React.useState('');

  React.useEffect(() => { if (settings) setForm(settings); }, [settings]);

  const setNum = (k) => (e) => setForm(f => ({ ...f, [k]: e.target.value }));

  const billingRanges = React.useMemo(() => {
    if (typeof formatDayRangeLabel !== 'function') return null;
    return {
      normal: formatDayRangeLabel(form.billing_period_start_day, form.billing_period_end_day),
      late1: formatDayRangeLabel(form.overdue_from_day, form.late_until_day),
      late2: formatDayRangeLabel(form.severe_late_from_day, form.severe_late_until_day),
    };
  }, [form]);

  const save = async () => {
    setSaving(true); setErr(''); setOk('');
    const validation = typeof validateBillingSettings === 'function' ? validateBillingSettings(form) : '';
    if (validation) { setErr(validation); setSaving(false); return; }
    try {
      await saveAcademySettings(form);
      notifySettingsChanged();
      setOk('Tarifas guardadas. Ventas y pagos usarán estos tramos por día del mes.');
      onSaved?.();
    } catch (e) { setErr(e.message); }
    setSaving(false);
  };

  return (
    <ConfigAccordionSection
      theme={theme}
      variant="card"
      defaultOpen
      title="TARIFAS Y MENSUALIDAD"
      sub="Define tres rangos de días (1–31) para la mensualidad sin recargo, el primer recargo y el segundo. Admin, ventas y portal del alumno usan la misma regla."
    >
      <div style={{
        marginBottom: 16, padding: 14, borderRadius: 10,
        background: `${theme.info}10`, border: `1px solid ${theme.info}33`,
        fontSize: 12, color: theme.textDim, fontFamily: 'Inter, sans-serif', lineHeight: 1.6,
      }}>
        <div style={{ fontWeight: 700, color: theme.text, marginBottom: 8, fontSize: 13 }}>¿Cómo funciona el cobro?</div>
        <p style={{ margin: '0 0 10px' }}>
          El total de la mensualidad depende del <strong style={{ color: theme.text }}>día del calendario</strong> en que registras el pago o el alumno consulta su adeudo:
          hoy para el mes en curso, el último día del mes para meses ya vencidos y la tarifa base (sin recargo) en adelantos de meses futuros.
        </p>
        {billingRanges && (
          <p style={{ margin: '0 0 10px' }}>
            <strong style={{ color: theme.text }}>Con tu configuración actual:</strong>{' '}
            sin recargo <strong style={{ color: theme.text }}>{billingRanges.normal}</strong>
            {' · '}primer recargo (+{form.late_fee_percent}%) <strong style={{ color: theme.text }}>{billingRanges.late1}</strong>
            {' · '}segundo recargo (+{form.severe_late_fee_percent}%) <strong style={{ color: theme.text }}>{billingRanges.late2}</strong>.
          </p>
        )}
        <ul style={{ margin: 0, paddingLeft: 18 }}>
          <li style={{ marginBottom: 6 }}>
            Los rangos <strong style={{ color: theme.text }}>no tienen que ser seguidos</strong>: puedes dejar huecos entre tramos o repartir el mes como prefiera la academia.
          </li>
          <li style={{ marginBottom: 6 }}>
            Si «desde» es mayor que «hasta» (por ejemplo del 24 al 5), el tramo <strong style={{ color: theme.text }}>cruza fin de mes</strong>: cuenta del día 24 al 31 y del 1 al 5.
          </li>
          <li>
            Si un mismo día cae en más de un tramo, se aplica en este orden: <strong style={{ color: theme.text }}>sin recargo</strong>, luego <strong style={{ color: theme.text }}>segundo recargo</strong>, luego <strong style={{ color: theme.text }}>primer recargo</strong>.
          </li>
        </ul>
      </div>
      <ConfigTariffSummary theme={theme} settings={form} />
      <div style={{ marginBottom: 20, padding: 20, borderRadius: 12, background: `${theme.primary}14`, border: `2px solid ${theme.primary}44` }}>
        <Input theme={theme} label="Tarifa base / mensualidad (MXN)" type="number" min={0} step="0.01"
          value={form.monthly_fee} onChange={setNum('monthly_fee')} icon="money" />
        <p style={{ margin: '10px 0 0', fontSize: 12, color: theme.textDim, fontFamily: 'Inter, sans-serif', lineHeight: 1.5 }}>
          Monto de referencia para cada alumno. Los recargos se calculan como porcentaje sobre esta cantidad.
        </p>
      </div>

      <ConfigAccordionSection theme={theme} variant="inner" title="1 · Mensualidad sin recargo"
        sub="Rango de días del mes (1–31) con tarifa base completa. Si el inicio es mayor que el fin, cruza fin de mes (ej. 24 al 5)."
        defaultOpen>
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12, maxWidth: 360 }}>
          <Input theme={theme} label="Sin recargo — desde el día" type="number" min={1} max={31} value={form.billing_period_start_day}
            onChange={setNum('billing_period_start_day')} icon="cal" />
          <Input theme={theme} label="Sin recargo — hasta el día" type="number" min={1} max={31} value={form.billing_period_end_day}
            onChange={setNum('billing_period_end_day')} icon="cal" />
        </div>
      </ConfigAccordionSection>

      <ConfigAccordionSection theme={theme} variant="inner" title="2 · Primer recargo"
        sub="Elige de qué día a qué día aplica el primer recargo (% sobre la mensualidad).">
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', gap: 12 }}>
          <Input theme={theme} label="Primer recargo — desde el día" type="number" min={1} max={31} value={form.overdue_from_day}
            onChange={setNum('overdue_from_day')} icon="warning" />
          <Input theme={theme} label="Primer recargo — hasta el día" type="number" min={1} max={31} value={form.late_until_day}
            onChange={setNum('late_until_day')} icon="warning" />
          <Input theme={theme} label="Recargo (%)" type="number" min={0} max={100} step="0.01" value={form.late_fee_percent}
            onChange={setNum('late_fee_percent')} />
        </div>
      </ConfigAccordionSection>

      <ConfigAccordionSection theme={theme} variant="inner" title="3 · Segundo recargo adicional"
        sub="Elige de qué día a qué día aplica el segundo recargo (% adicional sobre la mensualidad).">
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', gap: 12 }}>
          <Input theme={theme} label="Segundo recargo — desde el día" type="number" min={1} max={31} value={form.severe_late_from_day}
            onChange={setNum('severe_late_from_day')} icon="warning" />
          <Input theme={theme} label="Segundo recargo — hasta el día" type="number" min={1} max={31} value={form.severe_late_until_day}
            onChange={setNum('severe_late_until_day')} icon="warning" />
          <Input theme={theme} label="Recargo extra (%)" type="number" min={0} max={100} step="0.01"
            value={form.severe_late_fee_percent} onChange={setNum('severe_late_fee_percent')} />
        </div>
      </ConfigAccordionSection>

      <ConfigAccordionSection theme={theme} variant="inner" title="Tabla de totales (vista previa)"
        sub="Misma lógica que Ventas y pagos y el portal del alumno.">
        <BillingCalculationTable theme={theme} form={form} />
      </ConfigAccordionSection>

      {err && <div style={{ color: theme.danger, fontSize: 13, marginTop: 12 }}>{err}</div>}
      {ok && <div style={{ color: theme.success, fontSize: 13, marginTop: 12 }}>{ok}</div>}
      <div style={{ marginTop: 16, display: 'flex', justifyContent: 'flex-end' }}>
        <Btn theme={theme} icon="check" onClick={save} disabled={saving}>{saving ? 'Guardando…' : 'Guardar tarifas'}</Btn>
      </div>
    </ConfigAccordionSection>
  );
};

const StatRowEditor = ({ theme, form, set, title, vKey, sKey, lKey, suffixHint }) => (
  <div style={{ display: 'grid', gridTemplateColumns: '120px 1fr 80px 1fr', gap: 10, alignItems: 'end', marginBottom: 10 }}>
    <div style={{ fontSize: 12, fontWeight: 600, color: theme.textDim, fontFamily: 'Inter, sans-serif', paddingBottom: 10 }}>{title}</div>
    <Input theme={theme} label="Número" placeholder="8" value={form[vKey] || ''} onChange={set(vKey)} />
    <Input theme={theme} label="Sufijo" placeholder={suffixHint || '%'} value={form[sKey] || ''} onChange={set(sKey)} />
    <Input theme={theme} label="Etiqueta" placeholder="Productos" value={form[lKey] || ''} onChange={set(lKey)} />
  </div>
);

const SitePublicSettingsForm = ({ theme, settings, onSaved }) => {
  const [form, setForm] = React.useState(settings || DEFAULT_ACADEMY_SETTINGS);
  const [siteTab, setSiteTab] = React.useState('landing');
  const [saving, setSaving] = React.useState(false);
  const [err, setErr] = React.useState('');
  const [ok, setOk] = React.useState('');

  React.useEffect(() => { if (settings) setForm(settings); }, [settings]);

  const set = (k) => (e) => setForm(f => ({ ...f, [k]: e.target.value }));

  const save = async () => {
    setSaving(true); setErr(''); setOk('');
    try {
      await saveAcademySettings(form);
      notifySettingsChanged();
      setOk(siteTab === 'tienda' ? 'Tienda (tienda.html) guardada.' : 'Landing (index.html) guardada.');
      onSaved?.();
    } catch (e) { setErr(e.message); }
    setSaving(false);
  };

  const tabBtn = (id, label) => (
    <button type="button" key={id} onClick={() => setSiteTab(id)} style={{
      padding: '10px 18px', borderRadius: 8, border: `1px solid ${siteTab === id ? theme.primary : theme.border}`,
      background: siteTab === id ? `${theme.primary}18` : theme.bgInput,
      color: siteTab === id ? theme.primary : theme.textDim,
      fontSize: 13, fontWeight: 700, cursor: 'pointer', fontFamily: 'Inter, sans-serif',
    }}>{label}</button>
  );

  return (
    <ConfigAccordionSection
      theme={theme}
      variant="card"
      title="SITIO WEB PÚBLICO"
      sub="Elige la página y edita solo su contenido. El footer de contacto se comparte entre landing y tienda."
    >
      <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap', marginBottom: 20 }}>
        {tabBtn('landing', 'Landing (index.html)')}
        {tabBtn('tienda', 'Tienda (tienda.html)')}
      </div>

      {siteTab === 'landing' && (
      <>
      <ConfigAccordionSection theme={theme} variant="inner" title="Inicio (hero)"
        sub="Título principal, subtítulo y etiqueta superior de la landing.">
      <Input theme={theme} label="Etiqueta superior" placeholder="Temporada 2026 abierta" value={form.hero_badge || ''} onChange={set('hero_badge')} />
      <p style={{ fontSize: 11, color: theme.textMute, margin: '12px 0 8px', fontFamily: 'Inter, sans-serif' }}>
        Título principal (3 líneas; la línea 2 lleva el color degradado en la landing).
      </p>
      <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', gap: 12, marginBottom: 12 }}>
        <Input theme={theme} label="Línea 1" placeholder="DONDE NACEN" value={form.hero_title_line1 || ''} onChange={set('hero_title_line1')} />
        <Input theme={theme} label="Línea 2 (destacada)" placeholder="LOS CAMPEONES" value={form.hero_title_line2 || ''} onChange={set('hero_title_line2')} />
        <Input theme={theme} label="Línea 3" placeholder="DEL VOLLEYBALL" value={form.hero_title_line3 || ''} onChange={set('hero_title_line3')} />
      </div>
      <textarea value={form.hero_subtitle || ''} onChange={set('hero_subtitle')} rows={3} placeholder="Academia profesional de VOLLEYBALL…" style={{
        width: '100%', padding: 12, borderRadius: 10, border: `1px solid ${theme.border}`,
        background: theme.bgInput, color: theme.text, fontFamily: 'Inter, sans-serif', fontSize: 14,
        resize: 'vertical', marginBottom: 12, boxSizing: 'border-box',
      }} />
      <p style={{ fontSize: 11, color: theme.textMute, margin: '0 0 0', fontFamily: 'Inter, sans-serif' }}>
        Los iconos de Facebook y WhatsApp bajo este texto usan los mismos enlaces de la sección Contacto (abajo).
      </p>
      </ConfigAccordionSection>

      <ConfigAccordionSection theme={theme} variant="inner" title="Contadores del hero"
        sub="Números y etiquetas bajo el título principal.">
      {[
        { vKey: 'hero_stat_alumni_value', lKey: 'hero_stat_alumni_label', title: 'Alumnos', sk: null },
        { vKey: 'hero_stat_coaches_value', lKey: 'hero_stat_coaches_label', title: 'Entrenadores', sk: null },
        { vKey: 'hero_stat_categories_value', lKey: 'hero_stat_categories_label', title: 'Categorías', sk: null },
        { vKey: 'hero_stat_trophies_value', lKey: 'hero_stat_trophies_label', title: 'Trofeos', sk: null },
      ].map(row => (
        <div key={row.vKey} style={{ display: 'grid', gridTemplateColumns: '120px 1fr 1fr', gap: 10, alignItems: 'end', marginBottom: 10 }}>
          <div style={{ fontSize: 12, fontWeight: 600, color: theme.textDim, fontFamily: 'Inter, sans-serif', paddingBottom: 10 }}>{row.title}</div>
          <Input theme={theme} label="Número" placeholder="320+" value={form[row.vKey] || ''} onChange={set(row.vKey)} />
          <Input theme={theme} label="Etiqueta" placeholder="Alumnos activos" value={form[row.lKey] || ''} onChange={set(row.lKey)} />
        </div>
      ))}
      </ConfigAccordionSection>

      <ConfigAccordionSection theme={theme} variant="inner" title="Contacto y redes (footer + hero)"
        sub="Teléfono, correo, dirección y enlaces sociales.">
      <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12, marginBottom: 16 }}>
        <Input theme={theme} label="Teléfono" placeholder="+52 33 1234 5678" icon="wa" value={form.contact_phone || ''} onChange={set('contact_phone')} />
        <Input theme={theme} label="Correo" placeholder="contacto@tecoselite.mx" value={form.contact_email || ''} onChange={set('contact_email')} />
        <Input theme={theme} label="Dirección (línea 1)" placeholder="Av. Universidad #1234" icon="pin" value={form.footer_address_line1 || ''} onChange={set('footer_address_line1')} />
        <Input theme={theme} label="Dirección (línea 2)" placeholder="Guadalajara, Jal." value={form.footer_address_line2 || ''} onChange={set('footer_address_line2')} />
        <Input theme={theme} label="Facebook (URL)" placeholder="https://facebook.com/..." icon="facebook" value={form.facebook_url || ''} onChange={set('facebook_url')} />
        <Input theme={theme} label="WhatsApp (teléfono)" placeholder="+52 33 1234 5678" icon="wa" value={form.whatsapp_phone || ''} onChange={set('whatsapp_phone')} />
        <div style={{ gridColumn: '1 / -1' }}>
          <Input theme={theme} label="WhatsApp (enlace)" placeholder="https://wa.me/523312345678" icon="wa" value={form.whatsapp_url || ''} onChange={set('whatsapp_url')} />
          <p style={{ fontSize: 11, color: theme.textMute, margin: '6px 0 0', fontFamily: 'Inter, sans-serif' }}>
            Si lo dejas vacío, se genera automáticamente desde el teléfono de WhatsApp.
          </p>
        </div>
      </div>
      </ConfigAccordionSection>

      <ConfigAccordionSection theme={theme} variant="inner" title="Texto bajo el logo (footer landing)"
        sub="Frase descriptiva en el pie de la landing.">
      <textarea value={form.footer_tagline || ''} onChange={set('footer_tagline')} rows={3} placeholder="Academia profesional de VOLLEYBALL…" style={{
        width: '100%', padding: 12, borderRadius: 10, border: `1px solid ${theme.border}`,
        background: theme.bgInput, color: theme.text, fontFamily: 'Inter, sans-serif', fontSize: 14,
        resize: 'vertical', marginBottom: 0, boxSizing: 'border-box',
      }} />
      </ConfigAccordionSection>

      <ConfigAccordionSection theme={theme} variant="inner" title="Pie de página (copyright)"
        sub="Texto y enlace del copyright.">
      <Input theme={theme} label="Texto copyright" value={form.footer_copyright_text || ''} onChange={set('footer_copyright_text')} />
      <div style={{ marginTop: 12, marginBottom: 16 }}>
        <Input theme={theme} label="Enlace copyright (opcional)" placeholder="https://..." value={form.footer_copyright_url || ''} onChange={set('footer_copyright_url')} />
      </div>
      </ConfigAccordionSection>

      <ConfigAccordionSection theme={theme} variant="inner" title="Crédito del sitio"
        sub="Enlace al desarrollador o estudio (ej. diseñador.html).">
      <Input theme={theme} label="Texto" value={form.footer_credit_text || ''} onChange={set('footer_credit_text')} />
      <div style={{ marginTop: 12, marginBottom: 8 }}>
        <Input theme={theme} label="Enlace" placeholder="diseñador.html" value={form.footer_credit_url || ''} onChange={set('footer_credit_url')} />
      </div>
      </ConfigAccordionSection>
      </>
      )}

      {siteTab === 'tienda' && (
      <>
      <ConfigAccordionSection theme={theme} variant="inner" title="Hero de la tienda"
        sub="Título, descripción y etiqueta de tienda.html.">
      <Input theme={theme} label="Etiqueta superior" placeholder="Equipo oficial · Temporada 2026" value={form.tienda_hero_badge || ''} onChange={set('tienda_hero_badge')} />
      <p style={{ fontSize: 11, color: theme.textMute, margin: '12px 0 8px', fontFamily: 'Inter, sans-serif' }}>
        Título (línea 2 con degradado, ej. OFICIAL).
      </p>
      <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12, marginBottom: 12 }}>
        <Input theme={theme} label="Línea 1" placeholder="TIENDA" value={form.tienda_hero_title_line1 || ''} onChange={set('tienda_hero_title_line1')} />
        <Input theme={theme} label="Línea 2 (destacada)" placeholder="OFICIAL" value={form.tienda_hero_title_line2 || ''} onChange={set('tienda_hero_title_line2')} />
      </div>
      <Input theme={theme} label="Descripción línea 1" value={form.tienda_hero_subtitle_line1 || ''} onChange={set('tienda_hero_subtitle_line1')} />
      <div style={{ marginTop: 12, marginBottom: 12 }}>
        <Input theme={theme} label="Descripción línea 2" value={form.tienda_hero_subtitle_line2 || ''} onChange={set('tienda_hero_subtitle_line2')} />
      </div>
      </ConfigAccordionSection>

      <ConfigAccordionSection theme={theme} variant="inner" title="Contadores del hero (tienda)"
        sub="Productos, categorías, entrega y oficial.">
      <StatRowEditor theme={theme} form={form} set={set} title="Productos" vKey="tienda_stat_products_value" sKey="tienda_stat_products_suffix" lKey="tienda_stat_products_label" />
      <StatRowEditor theme={theme} form={form} set={set} title="Categorías" vKey="tienda_stat_categories_value" sKey="tienda_stat_categories_suffix" lKey="tienda_stat_categories_label" />
      <StatRowEditor theme={theme} form={form} set={set} title="Entrega" vKey="tienda_stat_delivery_value" sKey="tienda_stat_delivery_suffix" lKey="tienda_stat_delivery_label" suffixHint="h" />
      <StatRowEditor theme={theme} form={form} set={set} title="Oficial" vKey="tienda_stat_official_value" sKey="tienda_stat_official_suffix" lKey="tienda_stat_official_label" suffixHint="%" />
      </ConfigAccordionSection>

      <ConfigAccordionSection theme={theme} variant="inner" title="Garantías y beneficios"
        sub="Cuatro tarjetas bajo el hero de la tienda.">
      {[1, 2, 3, 4].map(n => (
        <div key={n} style={{ marginBottom: 14, padding: 14, borderRadius: 10, border: `1px solid ${theme.border}`, background: theme.bgInput }}>
          <div style={{ fontSize: 12, fontWeight: 700, color: theme.text, marginBottom: 10, fontFamily: 'Inter, sans-serif' }}>Tarjeta {n}</div>
          <Input theme={theme} label="Título" value={form[`tienda_guarantee_${n}_title`] || ''} onChange={set(`tienda_guarantee_${n}_title`)} />
          <div style={{ marginTop: 10 }}>
            <textarea value={form[`tienda_guarantee_${n}_desc`] || ''} onChange={set(`tienda_guarantee_${n}_desc`)} rows={2} placeholder="Descripción…" style={{
              width: '100%', padding: 12, borderRadius: 10, border: `1px solid ${theme.border}`,
              background: theme.bgElev, color: theme.text, fontFamily: 'Inter, sans-serif', fontSize: 14,
              resize: 'vertical', boxSizing: 'border-box',
            }} />
          </div>
        </div>
      ))}
      <p style={{ fontSize: 11, color: theme.textMute, margin: '12px 0 0', fontFamily: 'Inter, sans-serif' }}>
        El footer de tienda.html usa los mismos datos de contacto, redes y copyright de la pestaña Landing.
      </p>
      </ConfigAccordionSection>
      </>
      )}

      {err && <div style={{ color: theme.danger, fontSize: 13, marginTop: 12, fontFamily: 'Inter, sans-serif' }}>{err}</div>}
      {ok && <div style={{ color: theme.success, fontSize: 13, marginTop: 12, fontFamily: 'Inter, sans-serif' }}>{ok}</div>}
      <div style={{ marginTop: 16, display: 'flex', justifyContent: 'flex-end' }}>
        <Btn theme={theme} icon="check" onClick={save} disabled={saving}>{saving ? 'Guardando…' : 'Guardar cambios'}</Btn>
      </div>
    </ConfigAccordionSection>
  );
};

const BANK_PURPOSE_SECTIONS = [
  {
    purpose: 'mensualidad',
    title: 'Pagos de alumnos',
    sub: 'Se muestra en el portal del alumno al pagar mensualidades (transferencia + comprobante).',
    defaultLabel: 'Mensualidades',
    sortOrder: 2,
    icon: 'money',
  },
  {
    purpose: 'tienda',
    title: 'Tienda online',
    sub: 'Se muestra en el checkout de la tienda cuando el cliente transfiere su compra.',
    defaultLabel: 'Tienda y órdenes',
    sortOrder: 1,
    icon: 'cart',
  },
];

const BankAccountRow = ({ theme, row, onEdit }) => (
  <div style={{
    padding: 14, borderRadius: 10, background: theme.bgInput, border: `1px solid ${theme.border}`,
    display: 'flex', gap: 12, alignItems: 'flex-start',
  }}>
    <div style={{ flex: 1, minWidth: 0 }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 8, flexWrap: 'wrap' }}>
        <span style={{ fontWeight: 700, color: theme.text, fontFamily: 'Inter, sans-serif', fontSize: 14 }}>{row.label}</span>
        {!row.is_active && <Badge theme={theme} color="warning">Inactiva</Badge>}
      </div>
      <div style={{ fontSize: 12, color: theme.textDim, marginTop: 4, fontFamily: 'Inter, sans-serif' }}>
        {row.beneficiary} · {row.bank_name}
      </div>
      <div style={{ fontSize: 12, color: theme.textMute, marginTop: 2, fontFamily: 'Inter, sans-serif' }}>
        Cuenta {row.account_number} · CLABE {row.clabe}
      </div>
    </div>
    <RowActions theme={theme} onEdit={onEdit} />
  </div>
);

const ConfigAdminModule = ({ theme }) => {
  const { data: settings, loading: loadingSettings, reload: reloadSettings } = useLiveData(() => fetchAcademySettings(), []);
  const { rows, loading, error, needsAuth, reload } = useAdminList(() => fetchBankAccountsAdmin(), []);
  const [modal, setModal] = React.useState(null);
  const [form, setForm] = React.useState({});
  const [saving, setSaving] = React.useState(false);
  const [formErr, setFormErr] = React.useState('');

  const rowsByPurpose = React.useMemo(() => {
    const map = { mensualidad: [], tienda: [], otro: [] };
    (rows || []).forEach((r) => {
      const p = r.purpose === 'mensualidad' || r.purpose === 'tienda' ? r.purpose : 'otro';
      map[p].push(r);
    });
    return map;
  }, [rows]);

  const openNewBank = (purpose) => {
    const meta = BANK_PURPOSE_SECTIONS.find((s) => s.purpose === purpose);
    setForm({
      purpose,
      label: meta?.defaultLabel || '',
      beneficiary: '',
      bank_name: '',
      account_number: '',
      clabe: '',
      is_active: true,
      sort_order: meta?.sortOrder ?? 0,
    });
    setFormErr('');
    setModal('new');
  };

  const saveBank = async () => {
    if (!form.beneficiary?.trim() || !form.bank_name?.trim() || !form.clabe?.trim()) {
      setFormErr('Beneficiario, banco y CLABE son obligatorios.');
      return;
    }
    setSaving(true);
    setFormErr('');
    try {
      await upsertBankAccount(form, modal === 'new' ? null : modal);
      setModal(null);
      reload();
    } catch (e) {
      setFormErr(e.message);
    }
    setSaving(false);
  };

  const modalTitle = modal === 'new'
    ? (form.purpose === 'tienda' ? 'Nueva cuenta — Tienda online' : form.purpose === 'mensualidad' ? 'Nueva cuenta — Pagos alumnos' : 'Nueva cuenta bancaria')
    : 'Editar cuenta bancaria';

  return (
    <AdminEntityShell theme={theme} title="CONFIGURACIÓN" sub="Tarifas de mensualidad, cuenta admin, sitio público y cuentas bancarias." icon="settings">
      {needsAuth ? <AuthRequired theme={theme} onRetry={() => { reload(); reloadSettings(); }} /> : (
        <>
          {loadingSettings ? <LoadingBlock theme={theme} label="Cargando tarifas y ajustes…" /> : (
            <BillingSettingsForm theme={theme} settings={settings} onSaved={reloadSettings} />
          )}
          <AdminAccountSettingsForm theme={theme} />
          {!loadingSettings && (
            <AdminWhatsAppCloudPanel theme={theme} settings={settings} onSaved={reloadSettings} />
          )}
          {!loadingSettings && (
            <SitePublicSettingsForm theme={theme} settings={settings} onSaved={reloadSettings} />
          )}
          {loading ? <LoadingBlock theme={theme} label="Cargando cuentas bancarias…" /> : error ? (
            <EmptyState theme={theme} title="Error" message={error} icon="warning" />
          ) : (
            <ConfigAccordionSection
              theme={theme}
              variant="card"
              title="CUENTAS BANCARIAS"
              sub="Mensualidades del portal alumno y compras en la tienda. Solo la cuenta activa de cada tipo se muestra al pagar."
            >
              <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap', marginBottom: 16 }}>
                <Btn theme={theme} kind="soft" icon="money" size="sm" onClick={() => openNewBank('mensualidad')}>
                  + Pagos alumnos
                </Btn>
                <Btn theme={theme} kind="soft" icon="cart" size="sm" onClick={() => openNewBank('tienda')}>
                  + Tienda online
                </Btn>
              </div>

              {BANK_PURPOSE_SECTIONS.map((section) => {
                const list = rowsByPurpose[section.purpose] || [];
                return (
                  <ConfigAccordionSection
                    key={section.purpose}
                    theme={theme}
                    variant="inner"
                    title={section.title}
                    sub={section.sub}
                  >
                    <div style={{ display: 'flex', justifyContent: 'flex-end', marginBottom: 12 }}>
                      <Btn theme={theme} icon="plus" size="sm" onClick={() => openNewBank(section.purpose)}>
                        Agregar cuenta
                      </Btn>
                    </div>
                    {list.length === 0 ? (
                      <p style={{ margin: 0, fontSize: 13, color: theme.textMute, fontFamily: 'Inter, sans-serif' }}>
                        Sin cuenta configurada. Los alumnos o la tienda no verán datos bancarios hasta que agregues una activa.
                      </p>
                    ) : (
                      <div style={{ display: 'grid', gap: 10 }}>
                        {list.map((r) => (
                          <BankAccountRow
                            key={r.id}
                            theme={theme}
                            row={r}
                            onEdit={() => { setForm({ ...r, is_active: r.is_active !== false }); setFormErr(''); setModal(r.id); }}
                          />
                        ))}
                      </div>
                    )}
                  </ConfigAccordionSection>
                );
              })}
              {(rowsByPurpose.otro || []).length > 0 && (
                <ConfigAccordionSection theme={theme} variant="inner" title="Otras cuentas"
                  sub="Cuentas con otro uso o histórico.">
                  <div style={{ display: 'grid', gap: 10 }}>
                    {rowsByPurpose.otro.map((r) => (
                      <BankAccountRow
                        key={r.id}
                        theme={theme}
                        row={r}
                        onEdit={() => { setForm({ ...r, is_active: r.is_active !== false }); setFormErr(''); setModal(r.id); }}
                      />
                    ))}
                  </div>
                </ConfigAccordionSection>
              )}
            </ConfigAccordionSection>
          )}
        </>
      )}
      <SimpleFormModal open={!!modal} onClose={() => setModal(null)} theme={theme} title={modalTitle}
        fields={[
          {
            key: 'purpose',
            label: '¿Dónde se usa esta cuenta?',
            type: 'select',
            options: [
              { value: 'mensualidad', label: 'Pagos de alumnos (portal · mensualidades)' },
              { value: 'tienda', label: 'Tienda online (checkout · compras)' },
              { value: 'otro', label: 'Otro uso' },
            ],
          },
          { key: 'label', label: 'Nombre interno (solo admin)', placeholder: 'Ej. Mensualidades BBVA' },
          { key: 'beneficiary', label: 'Beneficiario (titular)' },
          { key: 'bank_name', label: 'Banco' },
          { key: 'account_number', label: 'Número de cuenta' },
          { key: 'clabe', label: 'CLABE interbancaria' },
          {
            key: 'is_active',
            label: 'Activa (visible al pagar)',
            type: 'select',
            options: [
              { value: 'true', label: 'Sí — mostrar en transferencias' },
              { value: 'false', label: 'No — oculta (respaldo o histórico)' },
            ],
          },
          { key: 'sort_order', label: 'Prioridad (menor = primero si hay varias activas)', type: 'number' },
        ]}
        values={{
          ...form,
          is_active: form.is_active === false || form.is_active === 'false' ? 'false' : 'true',
          sort_order: form.sort_order ?? 0,
        }}
        onChange={(k, v) => {
          if (k === 'is_active') setForm((f) => ({ ...f, is_active: v === 'true' }));
          else if (k === 'sort_order') setForm((f) => ({ ...f, [k]: Number(v) || 0 }));
          else setForm((f) => ({ ...f, [k]: v }));
        }}
        onSave={saveBank}
        saving={saving}
        error={formErr}
      />
    </AdminEntityShell>
  );
};

Object.assign(window, { ConfigAdminModule, BillingSettingsForm, AdminAccountSettingsForm, SitePublicSettingsForm });
