// live.jsx — auth gate + Google (Gmail/Calendar) real-time connection layer.
// Exposes window.RaiseLive. Talks to Supabase (RaiseDB) for auth + connection
// status, and to the google-api edge function (RaiseGoogle) for live read/send.
const { useState: useStateL, useEffect: useEffectL, useRef: useRefL, useCallback: useCb } = React;
const DB = window.RaiseDB;
const G = window.RaiseGoogle;

// ── session ────────────────────────────────────────────────────────────────
function useSession() {
  const [session, setSession] = useStateL(undefined); // undefined = loading
  useEffectL(() => {
    DB.auth.getSession().then(({ data }) => setSession(data.session || null));
    const { data: sub } = DB.auth.onAuthStateChange((_e, s) => setSession(s));
    return () => sub.subscription.unsubscribe();
  }, []);
  return session;
}

// ── connection status (polls the connections table; near-real-time) ──────────
function useConnections(intervalMs = 15000) {
  const [conns, setConns] = useStateL({});
  const load = useCb(async () => {
    const { data } = await DB.from('connections').select('*');
    if (data) { const m = {}; data.forEach(r => m[r.provider] = r); setConns(m); }
  }, []);
  useEffectL(() => {
    load();
    const id = setInterval(load, intervalMs);
    const onFocus = () => load();
    window.addEventListener('focus', onFocus);
    return () => { clearInterval(id); window.removeEventListener('focus', onFocus); };
  }, [load, intervalMs]);
  return [conns, load];
}

// set a connection row's status from the browser (RLS allows owner writes)
async function setConnStatus(provider, patch) {
  await DB.from('connections').update({ ...patch, updated_at: new Date().toISOString() }).eq('provider', provider);
}

// ── one-time handling of the ?connect=success|error return from OAuth ─────────
function consumeConnectResult() {
  const u = new URL(window.location.href);
  const r = u.searchParams.get('connect');
  if (!r) return null;
  u.searchParams.delete('connect'); u.searchParams.delete('reason');
  window.history.replaceState({}, '', u.toString());
  return r;
}

// ── live calendar hook ───────────────────────────────────────────────────────
// Returns Google events in [timeMin,timeMax]; refetches on interval. Falls back
// to [] (callers can merge with local seed) and surfaces error state.
function useLiveCalendar(timeMin, timeMax, { enabled = true, intervalMs = 30000 } = {}) {
  const CK = 'cal.events';
  const [state, setState] = useStateL(() => {
    const c = window.RaiseCache && window.RaiseCache.get(CK);
    return { events: c || [], loading: enabled && !c, error: null, cached: !!c };
  });
  useEffectL(() => {
    if (!enabled) { setState(s => ({ ...s, loading: false })); return; } // keep cached events
    let alive = true;
    const run = async () => {
      try {
        const items = await G.listCalendar(timeMin, timeMax);
        if (alive) { setState({ events: items, loading: false, error: null, cached: false }); if (window.RaiseCache) window.RaiseCache.set(CK, items); }
      } catch (e) { if (alive) setState(s => ({ ...s, loading: false, error: e.message })); } // keep last/cached events on error
    };
    run();
    const id = setInterval(run, intervalMs);
    return () => { alive = false; clearInterval(id); };
  }, [timeMin, timeMax, enabled, intervalMs]);
  return state;
}

// ── live inbox hook ──────────────────────────────────────────────────────────
function useLiveInbox(q = 'in:inbox', { enabled = true, intervalMs = 30000, maxResults = 25 } = {}) {
  const CK = 'list.' + q;
  const [state, setState] = useStateL(() => {
    const c = window.RaiseCache && window.RaiseCache.get(CK);
    return { messages: c || [], loading: enabled && !c, error: null, cached: !!c };
  });
  useEffectL(() => {
    // re-seed from cache when the query (folder) changes, so switching is instant
    const c = window.RaiseCache && window.RaiseCache.get(CK);
    setState((s) => ({ messages: c || s.messages, loading: enabled && !c, error: null, cached: !!c }));
    if (!enabled) { setState((s) => ({ ...s, loading: false })); return; } // keep cached
    let alive = true;
    const run = async () => {
      try {
        const messages = await G.listInbox(q, maxResults);
        if (alive) { setState({ messages, loading: false, error: null, cached: false }); if (window.RaiseCache) window.RaiseCache.set(CK, messages); }
      } catch (e) { if (alive) setState((s) => ({ ...s, loading: false, error: e.message })); } // keep last/cached on error
    };
    run();
    const id = setInterval(run, intervalMs);
    return () => { alive = false; clearInterval(id); };
  }, [q, enabled, intervalMs, maxResults]);
  return state;
}

