// Pantalla de login / registro. Se muestra cuando no hay token válido.
// Layout split-screen: formulario a la izquierda, panel hero a la derecha.
// En mobile colapsa a una sola columna y oculta el panel hero.

const EMAIL_RX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;

// Calcula la "fuerza" de una contraseña en una escala 0-4.
// 0=vacía, 1=débil, 2=ok, 3=fuerte, 4=excelente.
function passwordStrength(pwd) {
  if (!pwd) return 0;
  let score = 0;
  if (pwd.length >= 6) score++;
  if (pwd.length >= 10) score++;
  if (/[A-Z]/.test(pwd) && /[a-z]/.test(pwd)) score++;
  if (/\d/.test(pwd) && /[^A-Za-z0-9]/.test(pwd)) score++;
  return Math.min(score, 4);
}

const STRENGTH_LABELS = ['', 'Débil', 'Aceptable', 'Fuerte', 'Excelente'];
const STRENGTH_COLORS = ['transparent', '#ef6868', '#f5a623', '#26d989', '#00c275'];

function AuthScreen({ backend, onAuthenticated, initialMode = 'login', onBack }) {
  const { useState, useMemo, useEffect, useRef } = React;

  const [mode, setMode] = useState(initialMode);
  const [email, setEmail] = useState('');
  const [emailTouched, setEmailTouched] = useState(false);
  const [password, setPassword] = useState('');
  const [showPassword, setShowPassword] = useState(false);
  const [passwordConfirm, setPasswordConfirm] = useState('');
  const [showPasswordConfirm, setShowPasswordConfirm] = useState(false);
  const [remember, setRemember] = useState(true);
  const [importLocal, setImportLocal] = useState(true);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState('');
  const [googleClientId, setGoogleClientId] = useState('');
  const googleBtnRef = useRef(null);

  const isRegister = mode === 'register';

  const hasLocalData = useMemo(() => {
    try {
      const a = localStorage.getItem('finanzas_assets');
      return a && JSON.parse(a).length > 0;
    } catch { return false; }
  }, []);

  // Validación email en vivo (solo se muestra después del primer blur, para no
  // chillar mientras el usuario está tipeando los primeros caracteres)
  const emailValid = !email || EMAIL_RX.test(email);
  const showEmailError = emailTouched && !emailValid;

  const strength = passwordStrength(password);

  // Cargar GOOGLE_CLIENT_ID desde el backend al montar.
  useEffect(() => {
    fetch(`${backend}/api/config`)
      .then(r => r.ok ? r.json() : {})
      .then(c => setGoogleClientId(c.googleClientId || ''))
      .catch(() => {});
  }, [backend]);

  // Helper de payload que comparte registro / login / google con la lógica
  // de import de localData.
  const buildLocalPayload = () => {
    if (mode !== 'register' || !importLocal || !hasLocalData) return null;
    try {
      return {
        portfolios: JSON.parse(localStorage.getItem('finanzas_portfolios') || '[]'),
        assets: JSON.parse(localStorage.getItem('finanzas_assets') || '[]'),
        activePortfolio: localStorage.getItem('finanzas_activePortfolio') || null,
      };
    } catch { return null; }
  };

  const cleanupLocalAfterImport = () => {
    if (mode === 'register' && importLocal && hasLocalData) {
      localStorage.removeItem('finanzas_assets');
      localStorage.removeItem('finanzas_portfolios');
      localStorage.removeItem('finanzas_activePortfolio');
    }
  };

  // Render del botón oficial de Google una vez que la lib + el client ID están listos.
  // Re-renderiza cuando cambia el modo (para que el theme matchee).
  useEffect(() => {
    if (!googleClientId || !googleBtnRef.current) return;

    let canceled = false;
    const tryInit = () => {
      if (canceled) return;
      const g = window.google?.accounts?.id;
      if (!g) { setTimeout(tryInit, 120); return; }

      g.initialize({
        client_id: googleClientId,
        callback: async (resp) => {
          if (!resp?.credential) return;
          setLoading(true); setError('');
          try {
            const localData = buildLocalPayload();
            const r = await fetch(`${backend}/api/auth/google`, {
              method: 'POST',
              headers: { 'Content-Type': 'application/json' },
              body: JSON.stringify({ credential: resp.credential, remember, localData }),
            });
            const data = await r.json();
            if (!r.ok) throw new Error(data.error || 'Error con Google');
            localStorage.setItem('finanzas_token', data.token);
            cleanupLocalAfterImport();
            onAuthenticated(data.token, data.user);
          } catch (err) {
            setError(err.message);
          } finally {
            setLoading(false);
          }
        },
      });

      // Limpiar el contenedor antes de re-renderizar (evita botones duplicados al
      // cambiar de modo o re-correr el efecto).
      if (googleBtnRef.current) googleBtnRef.current.innerHTML = '';
      g.renderButton(googleBtnRef.current, {
        type: 'standard', theme: 'filled_black', size: 'large',
        text: isRegister ? 'signup_with' : 'continue_with',
        shape: 'pill', width: 320,
      });
    };
    tryInit();
    return () => { canceled = true; };
  }, [googleClientId, mode, backend, importLocal, hasLocalData, remember]);

  const submit = async (e) => {
    e.preventDefault();
    setError('');
    if (!EMAIL_RX.test(email.trim())) {
      setEmailTouched(true);
      return setError('Ingresá un email válido');
    }
    if (password.length < 6) return setError('La contraseña debe tener al menos 6 caracteres');
    if (isRegister && password !== passwordConfirm) return setError('Las contraseñas no coinciden');

    setLoading(true);
    try {
      const localData = buildLocalPayload();
      const resp = await fetch(`${backend}/api/auth/${mode}`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ email: email.trim(), password, remember, localData }),
      });
      const data = await resp.json();
      if (!resp.ok) throw new Error(data.error || 'Error desconocido');

      localStorage.setItem('finanzas_token', data.token);
      cleanupLocalAfterImport();
      onAuthenticated(data.token, data.user);
    } catch (err) {
      setError(err.message);
    } finally {
      setLoading(false);
    }
  };

  const switchMode = () => {
    setMode(isRegister ? 'login' : 'register');
    setError('');
    setPasswordConfirm('');
  };

  return (
    <div className="auth-shell" style={{
      minHeight: '100vh', display: 'grid',
      gridTemplateColumns: 'minmax(0, 1fr) minmax(0, 1fr)',
      background: 'var(--bg)',
    }}>
      <AuthFormPanel
        mode={mode}
        isRegister={isRegister}
        email={email}
        password={password}
        showPassword={showPassword}
        passwordConfirm={passwordConfirm}
        showPasswordConfirm={showPasswordConfirm}
        showEmailError={showEmailError}
        emailValid={emailValid}
        strength={strength}
        remember={remember}
        importLocal={importLocal}
        hasLocalData={hasLocalData}
        loading={loading}
        error={error}
        googleClientId={googleClientId}
        googleBtnRef={googleBtnRef}
        onBack={onBack}
        onEmailChange={setEmail}
        onEmailBlur={() => setEmailTouched(true)}
        onPasswordChange={setPassword}
        onShowPasswordToggle={() => setShowPassword(s => !s)}
        onPasswordConfirmChange={setPasswordConfirm}
        onShowPasswordConfirmToggle={() => setShowPasswordConfirm(s => !s)}
        onRememberChange={setRemember}
        onImportLocalChange={setImportLocal}
        onSubmit={submit}
        onSwitchMode={switchMode}
      />
      <AuthHeroPanel />

      <style>{`
        @media (max-width: 880px) {
          .auth-shell { grid-template-columns: 1fr !important; }
          .auth-hero-panel { display: none !important; }
        }
      `}</style>
    </div>
  );
}

