// ─────────────────────────────────────────────
// components/DO_Login.jsx
//
// Multi-step login flow:
//   Step 1: Email
//   Step 2: Password (if set) + Send Access Code (email or SMS)
//   Step 3: Enter 6-digit code
//   onLogin(jwt, user) called on success
// ─────────────────────────────────────────────

const { useState, useRef, useEffect } = React;

const API_BASE = window.API_BASE || '';

async function apiPost(endpoint, body) {
  const res = await fetch(`${API_BASE}/v6/auth/${endpoint}`, {
    method:  'POST',
    headers: { 'Content-Type': 'application/json' },
    body:    JSON.stringify(body),
  });
  return res.json();
}

// ── 6-digit code input ────────────────────────
function CodeInput({ onComplete, disabled }) {
  const [digits, setDigits] = useState(['','','','','','']);
  const refs = Array.from({ length: 6 }, () => useRef());

  useEffect(() => { refs[0].current?.focus(); }, []);

  function handleChange(i, e) {
    const val = e.target.value.replace(/\D/g, '').slice(-1);
    const next = [...digits];
    next[i] = val;
    setDigits(next);
    if (val && i < 5) refs[i + 1].current?.focus();
    if (next.every(d => d !== '')) onComplete(next.join(''));
  }

  function handleKeyDown(i, e) {
    if (e.key === 'Backspace' && !digits[i] && i > 0) {
      const next = [...digits];
      next[i - 1] = '';
      setDigits(next);
      refs[i - 1].current?.focus();
    }
    if (e.key === 'ArrowLeft'  && i > 0) refs[i - 1].current?.focus();
    if (e.key === 'ArrowRight' && i < 5) refs[i + 1].current?.focus();
  }

  function handlePaste(e) {
    const pasted = e.clipboardData.getData('text').replace(/\D/g, '').slice(0, 6);
    if (pasted.length === 6) {
      setDigits(pasted.split(''));
      refs[5].current?.focus();
      onComplete(pasted);
    }
    e.preventDefault();
  }

  return (
    <div style={{ display:'flex', gap:8, justifyContent:'center', margin:'24px 0 16px' }}>
      {digits.map((d, i) => (
        <input
          key={i}
          ref={refs[i]}
          type="text"
          inputMode="numeric"
          maxLength={1}
          value={d}
          disabled={disabled}
          onChange={e => handleChange(i, e)}
          onKeyDown={e => handleKeyDown(i, e)}
          onPaste={handlePaste}
          style={{
            width: 44, height: 54,
            border: `2px solid ${d ? '#2563eb' : '#e2e8f0'}`,
            borderRadius: 6,
            fontSize: 26, fontWeight: 700,
            textAlign: 'center',
            color: '#0f172a',
            outline: 'none',
            background: disabled ? '#f8fafc' : '#fff',
            transition: 'border-color 0.15s',
          }}
        />
      ))}
    </div>
  );
}

// ── Device fingerprint ────────────────────────
// Generates a stable hash from browser characteristics.
// Used to identify trusted devices — not PII, stored as hash only.
async function getDeviceHash() {
  const components = [
    navigator.userAgent,
    navigator.language || '',
    (screen.width || 0) + 'x' + (screen.height || 0),
    Intl.DateTimeFormat().resolvedOptions().timeZone || '',
    navigator.platform || '',
  ].join('|');
  if (window.crypto?.subtle) {
    try {
      const encoded    = new TextEncoder().encode(components);
      const hashBuffer = await crypto.subtle.digest('SHA-256', encoded);
      return Array.from(new Uint8Array(hashBuffer)).map(b => b.toString(16).padStart(2,'0')).join('');
    } catch(e) {}
  }
  // Fallback simple hash
  let h = 0;
  for (let i = 0; i < components.length; i++) { h = ((h << 5) - h) + components.charCodeAt(i); h |= 0; }
  return Math.abs(h).toString(16).padStart(8, '0');
}