// ── safe-build pause flag ────────────────────────────────────────────────────
function useLivePaused() {
  const [paused, setP] = useStateL(G.isPaused());
  useEffectL(() => {
    const sync = () => setP(G.isPaused());
    window.addEventListener('raise-live-paused', sync);
    window.addEventListener('storage', sync);
    return () => { window.removeEventListener('raise-live-paused', sync); window.removeEventListener('storage', sync); };
  }, []);
  return [paused, (v) => G.setPaused(v)];
}

// ── hidden driver: feeds live Google calendar into the existing store ─────────
// Renders nothing. Pauses with the safe-build switch; clears live events when
// paused or disconnected so the calendar shows only seed/local data while building.
function LiveSync() {
  const [conns] = useConnections();
  const [paused] = useLivePaused();
  const calConnected = conns.google_calendar?.status === 'connected';
  const enabled = calConnected && !paused;
  const win = useRefL(null);
  if (!win.current) {
    const a = new Date(); a.setDate(a.getDate() - 7);
    const b = new Date(); b.setDate(b.getDate() + 30);
    win.current = { min: a.toISOString(), max: b.toISOString() };
  }
  const cal = useLiveCalendar(win.current.min, win.current.max, { enabled, intervalMs: 30000 });
  useEffectL(() => {
    const S = window.RaiseStore; if (!S || !S.ingestLive) return;
    if (enabled) S.ingestLive(cal.events || []);
    else if (S.clearLive) S.clearLive();
  }, [cal.events, enabled]);
  return null;
}