// ─── Panel izquierdo: formulario ──────────────────────────────────────────

function AuthFormPanel(props) {
  const {
    mode, isRegister, email, password, showPassword,
    passwordConfirm, showPasswordConfirm,
    showEmailError, emailValid,
    strength, remember, importLocal, hasLocalData, loading, error,
    googleClientId, googleBtnRef, onBack,
    onEmailChange, onEmailBlur, onPasswordChange, onShowPasswordToggle,
    onPasswordConfirmChange, onShowPasswordConfirmToggle,
    onRememberChange, onImportLocalChange, onSubmit, onSwitchMode,
  } = props;

  // Estado del match de contraseñas para el feedback en vivo bajo el campo de
  // confirmación. Mientras `passwordConfirm` está vacío no decimos nada.
  const confirmMatches = passwordConfirm.length > 0 && passwordConfirm === password;
  const confirmMismatches = passwordConfirm.length > 0 && passwordConfirm !== password;

  return (
    <div style={{
      display: 'flex', alignItems: 'center', justifyContent: 'center',
      padding: '40px 24px', overflowY: 'auto',
    }}>
      <div style={{ width: '100%', maxWidth: 420 }}>
        {onBack && (
          <button
            type="button"
            onClick={onBack}
            style={{
              display: 'inline-flex', alignItems: 'center', gap: 6,
              padding: '4px 0', marginBottom: 24,
              fontSize: 12.5, fontWeight: 500, color: 'var(--text-dim)',
              background: 'transparent', border: 'none',
            }}
            onMouseEnter={e => e.currentTarget.style.color = 'var(--text)'}
            onMouseLeave={e => e.currentTarget.style.color = 'var(--text-dim)'}
          >
            <svg width="14" height="14" viewBox="0 0 16 16" fill="none">
              <path d="M10 3 L5 8 L10 13" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" />
            </svg>
            Volver al inicio
          </button>
        )}

        <BrandHeader />

        <div style={{ fontSize: 26, fontWeight: 700, letterSpacing: -0.5, marginBottom: 6 }}>
          {isRegister ? 'Creá tu cuenta' : 'Bienvenido de vuelta'}
        </div>
        <div style={{ fontSize: 13.5, color: 'var(--text-dim)', marginBottom: 26 }}>
          {isRegister
            ? 'Trackeá tu portafolio en segundos. Es gratis.'
            : 'Ingresá para ver tus portafolios.'}
        </div>

        {/* Botón Google — solo se muestra si hay Client ID configurado */}
        {googleClientId && (
          <>
            <div ref={googleBtnRef} style={{ display: 'flex', justifyContent: 'center', marginBottom: 18 }} />
            <div style={{
              display: 'flex', alignItems: 'center', gap: 12,
              fontSize: 11.5, color: 'var(--text-faint)', textTransform: 'uppercase',
              letterSpacing: 1, fontWeight: 600, marginBottom: 18,
            }}>
              <div style={{ flex: 1, height: 1, background: 'var(--border)' }} />
              o con email
              <div style={{ flex: 1, height: 1, background: 'var(--border)' }} />
            </div>
          </>
        )}

        <form onSubmit={onSubmit} style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
          <FieldLabel
            label="Email"
            error={showEmailError ? 'Formato inválido' : null}
          >
            <Input
              type="email"
              value={email}
              onChange={e => onEmailChange(e.target.value)}
              onBlur={onEmailBlur}
              placeholder="tu@email.com"
              autoComplete="email"
              disabled={loading}
              hasError={showEmailError}
              isValid={email && emailValid}
            />
          </FieldLabel>

          <FieldLabel label="Contraseña">
            <PasswordInput
              value={password}
              onChange={onPasswordChange}
              show={showPassword}
              onToggleShow={onShowPasswordToggle}
              placeholder={isRegister ? 'Mínimo 6 caracteres' : '••••••'}
              autoComplete={isRegister ? 'new-password' : 'current-password'}
              disabled={loading}
            />
            {isRegister && password.length > 0 && (
              <PasswordStrengthBar strength={strength} />
            )}
          </FieldLabel>

          {isRegister && (
            <FieldLabel
              label="Confirmar contraseña"
              error={confirmMismatches ? 'No coinciden' : null}
            >
              <PasswordInput
                value={passwordConfirm}
                onChange={onPasswordConfirmChange}
                show={showPasswordConfirm}
                onToggleShow={onShowPasswordConfirmToggle}
                placeholder="Repetí la contraseña"
                autoComplete="new-password"
                disabled={loading}
                hasError={confirmMismatches}
                isValid={confirmMatches}
              />
              {confirmMatches && (
                <div style={{ fontSize: 11.5, color: 'var(--green)', fontWeight: 600, marginTop: 5, display: 'inline-flex', alignItems: 'center', gap: 4 }}>
                  <svg width="11" height="11" viewBox="0 0 12 12" fill="none">
                    <path d="M2.5 6.5 L5 9 L9.5 3.5" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
                  </svg>
                  Coinciden
                </div>
              )}
            </FieldLabel>
          )}

          <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginTop: 2 }}>
            <label style={{ display: 'inline-flex', alignItems: 'center', gap: 8, cursor: 'pointer', fontSize: 13, color: 'var(--text-dim)' }}>
              <input
                type="checkbox"
                checked={remember}
                onChange={e => onRememberChange(e.target.checked)}
                style={{ accentColor: 'var(--accent)' }}
              />
              Recordarme
            </label>
          </div>

          {isRegister && hasLocalData && (
            <label style={{
              display: 'flex', alignItems: 'flex-start', gap: 10, cursor: 'pointer',
              padding: '10px 12px', borderRadius: 10, background: 'rgba(167,139,250,0.08)',
              border: '1px solid rgba(167,139,250,0.2)',
            }}>
              <input
                type="checkbox"
                checked={importLocal}
                onChange={e => onImportLocalChange(e.target.checked)}
                style={{ marginTop: 2, accentColor: 'var(--purple)' }}
              />
              <div style={{ fontSize: 12.5, lineHeight: 1.4 }}>
                <div style={{ fontWeight: 600, color: 'var(--text)' }}>Importar datos del navegador</div>
                <div style={{ color: 'var(--text-dim)', marginTop: 2 }}>
                  Detecté activos cargados localmente. Los traigo a tu cuenta para no perderlos.
                </div>
              </div>
            </label>
          )}

          {error && (
            <div style={{
              fontSize: 12.5, color: 'var(--red)', background: 'rgba(239,104,104,0.08)',
              border: '1px solid rgba(239,104,104,0.2)', borderRadius: 8, padding: '10px 12px',
              animation: 'feedbackSlideIn 0.18s ease-out',
            }}>
              {error}
            </div>
          )}

          <button
            type="submit"
            disabled={loading}
            style={{
              padding: '13px 0', borderRadius: 11, fontWeight: 700, fontSize: 14,
              background: 'var(--accent)', color: '#0c2418', border: 'none',
              opacity: loading ? 0.6 : 1, cursor: loading ? 'default' : 'pointer',
              marginTop: 4, transition: 'transform 0.1s, box-shadow 0.15s',
              boxShadow: '0 4px 14px rgba(0, 194, 117, 0.25)',
            }}
            onMouseEnter={e => { if (!loading) e.currentTarget.style.transform = 'translateY(-1px)'; }}
            onMouseLeave={e => { e.currentTarget.style.transform = 'translateY(0)'; }}
          >
            {loading ? (
              <span style={{ display: 'inline-flex', alignItems: 'center', gap: 8 }}>
                <Spinner /> {isRegister ? 'Creando cuenta…' : 'Ingresando…'}
              </span>
            ) : (isRegister ? 'Crear cuenta' : 'Ingresar')}
          </button>
        </form>

        <div style={{ textAlign: 'center', marginTop: 22, fontSize: 13.5, color: 'var(--text-dim)' }}>
          {isRegister ? '¿Ya tenés cuenta? ' : '¿No tenés cuenta? '}
          <button
            onClick={onSwitchMode}
            style={{ color: 'var(--accent)', fontWeight: 700, padding: 0, background: 'none', border: 'none', cursor: 'pointer' }}
          >
            {isRegister ? 'Iniciar sesión' : 'Crear una gratis'}
          </button>
        </div>

        <div style={{ textAlign: 'center', marginTop: 32, fontSize: 11, color: 'var(--text-faint)', lineHeight: 1.5 }}>
          Al continuar aceptás que tus datos se almacenen de forma segura para
          gestionar tu portafolio. No compartimos información con terceros.
        </div>
      </div>
    </div>
  );
}

