const TURNSTILE_SCRIPT_ID = 'termi-turnstile-script';
const TURNSTILE_SCRIPT_SRC =
  'https://challenges.cloudflare.com/turnstile/v0/api.js?render=explicit';

type TurnstileApi = {
  render: (
    container: HTMLElement,
    options: Record<string, unknown>,
  ) => string | number;
  reset: (widgetId?: string | number) => void;
  remove?: (widgetId?: string | number) => void;
};

declare global {
  interface Window {
    turnstile?: TurnstileApi;
    __termiTurnstileLoader__?: Promise<TurnstileApi>;
  }
}

export type MountedTurnstile = {
  reset: () => void;
  remove: () => void;
};

async function loadTurnstileScript(): Promise<TurnstileApi> {
  if (window.turnstile) {
    return window.turnstile;
  }

  if (!window.__termiTurnstileLoader__) {
    window.__termiTurnstileLoader__ = new Promise<TurnstileApi>((resolve, reject) => {
      const existing = document.getElementById(TURNSTILE_SCRIPT_ID) as HTMLScriptElement | null;

      const handleReady = () => {
        if (window.turnstile) {
          resolve(window.turnstile);
        } else {
          reject(new Error('Turnstile script loaded without API'));
        }
      };

      if (existing) {
        existing.addEventListener('load', handleReady, { once: true });
        existing.addEventListener(
          'error',
          () => reject(new Error('Failed to load Turnstile script')),
          { once: true },
        );
        return;
      }

      const script = document.createElement('script');
      script.id = TURNSTILE_SCRIPT_ID;
      script.src = TURNSTILE_SCRIPT_SRC;
      script.async = true;
      script.defer = true;
      script.addEventListener('load', handleReady, { once: true });
      script.addEventListener(
        'error',
        () => reject(new Error('Failed to load Turnstile script')),
        { once: true },
      );
      document.head.appendChild(script);
    });
  }

  return window.__termiTurnstileLoader__;
}

export async function mountTurnstile(
  container: HTMLElement,
  options: {
    siteKey: string;
    onToken: (token: string) => void;
    onExpire?: () => void;
    onError?: () => void;
  },
): Promise<MountedTurnstile> {
  const turnstile = await loadTurnstileScript();

  container.innerHTML = '';

  const widgetId = turnstile.render(container, {
    sitekey: options.siteKey,
    callback: (token: string) => {
      options.onToken(token);
    },
    'expired-callback': () => {
      options.onExpire?.();
    },
    'error-callback': () => {
      options.onError?.();
    },
  });

  return {
    reset() {
      turnstile.reset(widgetId);
    },
    remove() {
      if (typeof turnstile.remove === 'function') {
        turnstile.remove(widgetId);
      } else {
        turnstile.reset(widgetId);
      }
      container.innerHTML = '';
    },
  };
}
