import { useEffect, useRef } from 'react';

const SITE_KEY = import.meta.env.VITE_RECAPTCHA_SITE_KEY;
const SRC = 'https://www.google.com/recaptcha/api.js?render=explicit';

// When no site key is configured, the captcha is disabled everywhere and the
// login/signup buttons are not gated by it.
export const RECAPTCHA_ENABLED = Boolean(SITE_KEY);

// Load the reCAPTCHA script once and share the promise.
let scriptPromise;
function loadScript() {
  if (window.grecaptcha?.render) return Promise.resolve();
  if (!scriptPromise) {
    scriptPromise = new Promise((resolve, reject) => {
      const s = document.createElement('script');
      s.src = SRC;
      s.async = true;
      s.defer = true;
      s.onload = resolve;
      s.onerror = () => {
        scriptPromise = undefined; // allow a retry on next mount
        reject(new Error('Failed to load reCAPTCHA'));
      };
      document.head.appendChild(s);
    });
  }
  return scriptPromise;
}

/**
 * Renders Google's reCAPTCHA v2 ("I'm not a robot") checkbox.
 * - onChange(token) fires with the token when solved, and with '' when it
 *   expires/errors or is reset.
 * - Bump `resetSignal` (a changing number) to reset the widget, e.g. after a
 *   failed submit (the token is single-use).
 *
 * NOTE: `onChange` should be memoized (useCallback) by the parent.
 */
export default function Recaptcha({ onChange, resetSignal = 0 }) {
  const ref = useRef(null);
  const widgetId = useRef(null);

  useEffect(() => {
    if (!SITE_KEY) return undefined;
    let cancelled = false;

    loadScript()
      .then(() => {
        if (cancelled || !ref.current) return;
        window.grecaptcha.ready(() => {
          // Guard against a double render (React StrictMode runs effects twice).
          if (cancelled || !ref.current || widgetId.current !== null) return;
          widgetId.current = window.grecaptcha.render(ref.current, {
            sitekey: SITE_KEY,
            callback: (token) => onChange(token),
            'expired-callback': () => onChange(''),
            'error-callback': () => onChange(''),
          });
        });
      })
      .catch(() => {});

    return () => {
      cancelled = true;
    };
  }, [onChange]);

  // Reset the widget when the parent bumps resetSignal.
  useEffect(() => {
    if (resetSignal && widgetId.current !== null && window.grecaptcha) {
      window.grecaptcha.reset(widgetId.current);
      onChange('');
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [resetSignal]);

  if (!SITE_KEY) return null;
  return <div className="recaptcha-wrap" ref={ref} />;
}
