// auth.jsx — Clerk authentication abstraction for the browser.
// All Clerk SDK calls are isolated here. The rest of the app only uses:
//   AuthProvider, useAuthState(), useAuthHeaders(), AuthButton

const { useState: useAuthStateHook, useEffect: useAuthEffect, useRef: useAuthRef, createContext, useContext } = React;

const AuthContext = createContext(null);

function AuthProvider({ children }) {
  const [state, setState] = useAuthStateHook({ isLoaded: false, isSignedIn: false, user: null });
  const clerkRef = useAuthRef(null);

  const clerkLoadedRef = useAuthRef(false);

  useAuthEffect(() => {
    const scriptTag = document.querySelector('script[data-clerk-publishable-key]');
    const key = scriptTag ? scriptTag.getAttribute('data-clerk-publishable-key') : '';
    if (!key || !key.startsWith('pk_')) {
      console.warn('[auth] data-clerk-publishable-key missing or invalid — read-only mode. Got:', key);
      setState({ isLoaded: true, isSignedIn: false, user: null });
      return;
    }

    const waitForClerk = () => new Promise(resolve => {
      if (window.__clerkReady && window.Clerk) return resolve(window.Clerk);
      const iv = setInterval(() => {
        if (window.__clerkReady && window.Clerk) { clearInterval(iv); resolve(window.Clerk); }
      }, 50);
    });

    (async () => {
      try {
        const clerk = await waitForClerk();
        clerkRef.current = clerk;
        const scriptTag = document.querySelector('script[data-clerk-publishable-key]');
        console.log('[auth] publishable key starts with:', scriptTag?.getAttribute('data-clerk-publishable-key')?.substring(0, 20));
        await clerk.load({ afterSignOutUrl: 'https://familycookbook.ai' });
        clerkLoadedRef.current = true;
        console.log('[auth] clerk loaded');
        console.log('[auth] clerk.user:', clerk.user);
        console.log('[auth] clerk.session:', clerk.session);
        if (!clerk.user) {
          document.cookie.split(';').forEach(c => {
            document.cookie = c.replace(/^ +/, '').replace(/=.*/, '=;expires=' + new Date().toUTCString() + ';path=/');
          });
        }
        setState({ isLoaded: true, isSignedIn: !!clerk.user, user: clerk.user || null });
        clerk.addListener(({ user }) => {
          setState({ isLoaded: true, isSignedIn: !!user, user: user || null });
        });
      } catch (err) {
        console.error('[auth] Clerk failed to load:', err);
        setState({ isLoaded: true, isSignedIn: false, user: null });
      }
    })();
  }, []);

  async function getAuthHeaders() {
    const clerk = clerkRef.current;
    if (!clerk || !clerk.session) return {};
    try {
      const token = await clerk.session.getToken();
      return token ? { Authorization: `Bearer ${token}` } : {};
    } catch {
      return {};
    }
  }

  function openSignIn() {
    window.location.href = '/sign-in';
  }

  function openSignUp() {
    if (!clerkLoadedRef.current || !clerkRef.current) {
      console.warn('[auth] openSignUp called before clerk.load() resolved');
      return;
    }
    clerkRef.current.openSignUp();
  }

  function signOut() {
    const clerk = clerkRef.current;
    if (clerk) clerk.signOut({ redirectUrl: 'https://familycookbook.ai' });
  }

  return (
    <AuthContext.Provider value={{ ...state, getAuthHeaders, openSignIn, openSignUp, signOut, clerkRef, clerkLoadedRef }}>
      {children}
    </AuthContext.Provider>
  );
}

function useAuthState() {
  const ctx = useContext(AuthContext);
  if (!ctx) throw new Error('useAuthState must be used inside AuthProvider');
  return ctx;
}

// Convenience hook: returns a function that resolves to { Authorization: "Bearer ..." }
// (or {}) and a boolean indicating whether the user is signed in.
function useAuthHeaders() {
  const { isSignedIn, getAuthHeaders } = useAuthState();
  return { isSignedIn, getAuthHeaders };
}

// Header button: shows Clerk's native UserButton when signed in, or a "Sign In"
// button when signed out. Uses clerk.mountUserButton() so Clerk handles the
// avatar, sign-out menu, and profile management natively.
function AuthButton() {
  const { isSignedIn, clerkRef, clerkLoadedRef } = useAuthState();
  const containerRef = useAuthRef(null);

  useAuthEffect(() => {
    const clerk = clerkRef.current;
    if (!isSignedIn || !clerk || !containerRef.current) return;
    clerk.mountUserButton(containerRef.current);
    return () => {
      try { clerk.unmountUserButton(containerRef.current); } catch {}
    };
  }, [isSignedIn]);

  // When signed in, swap to Clerk's native UserButton (avatar + sign-out menu).
  if (isSignedIn) {
    return <div ref={containerRef} className="auth-user-btn" />;
  }

  // Always render the Sign In button. On click, wait for Clerk to be ready
  // (initialization is async) before calling openSignIn().
  function handleSignIn() {
    window.location.href = '/sign-in';
  }

  return (
    <button className="ghost-btn auth-sign-in-btn" onClick={handleSignIn} title="Sign in">
      <IconUsers size={18} stroke={1.7} />
      <span>Sign In</span>
    </button>
  );
}