function getDeviceName() {
  const ua = navigator.userAgent;
  let browser = 'Browser', os = 'Unknown';
  if      (ua.includes('Edg'))     browser = 'Edge';
  else if (ua.includes('Chrome'))  browser = 'Chrome';
  else if (ua.includes('Firefox')) browser = 'Firefox';
  else if (ua.includes('Safari'))  browser = 'Safari';
  if      (ua.includes('iPhone'))  os = 'iPhone';
  else if (ua.includes('iPad'))    os = 'iPad';
  else if (ua.includes('Android')) os = 'Android';
  else if (ua.includes('Mac'))     os = 'Mac';
  else if (ua.includes('Windows')) os = 'Windows';
  else if (ua.includes('Linux'))   os = 'Linux';
  return `${browser} on ${os}`;
}

// ── Main component ────────────────────────────
function DOLogin({ appId, theme = {}, onLogin, appName = '' }) {

  const primary = theme.primary || '#2563eb';
  const navBg   = theme.nav_bg  || '#0f2744';
  const font     = theme.font   || "'Segoe UI', sans-serif";
  const radius   = `${theme.border_radius || 6}px`;

  // ── Device fingerprint (generated once on mount) ──
  const [deviceHash, setDeviceHash] = useState(null);
  const [deviceName, setDeviceName] = useState('');

  useEffect(() => {
    getDeviceHash().then(h => setDeviceHash(h));
    setDeviceName(getDeviceName());
  }, []);

  // ── Access check — runs before showing ANY login UI ──
  const [accessChecked, setAccessChecked] = useState(false);
  const [accessAllowed, setAccessAllowed] = useState(false);

  useEffect(() => {
    fetch(`${API_BASE}/v6/auth/access?app=${appId}`)
      .then(r => r.json())
      .then(data => {
        setAccessAllowed(data.allowed !== false);
        setAccessChecked(true);
      })
      .catch(() => {
        // Fail open on network error — don't lock out due to a bug
        setAccessAllowed(true);
        setAccessChecked(true);
      });
  }, [appId]);

  const [step,        setStep]        = useState('email');
  const [email,       setEmail]       = useState('');
  const [password,    setPassword]    = useState('');
  const [showPw,      setShowPw]      = useState(false);
  const [remember,    setRemember]    = useState(false);
  const [hasPassword, setHasPassword] = useState(false);
  const [hasPhone,    setHasPhone]    = useState(false);
  const [codeVia,     setCodeVia]     = useState(null);
  const [loading,     setLoading]     = useState(false);
  const [error,       setError]       = useState(null);
  const [info,        setInfo]        = useState(null);
  const [canResend,   setCanResend]   = useState(false);
  const resendRef = useRef(null);

  function clearMsg() { setError(null); setInfo(null); }

  function startResendTimer() {
    setCanResend(false);
    clearTimeout(resendRef.current);
    resendRef.current = setTimeout(() => setCanResend(true), 30000);
  }

  // ── Step 1: check email ───────────────────────
  async function handleEmailSubmit(e) {
    e?.preventDefault();
    if (!email.trim()) return;
    clearMsg();
    setLoading(true);
    try {
      const data = await apiPost('check', { app: appId, email: email.trim(), deviceHash });
      if (data.status === 'blocked') { setError(data.message); return; }
      setHasPassword(!!data.hasPassword);
      setHasPhone(!!data.hasPhone);
      // If 2FA required and no password, go straight to code
      if (data.need2fa && !data.hasPassword) {
        await handleSendCode('email');
        return;
      }
      setStep('options');
    } catch(err) {
      setError('Something went wrong. Please try again.');
    } finally {
      setLoading(false);
    }
  }

  // ── Step 2a: password login ───────────────────
  async function handlePasswordSubmit(e) {
    e?.preventDefault();
    if (!password) return;
    clearMsg();
    setLoading(true);
    try {
      const data = await apiPost('password', { app: appId, email, password, remember, deviceHash, deviceName });
      if (data.status === 'need_2fa') {
        // Password correct but 2FA required — send code and proceed to code step
        await handleSendCode('email');
        return;
      }
      if (data.status !== 'ok') throw new Error(data.message);
      onLogin && onLogin(data.jwt, data.user);
    } catch(err) {
      setError(err.message || 'Incorrect email or password.');
    } finally {
      setLoading(false);
    }
  }

  // ── Step 2b: send access code ─────────────────
  async function handleSendCode(via) {
    clearMsg();
    setLoading(true);
    setCodeVia(via);
    try {
      const data = await apiPost('code', { app: appId, email, via });
      if (data.status !== 'ok') throw new Error(data.message);
      setStep('code');
      startResendTimer();
    } catch(err) {
      setError(err.message || 'Failed to send code. Please try again.');
    } finally {
      setLoading(false);
    }
  }

  // ── Step 3: verify code ───────────────────────
  async function handleCodeComplete(code) {
    clearMsg();
    setLoading(true);
    try {
      const data = await apiPost('verify', { app: appId, email, code, remember, deviceHash, deviceName });
      if (data.status !== 'ok') throw new Error(data.message);
      onLogin && onLogin(data.jwt, data.user);
    } catch(err) {
      setError(err.message || 'Invalid or expired code. Please try again.');
      setLoading(false);
    }
  }

  // ── Shared styles ─────────────────────────────
  const S = {
    page:     { minHeight:'100vh', background:'#f8fafc', display:'flex', flexDirection:'column', alignItems:'center', justifyContent:'center', fontFamily:font, padding:'24px 16px' },
    card:     { background:'#fff', borderRadius:radius, boxShadow:'0 1px 3px rgba(0,0,0,0.08), 0 8px 32px rgba(0,0,0,0.08)', padding:'40px 36px', width:'100%', maxWidth:400 },
    logoWrap: { textAlign:'center', marginBottom:28, paddingBottom:24, borderBottom:'1px solid #f1f5f9' },
    logoText: { fontSize:22, fontWeight:800, color:navBg, letterSpacing:'-0.5px' },
    appName:  { fontSize:13, color:'#94a3b8', marginTop:4 },
    heading:  { fontSize:20, fontWeight:700, color:'#0f172a', margin:'0 0 6px' },
    sub:      { fontSize:14, color:'#64748b', margin:'0 0 24px', lineHeight:1.5 },
    label:    { display:'block', fontSize:12, fontWeight:600, color:'#475569', marginBottom:6, textTransform:'uppercase', letterSpacing:'0.04em' },
    input:    { width:'100%', padding:'10px 12px', border:'1px solid #e2e8f0', borderRadius:radius, fontSize:15, color:'#0f172a', fontFamily:font, outline:'none', boxSizing:'border-box' },
    btnPrimary:   { width:'100%', padding:'11px', background:primary, color:'#fff', border:'none', borderRadius:radius, fontSize:15, fontWeight:600, cursor:'pointer', fontFamily:font, marginTop:4 },
    btnSecondary: { width:'100%', padding:'10px 12px', background:'#f8fafc', color:'#374151', border:'1px solid #e2e8f0', borderRadius:radius, fontSize:14, fontWeight:500, cursor:'pointer', fontFamily:font, marginTop:8, textAlign:'left', display:'flex', alignItems:'center', gap:10 },
    btnLink:  { background:'none', border:'none', color:primary, fontSize:13, cursor:'pointer', fontFamily:font, padding:0, textDecoration:'underline' },
    divider:  { display:'flex', alignItems:'center', gap:12, margin:'20px 0' },
    divLine:  { flex:1, height:1, background:'#f1f5f9' },
    orLabel:  { color:'#94a3b8', fontSize:12, fontWeight:600, textTransform:'uppercase', letterSpacing:'0.06em' },
    error:    { background:'#fef2f2', border:'1px solid #fecaca', borderRadius:radius, color:'#dc2626', fontSize:13, padding:'10px 14px', marginBottom:16, lineHeight:1.5 },
    info:     { background:'#f0fdf4', border:'1px solid #bbf7d0', borderRadius:radius, color:'#16a34a', fontSize:13, padding:'10px 14px', marginBottom:16, lineHeight:1.5 },
    back:     { background:'none', border:'none', color:'#94a3b8', fontSize:13, cursor:'pointer', fontFamily:font, padding:'0 0 20px', display:'flex', alignItems:'center', gap:4 },
    remember: { display:'flex', alignItems:'center', gap:8, fontSize:13, color:'#64748b', margin:'12px 0 4px', cursor:'pointer' },
    footer:   { textAlign:'center', marginTop:24, paddingTop:20, borderTop:'1px solid #f1f5f9', fontSize:12, color:'#94a3b8' },
    codeIcon: { fontSize:20 },
  };

  const logo = theme.logo_url
    ? <img src={theme.logo_url} alt="Logo" style={{ height:40, width:'auto' }} />
    : <span style={S.logoText}>{theme.logo_text || 'DO'}</span>;

  // ── While access check is in flight — show blank card ──
  if (!accessChecked) return (
    <div style={S.page}>
      <div style={S.card}>
        <div style={S.logoWrap}>
          <span style={S.logoText}>{theme.logo_text || 'DO'}</span>
        </div>
      </div>
    </div>
  );

  // ── Access blocked — generic message, reveals nothing ──
  if (!accessAllowed) return (
    <div style={S.page}>
      <div style={S.card}>
        <div style={S.logoWrap}>
          <span style={S.logoText}>{theme.logo_text || 'DO'}</span>
          <div style={S.appName}>DataObjects</div>
        </div>
        <div style={{ textAlign:'center', color:'#64748b', fontSize:14, lineHeight:1.7, padding:'8px 0 16px' }}>
          There is either no DataObjects app at this address,
          or this app has restricted access.<br /><br />
          Please contact your administrator.
        </div>
      </div>
    </div>
  );

  return (
    <div style={S.page}>
      <div style={S.card}>

        {/* Logo */}
        <div style={S.logoWrap}>
          {logo}
          {appName && <div style={S.appName}>{appName}</div>}
        </div>

        {/* Back button */}
        {(step === 'options' || step === 'code') && (
          <button style={S.back} onClick={() => {
            clearMsg();
            setPassword('');
            setStep(step === 'code' ? 'options' : 'email');
          }}>← Back</button>
        )}

        {/* ── STEP 1: Email ── */}
        {step === 'email' && (
          <>
            <h1 style={S.heading}>Log in</h1>
            <p style={S.sub}>Enter your email address to continue.</p>
            {error && <div style={S.error}>{error}</div>}
            <form onSubmit={handleEmailSubmit}>
              <div style={{ marginBottom:16 }}>
                <label style={S.label}>Email Address</label>
                <input
                  style={S.input}
                  type="email"
                  value={email}
                  onChange={e => setEmail(e.target.value)}
                  placeholder="you@example.com"
                  autoComplete="email"
                  autoFocus
                  required
                />
              </div>
              <button
                type="submit"
                style={{ ...S.btnPrimary, opacity: loading ? 0.7 : 1 }}
                disabled={loading || !email.trim()}
              >
                {loading ? 'Checking…' : 'Continue →'}
              </button>
            </form>
          </>
        )}

        {/* ── STEP 2: Options ── */}
        {step === 'options' && (
          <>
            <h1 style={S.heading}>Welcome back</h1>
            <p style={S.sub}>Logging in as <strong>{email}</strong></p>

            {error && <div style={S.error}>{error}</div>}
            {info  && <div style={S.info}>{info}</div>}

            {/* Password — only if set */}
            {hasPassword && (
              <>
                <form onSubmit={handlePasswordSubmit}>
                  <div style={{ marginBottom:4 }}>
                    <label style={S.label}>Password</label>
                    <div style={{ position:'relative' }}>
                      <input
                        style={{ ...S.input, paddingRight:38 }}
                        type={showPw ? 'text' : 'password'}
                        value={password}
                        onChange={e => setPassword(e.target.value)}
                        placeholder="Enter your password"
                        autoComplete="current-password"
                        autoFocus
                        required
                      />
                      <button
                        type="button"
                        onClick={() => setShowPw(!showPw)}
                        style={{ position:'absolute', right:10, top:'50%', transform:'translateY(-50%)', background:'none', border:'none', cursor:'pointer', color:'#94a3b8', fontSize:16 }}
                        tabIndex={-1}
                      >{showPw ? '🙈' : '👁'}</button>
                    </div>
                  </div>
                  <label style={S.remember}>
                    <input type="checkbox" checked={remember} onChange={e => setRemember(e.target.checked)} />
                    Remember me for 30 days
                  </label>
                  <button
                    type="submit"
                    style={{ ...S.btnPrimary, opacity: loading ? 0.7 : 1 }}
                    disabled={loading || !password}
                  >
                    {loading ? 'Logging in…' : 'Log In'}
                  </button>
                  <div style={{ textAlign:'right', marginTop:6 }}>
                    <button
                      type="button"
                      style={{ background:'none', border:'none', color:'#64748b', fontSize:12, cursor:'pointer', fontFamily:'inherit', textDecoration:'underline' }}
                      onClick={() => { setPassword(''); handleSendCode('email'); }}
                    >Forgot password?</button>
                  </div>
                </form>

                <div style={S.divider}>
                  <div style={S.divLine} />
                  <span style={S.orLabel}>or</span>
                  <div style={S.divLine} />
                </div>
              </>
            )}

            {/* Send access code — email */}
            <button
              style={{ ...S.btnSecondary, opacity: loading ? 0.6 : 1 }}
              onClick={() => handleSendCode('email')}
              disabled={loading}
            >
              <span style={S.codeIcon}>✉️</span>
              <span>
                <strong style={{ display:'block', fontSize:14 }}>Send Access Code</strong>
                <span style={{ fontSize:12, color:'#94a3b8' }}>We'll email a 6-digit code to {email}</span>
              </span>
            </button>

            {/* Send access code — SMS (only if phone on file) */}
            {hasPhone && (
              <button
                style={{ ...S.btnSecondary, opacity: loading ? 0.6 : 1 }}
                onClick={() => handleSendCode('sms')}
                disabled={loading}
              >
                <span style={S.codeIcon}>📱</span>
                <span>
                  <strong style={{ display:'block', fontSize:14 }}>Send Access Code by Text</strong>
                  <span style={{ fontSize:12, color:'#94a3b8' }}>We'll text a 6-digit code to your phone</span>
                </span>
              </button>
            )}
          </>
        )}

        {/* ── STEP 3: Code entry ── */}
        {step === 'code' && (
          <>
            <h1 style={S.heading}>Enter your code</h1>
            <p style={S.sub}>
              A 6-digit code was sent to{' '}
              {codeVia === 'sms'
                ? 'your phone number on file'
                : <strong>{email}</strong>
              }.
            </p>

            {error && <div style={S.error}>{error}</div>}

            <CodeInput onComplete={handleCodeComplete} disabled={loading} />

            {loading && (
              <p style={{ textAlign:'center', color:'#94a3b8', fontSize:14, margin:'0 0 16px' }}>
                Verifying…
              </p>
            )}

            <label style={S.remember}>
              <input type="checkbox" checked={remember} onChange={e => setRemember(e.target.checked)} />
              Remember me for 30 days
            </label>

            <div style={{ textAlign:'center', marginTop:16, fontSize:13, color:'#94a3b8' }}>
              {canResend ? (
                <>
                  Didn't receive it?{' '}
                  <button style={S.btnLink} onClick={() => handleSendCode(codeVia)}>
                    Send again
                  </button>
                  {hasPhone && (
                    <>
                      {' · '}
                      <button style={S.btnLink} onClick={() => handleSendCode(codeVia === 'sms' ? 'email' : 'sms')}>
                        {codeVia === 'sms' ? 'Send by email instead' : 'Send by text instead'}
                      </button>
                    </>
                  )}
                </>
              ) : (
                <span>Resend available in 30 seconds</span>
              )}
            </div>
          </>
        )}

        {/* Footer */}
        <div style={S.footer}>
          By logging in you accept our{' '}
          <a href="https://dataobjects.com/terms" style={{ color:'#cbd5e1' }}>Terms &amp; Conditions</a>
        </div>

      </div>
    </div>
  );
}
