'use client';

// Changes to the way hcaptcha is loaded have caused 3 incidents where users are unable to generate
// because they couldn't complete captchas. hcaptcha must *only* be loaded using this component.
// One likely failure mode if this is changed is a race condition that will *sometimes* cause hcaptcha
// to fail when the page is loaded. Casual testing is not enough to catch this. If you make changes here,
// please do extended validation in local dev and staging. Ensure you can pass a visual captcha on several
// fresh page loads on each of several browsers. Add @natdempk or @marc-suno as reviewers.
import HCaptcha from '@hcaptcha/react-hcaptcha';
import * as Sentry from '@sentry/nextjs';
import { observer } from 'mobx-react-lite';
import { usePathname } from 'next/navigation';
import { useCallback, useEffect, useRef } from 'react';

import { useLocation } from '@/hooks/useLocation';
import { FORCE_ENABLE_CAPTCHA } from '@/state/sessionStore';
import { PageEventType, eventLogger } from '@/utils/event-logger';

import { useStores } from './AppProviders';

export type Props = {
  wrapperClassName?: string;
};

const Captcha: React.FC<Props> = observer((props) => {
  const { wrapperClassName } = props;

  const { session: sessionStore } = useStores();
  const captchaRef = useRef<HCaptcha>(null);
  const pathname = usePathname();
  const location = useLocation();
  const nonLocalHost = !location?.hostname?.includes('localhost');
  const userId = sessionStore.userId ?? '';

  const handleHCaptchaOpen = useCallback(() => {
    eventLogger.logWebPageEvent({
      userId,
      element: 'hcaptcha_challenge',
      eventType: PageEventType.VIEW,
      pageUrl: pathname,
    });
  }, [pathname, userId]);

  const handleHCaptchaClose = useCallback(() => {
    eventLogger.logWebPageEvent({
      userId,
      element: 'hcaptcha_challenge_closed',
      eventType: PageEventType.VIEW,
      pageUrl: pathname,
    });
  }, [pathname, userId]);

  const handleHCaptchaError = useCallback((error: string) => {
    Sentry.captureException(`HCaptcha error: "${error}"`);
  }, []);

  const handleHCaptchaChallengeExpired = useCallback(() => {
    eventLogger.logWebPageEvent({
      userId,
      element: 'hcaptcha_challenge_expired',
      eventType: PageEventType.VIEW,
      pageUrl: pathname,
    });
  }, [pathname, userId]);

  /**
   * Give the session a way to get the captcha token
   */
  useEffect(() => {
    sessionStore.captchaVerification = async () => {
      if (!captchaRef.current) return null;
      const response = await captchaRef.current.execute({ async: true });
      return response.response || null;
    };
  }, [sessionStore]);

  if (!nonLocalHost && !FORCE_ENABLE_CAPTCHA) {
    return null;
  }

  const hcaptchaEnvironment =
    process.env.NEXT_PUBLIC_NODE_ENV === 'production' ? 'prod' : 'staging';

  return (
    <div className={wrapperClassName}>
      <HCaptcha
        sitekey={process.env.NEXT_PUBLIC_GENERATION_HCAPTCHA_KEY!}
        onOpen={handleHCaptchaOpen}
        onClose={handleHCaptchaClose}
        onError={handleHCaptchaError}
        onChalExpired={handleHCaptchaChallengeExpired}
        size='invisible'
        ref={captchaRef}
        // disable sentry for hcaptcha because it initializes a duplicate instance with a different version
        // hcaptcha readme: https://github.com/hCaptcha/react-hcaptcha/blob/master/README.md#avoid-conflicts-with-legacy-sentry-package-usage-on-react-hcaptcha-190
        // sentry issue: https://github.com/getsentry/sentry-javascript/issues/10310#issuecomment-2023916659
        // where it's loaded: https://github.com/hCaptcha/hcaptcha-loader/blob/543c7aabbb5f682dcde5d6d5553120e963f402bc/lib/src/sentry.ts#L15-L18
        sentry={false}
        // Be very careful when changing these, and never remove them! See the comment at the top of the file.
        scriptSource={`https://hcaptcha-endpoint-${hcaptchaEnvironment}.suno.com/1/api.js`}
        // @ts-expect-error react-hcaptcha forgot to include a type for endpoint
        // see https://github.com/hCaptcha/react-hcaptcha
        // and https://github.com/hCaptcha/hcaptcha-loader
        endpoint={`https://hcaptcha-endpoint-${hcaptchaEnvironment}.suno.com`}
        assethost={`https://hcaptcha-assets-${hcaptchaEnvironment}.suno.com`}
        imghost={`https://hcaptcha-imgs-${hcaptchaEnvironment}.suno.com`}
        reportapi={`https://hcaptcha-reportapi-${hcaptchaEnvironment}.suno.com`}
        render={`explicit`}
      />
    </div>
  );
});

export default Captcha;