// ─── Panel derecho: hero decorativo con value props ───────────────────────

function AuthHeroPanel() {
  return (
    <div className="auth-hero-panel" style={{
      position: 'relative', overflow: 'hidden',
      background: 'linear-gradient(135deg, #0a3a26 0%, #0e0e10 60%, #1a1a1c 100%)',
      display: 'flex', flexDirection: 'column', justifyContent: 'center',
      padding: '48px 56px', borderLeft: '1px solid var(--border)',
    }}>
      {/* Patrón decorativo */}
      <div style={{
        position: 'absolute', top: -120, right: -120,
        width: 360, height: 360, borderRadius: '50%',
        background: 'radial-gradient(circle, rgba(0, 194, 117, 0.18), transparent 70%)',
        animation: 'float 6s ease-in-out infinite',
      }} />
      <div style={{
        position: 'absolute', bottom: -100, left: -80,
        width: 280, height: 280, borderRadius: '50%',
        background: 'radial-gradient(circle, rgba(167, 139, 250, 0.12), transparent 70%)',
        animation: 'float 7s ease-in-out infinite reverse',
      }} />

      <div style={{ position: 'relative', zIndex: 1, display: 'flex', flexDirection: 'column', gap: 28 }}>
        <div>
          <div style={{
            fontFamily: 'Space Grotesk, Inter, sans-serif', fontWeight: 700,
            fontSize: 30, lineHeight: 1.15, letterSpacing: -0.8,
            marginBottom: 12,
          }}>
            Tu portafolio,<br />
            <span style={{ background: 'linear-gradient(90deg, #26d989, #00c275)', WebkitBackgroundClip: 'text', WebkitTextFillColor: 'transparent' }}>
              todo en un lugar.
            </span>
          </div>
          <div style={{ fontSize: 13.5, color: 'var(--text-dim)', lineHeight: 1.55, maxWidth: 380 }}>
            Cripto, acciones y ETFs con precios reales en USD y conversión automática a CCL/Dólar Cripto.
          </div>
        </div>

        <MiniDashboardMockup />

        <div style={{ display: 'flex', flexDirection: 'column', gap: 11 }}>
          <Bullet>Precios en vivo cada 30s</Bullet>
          <Bullet>Múltiples portafolios independientes</Bullet>
          <Bullet>Carga en USD o ARS — convierte solo</Bullet>
        </div>

        <SupportedAssetsConstellation />
      </div>

      <div style={{ position: 'relative', zIndex: 1, marginTop: 28, fontSize: 11.5, color: 'var(--text-faint)' }}>
        🌱 Beta · Empezando juntos
      </div>
    </div>
  );
}