// ── sign-in screen ───────────────────────────────────────────────────────────
function SignIn() {
  const [email, setEmail] = useStateL('austin@allstreetcap.com');
  const [pass, setPass] = useStateL('');
  const [busy, setBusy] = useStateL(false);
  const [err, setErr] = useStateL('');
  const [showPw, setShowPw] = useStateL(false);
  const submit = async (e) => {
    e.preventDefault(); setBusy(true); setErr('');
    const { error } = await DB.auth.signInWithPassword({ email, password: pass });
    if (error) { setErr(error.message); setBusy(false); }
  };
  const google = async () => {
    setErr('');
    const { error } = await DB.auth.signInWithOAuth({
      provider: 'google',
      options: { redirectTo: window.location.origin },
    });
    if (error) setErr(error.message);
  };
  return (
    <div style={{ minHeight: '100vh', display: 'grid', placeItems: 'center', background: 'var(--bg,#faf7f3)' }}>
      <div style={{ width: 320, background: '#fff', border: '1px solid #e7e1d8', borderRadius: 14, padding: 28, boxShadow: '0 10px 40px rgba(0,0,0,.06)' }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 10, marginBottom: 18 }}>
          <div style={{ width: 30, height: 30, borderRadius: 8, background: 'var(--primary,#c96442)', color: '#fff', display: 'grid', placeItems: 'center', fontWeight: 700 }}>R</div>
          <div><b style={{ fontSize: 15 }}>Raise OS</b><div style={{ fontSize: 11, color: '#988' }}>FUND II · $10M</div></div>
        </div>
        <button onClick={google} type="button"
          style={{ width: '100%', padding: '10px', display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 10, background: '#fff', color: '#3c4043', border: '1px solid #dadce0', borderRadius: 8, fontWeight: 600, fontSize: 14, cursor: 'pointer' }}>
          <svg width="17" height="17" viewBox="0 0 48 48"><path fill="#EA4335" d="M24 9.5c3.5 0 6.6 1.2 9 3.6l6.7-6.7C35.6 2.5 30.1 0 24 0 14.6 0 6.5 5.4 2.6 13.2l7.8 6.1C12.3 13.2 17.6 9.5 24 9.5z"/><path fill="#4285F4" d="M46.1 24.5c0-1.6-.1-3.1-.4-4.5H24v9h12.4c-.5 2.9-2.1 5.3-4.6 7l7.1 5.5c4.2-3.9 6.6-9.6 6.6-17z"/><path fill="#FBBC05" d="M10.4 28.3c-.5-1.4-.8-2.9-.8-4.3s.3-3 .8-4.3l-7.8-6.1C1 16.5 0 20.1 0 24s1 7.5 2.6 10.4l7.8-6.1z"/><path fill="#34A853" d="M24 48c6.1 0 11.3-2 15-5.5l-7.1-5.5c-2 1.3-4.6 2.1-7.9 2.1-6.4 0-11.7-3.7-13.6-8.8l-7.8 6.1C6.5 42.6 14.6 48 24 48z"/></svg>
          Continue with Google
        </button>
        {err && <div style={{ color: '#c0392b', fontSize: 12, margin: '12px 0 0' }}>{err}</div>}
        {!showPw && <button type="button" onClick={() => setShowPw(true)} style={{ width: '100%', marginTop: 14, background: 'none', border: 'none', color: '#988', fontSize: 12, cursor: 'pointer' }}>Use email & password instead</button>}
        {!showPw ? null : <form onSubmit={submit} style={{ marginTop: 16, paddingTop: 16, borderTop: '1px solid #f0ebe3' }}>
        <label style={{ fontSize: 12, color: '#766' }}>Email</label>
        <input value={email} onChange={e => setEmail(e.target.value)} autoComplete="username"
          style={{ width: '100%', padding: '9px 11px', margin: '4px 0 12px', border: '1px solid #ddd5ca', borderRadius: 8, fontSize: 14 }} />
        <label style={{ fontSize: 12, color: '#766' }}>Password</label>
        <input value={pass} onChange={e => setPass(e.target.value)} type="password" autoComplete="current-password"
          style={{ width: '100%', padding: '9px 11px', margin: '4px 0 16px', border: '1px solid #ddd5ca', borderRadius: 8, fontSize: 14 }} />
        {err && <div style={{ color: '#c0392b', fontSize: 12, marginBottom: 10 }}>{err}</div>}
        <button disabled={busy} type="submit"
          style={{ width: '100%', padding: '10px', background: 'var(--primary,#c96442)', color: '#fff', border: 'none', borderRadius: 8, fontWeight: 600, cursor: 'pointer', opacity: busy ? .6 : 1 }}>
          {busy ? 'Signing in…' : 'Sign in'}
        </button>
      </form>}
      </div>
    </div>
  );
}

// ── auth gate: wraps the app ─────────────────────────────────────────────────
function AuthGate({ children }) {
  const session = useSession();
  if (session === undefined) return <div style={{ minHeight: '100vh', display: 'grid', placeItems: 'center', color: '#988' }}>Loading…</div>;
  if (!session) return <SignIn />;
  return children;
}

// ── Google connection card (used in Settings) ────────────────────────────────
const STATUS_META = {
  disconnected: { label: 'Not connected', color: '#9b9285', dot: '#c9c1b5' },
  connecting:   { label: 'Connecting…',   color: '#c08a2a', dot: '#e0a25e' },
  connected:    { label: 'Connected',     color: '#3f9560', dot: '#3f9560' },
  syncing:      { label: 'Syncing…',      color: '#4a78c8', dot: '#4a78c8' },
  error:        { label: 'Error',         color: '#c0392b', dot: '#c0392b' },
};

