/**
 * @ai-summary Google Maps JavaScript API loader
 * Handles dynamic loading and singleton pattern
 */

import { getGoogleMapsApiKey } from '@/core/config/config.types';

let mapsPromise: Promise<void> | null = null;

/**
 * Load Google Maps JavaScript API dynamically
 * Uses singleton pattern - only loads once
 *
 * @returns Promise that resolves when Google Maps is loaded
 */
export function loadGoogleMaps(): Promise<void> {
  // Return cached promise if already loading/loaded
  if (mapsPromise) {
    return mapsPromise;
  }

  // Create loading promise
  mapsPromise = new Promise((resolve, reject) => {
    // Check if already loaded in window
    if ((window as any).google?.maps) {
      resolve();
      return;
    }

    // Get API key from runtime config
    const apiKey = getGoogleMapsApiKey();

    if (!apiKey) {
      reject(new Error('Google Maps API key is not configured'));
      return;
    }

    // Create a global callback for Google Maps to call when ready
    const callbackName = `gmapsCallback_${Date.now()}`;
    (window as any)[callbackName] = () => {
      if ((window as any).google?.maps) {
        resolve();
      } else {
        reject(
          new Error('Google Maps loaded but window.google.maps not available')
        );
      }
      // Clean up callback
      delete (window as any)[callbackName];
    };

    // Create script tag with callback
    // The callback parameter tells Google Maps to call our function when ready
    // Using async + callback ensures Google Maps initializes asynchronously
    const script = document.createElement('script');
    script.src = `https://maps.googleapis.com/maps/api/js?key=${apiKey}&callback=${callbackName}&libraries=places,marker&loading=async`;
    script.async = true;
    script.defer = true; // Load asynchronously without blocking parsing (per Maps best practices)

    script.onerror = () => {
      // Reset promise so retry is possible
      mapsPromise = null;
      delete (window as any)[callbackName];
      reject(new Error('Failed to load Google Maps script'));
    };

    // Add to document
    document.head.appendChild(script);
  });

  return mapsPromise;
}

/**
 * Get Google Maps API (after loading)
 *
 * @returns Google Maps object
 * @throws Error if Google Maps not loaded
 */
export function getGoogleMapsApi(): typeof google.maps {
  if (!(window as any).google?.maps) {
    throw new Error('Google Maps not loaded. Call loadGoogleMaps() first.');
  }

  return (window as any).google.maps;
}

/**
 * Reset loader (for testing)
 */
export function resetMapsLoader(): void {
  mapsPromise = null;
}