// Mini-mockup animado del dashboard: balance fake, gráfico que se dibuja en
// 2s al cargar, y 3 filas de assets con sus logos. Los datos son plausibles
// pero estáticos (no necesita network). Los logos cripto sí vienen de
// CryptoCompare CDN; si fallan, fallback al círculo de iniciales.
function MiniDashboardMockup() {
  const rows = [
    { ticker: 'BTC', name: 'Bitcoin',  qty: '0.42 BTC', value: '$32,250', change: 1.2,
      iconUrl: 'https://www.cryptocompare.com/media/37746251/btc.png' },
    { ticker: 'ETH', name: 'Ethereum', qty: '2.5 ETH',  value: '$5,680',  change: -0.5,
      iconUrl: 'https://www.cryptocompare.com/media/37746238/eth.png' },
    { ticker: 'SOL', name: 'Solana',   qty: '18 SOL',   value: '$1,508',  change: 3.1,
      iconUrl: 'https://www.cryptocompare.com/media/37747734/sol.png' },
  ];

  return (
    <div style={{
      background: 'rgba(255, 255, 255, 0.04)',
      border: '1px solid rgba(255, 255, 255, 0.08)',
      borderRadius: 14, padding: '18px 18px 16px',
      backdropFilter: 'blur(8px)',
    }}>
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start' }}>
        <div>
          <div style={{ fontSize: 11, color: 'var(--text-faint)', letterSpacing: 0.4, fontWeight: 600, textTransform: 'uppercase', marginBottom: 4 }}>
            Mi Portafolio
          </div>
          <div style={{
            fontFamily: 'Space Grotesk, Inter, sans-serif',
            fontSize: 28, fontWeight: 700, letterSpacing: -0.8, lineHeight: 1,
            fontVariantNumeric: 'tabular-nums',
          }}>
            $39,438.50
          </div>
          <div style={{ fontSize: 12, color: 'var(--green)', fontWeight: 600, marginTop: 4, fontVariantNumeric: 'tabular-nums' }}>
            +$884.50 (+2.30%)
          </div>
        </div>
        <div style={{
          fontSize: 10, color: 'var(--text-faint)', letterSpacing: 0.5, fontWeight: 700,
          padding: '3px 7px', border: '1px solid var(--border)', borderRadius: 5,
        }}>
          30D
        </div>
      </div>

      <svg viewBox="0 0 280 70" preserveAspectRatio="none" style={{ width: '100%', height: 70, marginTop: 12, marginBottom: 12 }}>
        <defs>
          <linearGradient id="mockupAreaGrad" x1="0" x2="0" y1="0" y2="1">
            <stop offset="0%"   stopColor="rgba(38, 217, 137, 0.35)" />
            <stop offset="100%" stopColor="rgba(38, 217, 137, 0)" />
          </linearGradient>
        </defs>
        <path
          d="M0,52 L25,49 L50,53 L75,46 L100,48 L125,38 L150,42 L175,30 L200,33 L225,22 L250,25 L280,12 L280,70 L0,70 Z"
          fill="url(#mockupAreaGrad)"
        />
        <path
          d="M0,52 L25,49 L50,53 L75,46 L100,48 L125,38 L150,42 L175,30 L200,33 L225,22 L250,25 L280,12"
          stroke="#26d989" strokeWidth="2" fill="none"
          strokeLinecap="round" strokeLinejoin="round"
          style={{ strokeDasharray: 600, strokeDashoffset: 600, animation: 'mockupChartDraw 2.4s 0.2s ease-out forwards' }}
        />
      </svg>

      <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
        {rows.map(r => <MockAssetRow key={r.ticker} {...r} />)}
      </div>

      <style>{`
        @keyframes mockupChartDraw { to { stroke-dashoffset: 0; } }
      `}</style>
    </div>
  );
}