// Shared Clerk `appearance` — heirloom palette (cream paper, bottle-green
// accent, Young Serif headings, Lato body). Applied to every mounted Clerk
// component (sign-in, invite sign-up) so all auth surfaces match the app.
// Values mirror the CSS tokens in app.css.
const CLERK_APPEARANCE = {
  variables: {
    colorPrimary:          '#1f4a38',  // --accent (bottle green)
    colorText:             '#241d12',  // --ink
    colorTextSecondary:    '#6e5f45',  // --muted
    colorBackground:       '#fdf8ec',  // paper card
    colorInputBackground:  '#ffffff',
    colorInputText:        '#241d12',
    colorDanger:           '#a32d2d',
    borderRadius:          '10px',
    fontFamily:            "'Lato', -apple-system, sans-serif",
    fontFamilyButtons:     "'Lato', -apple-system, sans-serif",
    fontSize:              '15px',
  },
  elements: {
    rootBox:              { width: '100%' },
    card: {
      boxShadow:    '0 12px 30px rgba(36,29,18,0.10)',
      border:       '1px solid #d9ccae',
      borderRadius: '12px',
      background:   '#fdf8ec',
    },
    headerTitle: {
      fontFamily: "'Young Serif', Georgia, serif",
      fontWeight: 400,
      color:      '#1f4a38',
      fontSize:   '1.45rem',
    },
    headerSubtitle: { color: '#6e5f45' },
    formButtonPrimary: {
      background:    '#1f4a38',
      color:         '#f4eee0',
      fontWeight:    700,
      textTransform: 'none',
      fontSize:      '0.95rem',
      borderRadius:  '99px',
      boxShadow:     'none',
      '&:hover':     { background: '#16382a' },
      '&:focus':     { background: '#16382a' },
    },
    socialButtonsBlockButton: {
      border:       '1px solid #d9ccae',
      borderRadius: '99px',
      background:   '#ffffff',
      color:        '#241d12',
      '&:hover':    { background: '#f4eee0' },
    },
    formFieldInput: {
      border:       '1px solid #d9ccae',
      borderRadius: '8px',
      background:   '#ffffff',
      '&:focus':    { borderColor: '#1f4a38', boxShadow: '0 0 0 3px rgba(31,74,56,0.15)' },
    },
    formFieldLabel:        { color: '#463a28', fontWeight: 700 },
    dividerLine:           { background: '#d9ccae' },
    dividerText:           { color: '#6e5f45' },
    footerActionText:      { color: '#6e5f45' },
    footerActionLink:      { color: '#1f4a38', fontWeight: 700, '&:hover': { color: '#16382a' } },
    identityPreviewEditButton: { color: '#1f4a38' },
    formResendCodeLink:    { color: '#1f4a38' },
    otpCodeFieldInput:     { borderColor: '#d9ccae' },
    // Hide the "Secured by Clerk" badge — visually noisy against the paper card.
    footer:                { background: 'transparent' },
    logoBox:               { display: 'none' },
  },
};

// Full-page auth view (sign-in or sign-up) using Clerk's mountSignIn() /
// mountSignUp(), wrapped in the heirloom chrome (wordmark + tagline like the
// landing page). Both modes point at each other in-app (signUpUrl/signInUrl)
// so the whole journey stays on our domain instead of bouncing to Clerk's
// hosted portal. Rendered at /sign-in and /sign-up.
function AuthPage({ mode = 'sign-in' }) {
  const { isSignedIn, clerkRef, clerkLoadedRef } = useAuthState();
  const containerRef = useAuthRef(null);
  const isSignUp = mode === 'sign-up';

  useAuthEffect(() => {
    if (isSignedIn) {
      window.location.replace('/app');
      return;
    }
    function tryMount() {
      if (clerkLoadedRef.current && clerkRef.current && containerRef.current) {
        const opts = {
          redirectUrl:    '/app',
          afterSignInUrl: '/app',
          afterSignUpUrl: '/app',
          signInUrl:      '/sign-in',
          signUpUrl:      '/sign-up',
          appearance:     CLERK_APPEARANCE,
        };
        if (isSignUp) clerkRef.current.mountSignUp(containerRef.current, opts);
        else          clerkRef.current.mountSignIn(containerRef.current, opts);
        return;
      }
      setTimeout(tryMount, 50);
    }
    tryMount();
    return () => {
      try {
        if (clerkRef.current && containerRef.current) {
          if (isSignUp) clerkRef.current.unmountSignUp(containerRef.current);
          else          clerkRef.current.unmountSignIn(containerRef.current);
        }
      } catch {}
    };
  }, [isSignedIn, isSignUp]);

  return (
    <div className="sign-in-page">
      <div className="sign-in-card">
        <a className="sign-in-wordmark" href="/">
          <span className="sign-in-wm-serif">Family Cookbook</span>
          <span className="sign-in-wm-hand">a keepsake, not an app</span>
        </a>
        <div ref={containerRef} className="sign-in-clerk" />
        <p className="sign-in-foot">
          <a href="/">← Back to familycookbook.ai</a>
        </p>
      </div>
    </div>
  );
}
function SignInPage() { return <AuthPage mode="sign-in" />; }