function GoogleConnectionCard() {
  const [conns, reload] = useConnections();
  const [toastMsg, setToastMsg] = useStateL('');
  const [paused, setPaused] = useLivePaused();
  const cal = conns.google_calendar || { status: 'disconnected' };
  const mail = conns.gmail || { status: 'disconnected' };
  // treat the pair as one Google account
  const status = cal.status === 'error' || mail.status === 'error' ? 'error'
    : (cal.status === 'connected' && mail.status === 'connected') ? 'connected'
    : (cal.status === 'connecting' || mail.status === 'connecting') ? 'connecting'
    : cal.status || 'disconnected';
  const meta = STATUS_META[status] || STATUS_META.disconnected;
  const account = cal.account_email || mail.account_email;
  const lastSync = cal.last_sync || mail.last_sync;

  useEffectL(() => {
    const r = consumeConnectResult();
    if (r === 'success') { setToastMsg('Google connected'); reload(); }
    else if (r === 'error') { setToastMsg('Connection failed — try again'); reload(); }
  }, []);

  const connect = async () => {
    await setConnStatus('gmail', { status: 'connecting' });
    await setConnStatus('google_calendar', { status: 'connecting' });
    G.connect(); // navigates away to Google
  };
  const disconnect = async () => {
    await setConnStatus('gmail', { status: 'disconnected', account_email: null, last_sync: null });
    await setConnStatus('google_calendar', { status: 'disconnected', account_email: null, last_sync: null });
    reload();
  };
  const fmt = (t) => t ? new Date(t).toLocaleString('en-US', { month: 'short', day: 'numeric', hour: 'numeric', minute: '2-digit' }) : '—';

  return (
    <>
      <div className="sett-title">Google · Gmail & Calendar</div>
      <div className="setcard">
        <div className="field">
          <div style={{ display: 'flex', alignItems: 'center', gap: 11 }}>
            <span style={{ width: 9, height: 9, borderRadius: '50%', background: meta.dot, boxShadow: status === 'connected' ? '0 0 0 3px ' + meta.dot + '22' : 'none' }} />
            <div>
              <div className="fk">{meta.label}{account ? ' · ' + account : ''}</div>
              <div className="fd">
                {status === 'connected'
                  ? 'Real-time read + send is live. Last activity ' + fmt(lastSync) + '.'
                  : status === 'error'
                    ? 'Token or API error — reconnect to restore. ' + (cal.last_error || mail.last_error || '')
                    : status === 'connecting'
                      ? 'Finishing Google authorization…'
                      : 'Connect your Google account to pull live calendar + inbox and send in real time.'}
              </div>
            </div>
          </div>
          <div className="fc2" style={{ display: 'flex', gap: 8 }}>
            {status === 'connected'
              ? <><button className="btn sm" onClick={connect}>Reconnect</button><button className="btn sm" onClick={disconnect}>Disconnect</button></>
              : <button className="btn sm" style={{ background: 'var(--primary)', color: '#fff', borderColor: 'transparent' }} onClick={connect}>
                  {status === 'error' ? 'Reconnect' : 'Connect Google'}
                </button>}
          </div>
        </div>
        <div className="field">
          <div>
            <div className="fk">Live actions {paused ? '· Paused (safe build mode)' : '· Active'}</div>
            <div className="fd">{paused
              ? 'Send + sync are OFF — clicking Send logs locally and never emails anyone. Flip on when you want real sends/reads.'
              : 'Live: the composer sends real email and the calendar pulls live Google events.'}</div>
          </div>
          <div className="seg fc2">
            <button className={paused ? 'on' : ''} onClick={() => setPaused(true)}>Paused</button>
            <button className={!paused ? 'on' : ''} onClick={() => setPaused(false)}>Live</button>
          </div>
        </div>
        {status === 'connected' && (
          <div className="sett-accts">
            <div className="sett-acct">
              <span className="sett-acct-dot" style={{ background: 'var(--primary)' }} />
              <div className="sett-acct-meta"><b>Calendar</b><small>{cal.detail?.events != null ? cal.detail.events + ' events in window' : 'live'}</small></div>
              <span className="sett-acct-conn"><span className="edot" />Live</span>
            </div>
            <div className="sett-acct">
              <span className="sett-acct-dot" style={{ background: 'var(--green)' }} />
              <div className="sett-acct-meta"><b>Gmail</b><small>read + send</small></div>
              <span className="sett-acct-conn"><span className="edot" />Live</span>
            </div>
          </div>
        )}
        {toastMsg && <div className="fd" style={{ marginTop: 8, color: 'var(--ink-2)' }}>{toastMsg}</div>}
      </div>
    </>
  );
}

async function signOut() { await DB.auth.signOut(); location.reload(); }

window.RaiseLive = {
  useSession, useConnections, useLiveCalendar, useLiveInbox, useLivePaused,
  AuthGate, SignIn, GoogleConnectionCard, LiveSync, setConnStatus, consumeConnectResult, signOut,
};