function MockAssetRow({ ticker, name, qty, value, change, iconUrl }) {
  const [imgFailed, setImgFailed] = React.useState(false);
  const positive = change >= 0;
  return (
    <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
      {iconUrl && !imgFailed ? (
        <img src={iconUrl} alt={ticker} onError={() => setImgFailed(true)}
          style={{ width: 26, height: 26, borderRadius: '50%', objectFit: 'cover', flexShrink: 0, background: 'rgba(255,255,255,0.06)' }} />
      ) : (
        <div style={{
          width: 26, height: 26, borderRadius: '50%',
          background: '#3a3a3f', color: '#fff',
          display: 'grid', placeItems: 'center', fontSize: 10, fontWeight: 700, flexShrink: 0,
        }}>{ticker.slice(0, 2)}</div>
      )}
      <div style={{ flex: 1, minWidth: 0, lineHeight: 1.25 }}>
        <div style={{ fontWeight: 600, fontSize: 12.5 }}>{ticker}</div>
        <div style={{ fontSize: 10.5, color: 'var(--text-faint)', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
          {qty}
        </div>
      </div>
      <div style={{ textAlign: 'right', lineHeight: 1.25, fontVariantNumeric: 'tabular-nums' }}>
        <div style={{ fontWeight: 600, fontSize: 12.5 }}>{value}</div>
        <div style={{ fontSize: 10.5, fontWeight: 600, color: positive ? 'var(--green)' : 'var(--red)' }}>
          {positive ? '+' : ''}{change.toFixed(1)}%
        </div>
      </div>
    </div>
  );
}

// Constelación de logos: 8 activos populares en grilla flexible. Cada uno
// flota con un delay distinto para que se sienta vivo. CryptoCompare para
// cripto, Clearbit para stocks. Si una imagen falla, se oculta.
const CONSTELLATION_LOGOS = [
  { src: 'https://www.cryptocompare.com/media/37746251/btc.png', alt: 'BTC' },
  { src: 'https://logo.clearbit.com/nvidia.com',                 alt: 'NVDA' },
  { src: 'https://www.cryptocompare.com/media/37746238/eth.png', alt: 'ETH' },
  { src: 'https://logo.clearbit.com/apple.com',                  alt: 'AAPL' },
  { src: 'https://www.cryptocompare.com/media/37747734/sol.png', alt: 'SOL' },
  { src: 'https://logo.clearbit.com/mercadolibre.com',           alt: 'MELI' },
  { src: 'https://logo.clearbit.com/microsoft.com',              alt: 'MSFT' },
  { src: 'https://logo.clearbit.com/google.com',                 alt: 'GOOGL' },
];

function SupportedAssetsConstellation() {
  return (
    <div>
      <div style={{
        fontSize: 11, color: 'var(--text-faint)', letterSpacing: 0.5,
        fontWeight: 600, textTransform: 'uppercase', marginBottom: 12,
      }}>
        Soporta tus activos favoritos
      </div>
      <div style={{ display: 'flex', flexWrap: 'wrap', gap: 10 }}>
        {CONSTELLATION_LOGOS.map((logo, i) => (
          <ConstellationLogo key={logo.alt} {...logo} delay={i * 0.18} />
        ))}
      </div>
    </div>
  );
}

function ConstellationLogo({ src, alt, delay }) {
  const [hidden, setHidden] = React.useState(false);
  if (hidden) return null;
  return (
    <div style={{
      width: 36, height: 36, borderRadius: '50%',
      background: 'rgba(255, 255, 255, 0.06)',
      border: '1px solid rgba(255, 255, 255, 0.1)',
      display: 'grid', placeItems: 'center', overflow: 'hidden',
      animation: `float 5s ease-in-out infinite`,
      animationDelay: `${delay}s`,
    }}>
      <img
        src={src} alt={alt}
        onError={() => setHidden(true)}
        style={{ width: 26, height: 26, objectFit: 'contain' }}
      />
    </div>
  );
}

// ─── Subcomponentes ──────────────────────────────────────────────────────

function BrandHeader() {
  return (
    <div style={{ display: 'flex', alignItems: 'center', gap: 12, marginBottom: 32 }}>
      <svg width="38" height="38" viewBox="0 0 70 70" aria-hidden>
        <circle cx="35" cy="35" r="27" fill="none" stroke="#00c275" strokeWidth="3" />
        <path d="M23 43 L35 27 L47 35" stroke="#00c275" strokeWidth="3" fill="none" strokeLinecap="round" strokeLinejoin="round" />
        <path d="M41 27 L47 27 L47 33" stroke="#00c275" strokeWidth="3" fill="none" strokeLinecap="round" strokeLinejoin="round" />
      </svg>
      <div style={{ fontFamily: 'Space Grotesk, Inter, sans-serif', fontWeight: 700, fontSize: 20, letterSpacing: -0.5 }}>
        tracker<span style={{ color: '#00c275' }}>pro</span>
      </div>
    </div>
  );
}

function FieldLabel({ label, error, children }) {
  return (
    <label style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', fontSize: 12, fontWeight: 500 }}>
        <span style={{ color: 'var(--text-dim)' }}>{label}</span>
        {error && <span style={{ color: 'var(--red)', fontSize: 11.5 }}>{error}</span>}
      </div>
      {children}
    </label>
  );
}

function Input({ hasError, isValid, ...rest }) {
  const borderColor = hasError ? 'var(--red)' : isValid ? 'var(--accent)' : 'var(--border-strong)';
  return (
    <input
      {...rest}
      style={{
        width: '100%', padding: '12px 14px', borderRadius: 10, fontSize: 14,
        background: 'var(--panel-2)', border: `1px solid ${borderColor}`,
        color: 'var(--text)', outline: 'none', boxSizing: 'border-box',
        transition: 'border-color 0.15s, box-shadow 0.15s',
      }}
      onFocus={e => e.target.style.boxShadow = `0 0 0 3px ${hasError ? 'rgba(239,104,104,0.15)' : 'rgba(0,194,117,0.15)'}`}
      onBlurCapture={(e) => {
        e.target.style.boxShadow = 'none';
        rest.onBlur?.(e);
      }}
    />
  );
}

function PasswordInput({ value, onChange, show, onToggleShow, placeholder, autoComplete, disabled, hasError, isValid }) {
  const borderColor = hasError ? 'var(--red)' : isValid ? 'var(--accent)' : 'var(--border-strong)';
  const focusRing = hasError ? 'rgba(239,104,104,0.15)' : 'rgba(0,194,117,0.15)';
  return (
    <div style={{ position: 'relative' }}>
      <input
        type={show ? 'text' : 'password'}
        value={value}
        onChange={e => onChange(e.target.value)}
        placeholder={placeholder}
        autoComplete={autoComplete}
        disabled={disabled}
        style={{
          width: '100%', padding: '12px 44px 12px 14px', borderRadius: 10, fontSize: 14,
          background: 'var(--panel-2)', border: `1px solid ${borderColor}`,
          color: 'var(--text)', outline: 'none', boxSizing: 'border-box',
          transition: 'border-color 0.15s, box-shadow 0.15s',
        }}
        onFocus={e => e.target.style.boxShadow = `0 0 0 3px ${focusRing}`}
        onBlur={e => e.target.style.boxShadow = 'none'}
      />
      <button
        type="button"
        onClick={onToggleShow}
        tabIndex={-1}
        style={{
          position: 'absolute', right: 10, top: '50%', transform: 'translateY(-50%)',
          width: 28, height: 28, borderRadius: 6,
          display: 'grid', placeItems: 'center', color: 'var(--text-faint)',
          background: 'transparent', border: 'none',
        }}
        onMouseEnter={e => e.currentTarget.style.color = 'var(--text)'}
        onMouseLeave={e => e.currentTarget.style.color = 'var(--text-faint)'}
        aria-label={show ? 'Ocultar contraseña' : 'Mostrar contraseña'}
      >
        {show ? (
          <svg width="16" height="16" viewBox="0 0 20 20" fill="none">
            <path d="M3 3 L17 17" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" />
            <path d="M7.5 6.5 C8.3 6.2 9.1 6 10 6 C13.5 6 16.5 8.5 18 10 C17.4 10.7 16.6 11.4 15.7 12.1 M12.5 13.5 C11.7 13.8 10.9 14 10 14 C6.5 14 3.5 11.5 2 10 C2.7 9.2 3.6 8.4 4.6 7.7" stroke="currentColor" strokeWidth="1.4" strokeLinecap="round" fill="none"/>
          </svg>
        ) : (
          <svg width="16" height="16" viewBox="0 0 20 20" fill="none">
            <path d="M2 10 C3.5 8.5 6.5 6 10 6 C13.5 6 16.5 8.5 18 10 C16.5 11.5 13.5 14 10 14 C6.5 14 3.5 11.5 2 10 Z" stroke="currentColor" strokeWidth="1.6" fill="none"/>
            <circle cx="10" cy="10" r="2.5" stroke="currentColor" strokeWidth="1.6" fill="none"/>
          </svg>
        )}
      </button>
    </div>
  );
}

function PasswordStrengthBar({ strength }) {
  const label = STRENGTH_LABELS[strength];
  const color = STRENGTH_COLORS[strength];
  return (
    <div style={{ marginTop: 8 }}>
      <div style={{ display: 'flex', gap: 4 }}>
        {[1, 2, 3, 4].map(i => (
          <div key={i} style={{
            flex: 1, height: 4, borderRadius: 2,
            background: i <= strength ? color : 'var(--panel-2)',
            transition: 'background 0.2s',
          }} />
        ))}
      </div>
      {label && (
        <div style={{ fontSize: 11, color, fontWeight: 600, marginTop: 5, letterSpacing: 0.3 }}>
          {label}
        </div>
      )}
    </div>
  );
}

function Bullet({ children }) {
  return (
    <div style={{ display: 'flex', alignItems: 'center', gap: 12, fontSize: 13.5, color: 'var(--text)' }}>
      <div style={{
        width: 22, height: 22, borderRadius: '50%',
        background: 'rgba(0,194,117,0.15)', border: '1px solid rgba(0,194,117,0.4)',
        display: 'grid', placeItems: 'center', flexShrink: 0,
      }}>
        <svg width="11" height="11" viewBox="0 0 12 12" fill="none">
          <path d="M2.5 6.5 L5 9 L9.5 3.5" stroke="#26d989" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
        </svg>
      </div>
      {children}
    </div>
  );
}

function Spinner() {
  return (
    <svg width="14" height="14" viewBox="0 0 24 24" fill="none" style={{ animation: 'spin 0.8s linear infinite' }}>
      <circle cx="12" cy="12" r="9" stroke="currentColor" strokeWidth="2.5" strokeDasharray="28" strokeDashoffset="10"/>
    </svg>
  );
}

Object.assign(window, { AuthScreen });