// Waitlist capture — shown in LAUNCH_MODE=waitlist wherever a stranger would
// otherwise start a new cookbook: the /sign-up page and the in-app no-family
// screen. Email-only (no Clerk account is created), posts to /api/waitlist.
// `compact` drops the page chrome for embedding inside the app.
function WaitlistForm({ source = 'signup-page', compact = false }) {
  const [email, setEmail] = useAuthStateHook('');
  const [name,  setName]  = useAuthStateHook('');
  const [busy,  setBusy]  = useAuthStateHook(false);
  const [done,  setDone]  = useAuthStateHook(false);
  const [err,   setErr]   = useAuthStateHook('');

  async function submit(e) {
    e.preventDefault();
    if (busy) return;
    setBusy(true); setErr('');
    try {
      const res = await fetch('/api/waitlist', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ email, name, source }),
      });
      const data = await res.json().catch(() => ({}));
      if (!res.ok) throw new Error(data.error || 'Something went wrong — please try again.');
      setDone(true);
    } catch (ex) {
      setErr(ex.message);
    } finally {
      setBusy(false);
    }
  }

  if (done) {
    return (
      <div className={`waitlist ${compact ? 'compact' : ''}`}>
        <p className="wl-eyebrow">you're on the list</p>
        <h2 className="wl-title">Saved you a seat.</h2>
        <p className="wl-sub">
          We'll email you the moment the doors open. Until then — go call your
          grandmother and ask how she really makes the gravy.
        </p>
      </div>
    );
  }

  return (
    <form className={`waitlist ${compact ? 'compact' : ''}`} onSubmit={submit}>
      <p className="wl-eyebrow">not quite open yet</p>
      <h2 className="wl-title">Save your seat at the table.</h2>
      <p className="wl-sub">
        We're setting the table for a small first group of families. Leave your
        email and we'll send you an invitation the moment we're ready.
      </p>
      <input
        className="ob-input"
        type="text"
        value={name}
        onChange={e => setName(e.target.value)}
        placeholder="Your name (optional)"
        maxLength={80}
        autoComplete="name"
      />
      <input
        className="ob-input"
        type="email"
        value={email}
        onChange={e => setEmail(e.target.value)}
        placeholder="you@example.com"
        maxLength={254}
        required
        autoComplete="email"
        autoFocus={!compact}
      />
      {err && <p className="ob-err">{err}</p>}
      <button className="primary-btn big" type="submit" disabled={busy || !email}>
        {busy ? 'Saving your seat…' : 'Save my seat'}
      </button>
      <p className="ob-skip">Already invited by family? <a href="/sign-in">Sign in here.</a></p>
    </form>
  );
}

// /sign-up: in waitlist mode this is the waitlist page (no Clerk account is
// created); in open mode it's the branded Clerk sign-up. Mode comes from
// /api/config, fetched here so the page works before the app boots.
function SignUpPage() {
  const [mode, setMode] = useAuthStateHook(null); // null = loading
  useAuthEffect(() => {
    fetch('/api/config').then(r => r.json())
      .then(c => setMode(c.launchMode === 'open' ? 'open' : 'waitlist'))
      .catch(() => setMode('waitlist')); // fail closed
  }, []);
  if (mode === 'open') return <AuthPage mode="sign-up" />;
  return (
    <div className="sign-in-page">
      <div className="sign-in-card">
        <a className="sign-in-wordmark" href="/">
          <span className="sign-in-wm-serif">Family Cookbook</span>
          <span className="sign-in-wm-hand">a keepsake, not an app</span>
        </a>
        {mode === null
          ? <div className="sign-in-clerk" />
          : <div className="waitlist-card"><WaitlistForm source="signup-page" /></div>}
        <p className="sign-in-foot">
          <a href="/">← Back to familycookbook.ai</a>
        </p>
      </div>
    </div>
  );
}

Object.assign(window, { AuthProvider, useAuthState, useAuthHeaders, AuthButton, SignInPage, SignUpPage, WaitlistForm, CLERK_APPEARANCE });
