"use client";

import { useState, useRef, useEffect } from "react";
import { MapPin, Search, X } from "lucide-react";

// Declare Google Maps types
declare global {
  interface Window {
    google: any;
    gm_authFailure?: () => void;
  }
}

// Type definitions for Google Maps Geocoder
interface GeocoderResult {
  formatted_address: string;
  geometry: {
    location: {
      lat: () => number;
      lng: () => number;
    };
  };
  address_components?: Array<{
    long_name: string;
    short_name: string;
    types: string[];
  }>;
  [key: string]: any;
}

type GeocoderStatus = 'OK' | 'ZERO_RESULTS' | 'OVER_QUERY_LIMIT' | 'REQUEST_DENIED' | 'INVALID_REQUEST' | 'UNKNOWN_ERROR';

export interface LocationDetails {
  address?: string;
  state?: string;
  city?: string;
  locality?: string;
  pincode?: string;
  landmark?: string;
}

interface GoogleMapLocationPickerProps {
  value: string;
  onChange: (location: string, lat?: number, lng?: number, details?: LocationDetails) => void;
  placeholder?: string;
  height?: string;
}

export default function GoogleMapLocationPicker({
  value,
  onChange,
  placeholder = "Search location or click on map",
  height = "400px",
}: GoogleMapLocationPickerProps) {
  const [searchQuery, setSearchQuery] = useState("");
  const [showMap, setShowMap] = useState(false);
  const [selectedLocation, setSelectedLocation] = useState<{ lat: number; lng: number; address: string } | null>(null);
  const [mapLoaded, setMapLoaded] = useState(false);
  const mapRef = useRef<HTMLDivElement>(null);
  const mapInstanceRef = useRef<any>(null);
  const markerRef = useRef<any>(null);
  const autocompleteRef = useRef<any>(null);
  const searchInputRef = useRef<HTMLInputElement>(null);

  // Load Google Maps script
  useEffect(() => {
    if (showMap && !mapLoaded) {
      const apiKey = process.env.NEXT_PUBLIC_GOOGLE_MAPS_API_KEY;

      console.log("API Key check:", {
        hasKey: !!apiKey,
        keyLength: apiKey?.length,
        keyPrefix: apiKey?.substring(0, 10),
        fullKey: apiKey // Only log in dev, remove in production
      });

      if (!apiKey) {
        alert("Google Maps API key is not configured.\n\nPlease add NEXT_PUBLIC_GOOGLE_MAPS_API_KEY to your .env.local file.\n\nTo get an API key:\n1. Go to https://console.cloud.google.com/\n2. Create a project\n3. Enable 'Maps JavaScript API' and 'Places API'\n4. Create credentials (API Key)\n5. Add: NEXT_PUBLIC_GOOGLE_MAPS_API_KEY=your_key_here\n\nAfter adding, restart your dev server!");
        setShowMap(false);
        return;
      }

      // Validate API key format (should start with AIza)
      if (!apiKey.startsWith('AIza')) {
        console.error("Invalid API key format. Google Maps API keys should start with 'AIza'");
        alert(`Invalid API key format detected.\n\nThe API key should start with 'AIza' but yours starts with '${apiKey.substring(0, 4)}'.\n\nPlease check:\n1. The API key in your .env.local file is correct\n2. There are no extra spaces or quotes around the key\n3. The key is copied completely from Google Cloud Console\n4. Restart your dev server after updating the key`);
        setShowMap(false);
        return;
      }

      // Set up global error handler for Google Maps API errors
      window.gm_authFailure = () => {
        const errorMsg = `Google Maps API Error: Invalid API key or API not enabled.

Please check:
1. API key is correct: ${apiKey ? `${apiKey.substring(0, 10)}...` : 'NOT FOUND'}
2. Maps JavaScript API is enabled in Google Cloud Console
3. Places API is enabled in Google Cloud Console
4. API key restrictions allow localhost (for dev) or your domain (for production)
5. Restart your Next.js dev server after adding the API key

To enable APIs:
- Go to: https://console.cloud.google.com/apis/library
- Search and enable: "Maps JavaScript API" and "Places API"

To check API key restrictions:
- Go to: https://console.cloud.google.com/apis/credentials
- Click on your API key
- Under "Application restrictions", add: http://localhost:3001`;
        alert(errorMsg);
        setMapLoaded(false);
        setShowMap(false);
      };

      // Check if script already exists
      const existingScript = document.querySelector(`script[src*="maps.googleapis.com"]`);
      if (existingScript) {
        if (window.google && window.google.maps) {
          setMapLoaded(true);
          setTimeout(() => {
            try {
              initializeMap();
            } catch (error) {
              console.error("Map initialization error:", error);
              alert("Failed to initialize map. Please check your API key configuration.");
            }
          }, 100);
        }
        return;
      }

      const script = document.createElement("script");
      // Ensure API key doesn't have any whitespace
      const cleanApiKey = apiKey.trim();
      const scriptUrl = `https://maps.googleapis.com/maps/api/js?key=${cleanApiKey}&libraries=places`;
      console.log("Loading Google Maps script. API Key prefix:", cleanApiKey.substring(0, 15) + "...");
      script.src = scriptUrl;
      script.async = true;
      script.defer = true;

      script.onload = () => {
        console.log("Google Maps script loaded");
        if (window.google && window.google.maps) {
          console.log("Google Maps API available");
          setMapLoaded(true);
          setTimeout(() => {
            try {
              initializeMap();
            } catch (error) {
              console.error("Map initialization error:", error);
              const errorDetails = error instanceof Error ? error.message : String(error);
              alert(`Failed to initialize map.\n\nError: ${errorDetails}\n\nPlease check:\n1. Maps JavaScript API is enabled\n2. Places API is enabled\n3. Billing is enabled for your project\n4. API key is correct`);
              setMapLoaded(false);
            }
          }, 100);
        } else {
          console.error("Google Maps script loaded but API not available");
          alert("Google Maps script loaded but API is not available.\n\nPlease check:\n1. Maps JavaScript API is enabled in Google Cloud Console\n2. Places API is enabled in Google Cloud Console\n3. Billing is enabled for your project\n4. Wait a few minutes after enabling APIs for them to activate");
          setMapLoaded(false);
        }
      };

      script.onerror = (error) => {
        console.error("Failed to load Google Maps script:", error);
        alert("Failed to load Google Maps script.\n\nPlease check:\n1. API key is correct: " + (apiKey ? apiKey.substring(0, 15) + "..." : "NOT FOUND") + "\n2. Maps JavaScript API is enabled\n3. Places API is enabled\n4. Billing is enabled\n5. Your internet connection\n6. Check browser console for detailed errors");
        setShowMap(false);
        setMapLoaded(false);
      };

      document.head.appendChild(script);
    } else if (showMap && mapLoaded && window.google && window.google.maps) {
      setTimeout(() => {
        try {
          initializeMap();
        } catch (error) {
          console.error("Map initialization error:", error);
        }
      }, 100);
    }
  }, [showMap, mapLoaded]);

  const initializeMap = () => {
    if (!mapRef.current) {
      console.error("Map container ref not available");
      return;
    }

    if (!window.google) {
      console.error("window.google is not available");
      alert("Google Maps API failed to load. Please check:\n1. Maps JavaScript API is enabled\n2. Places API is enabled\n3. Billing is enabled");
      setMapLoaded(false);
      return;
    }

    if (!window.google.maps) {
      console.error("window.google.maps is not available");
      alert("Google Maps API failed to load. Please check:\n1. Maps JavaScript API is enabled\n2. Places API is enabled\n3. Billing is enabled");
      setMapLoaded(false);
      return;
    }

    // Check if Places API is available
    if (!window.google.maps.places) {
      console.error("Places API is not available. The Places library may not be loaded or Places API is not enabled.");
      alert("Places API is not available.\n\nPlease enable Places API in Google Cloud Console:\n1. Go to: https://console.cloud.google.com/apis/library\n2. Search for 'Places API'\n3. Click 'Enable'\n4. Wait 2-5 minutes for activation\n5. Restart your dev server");
      setMapLoaded(false);
      return;
    }

    try {
      console.log("Initializing Google Map...");
      // Initialize map centered on India
      const map = new window.google.maps.Map(mapRef.current, {
        center: { lat: 20.5937, lng: 78.9629 }, // India center
        zoom: 6,
        mapTypeControl: true,
        streetViewControl: false,
      });

      console.log("Map initialized successfully");
      mapInstanceRef.current = map;

      // Add click listener to place marker
      map.addListener("click", (e: any) => {
        if (e.latLng) {
          const lat = e.latLng.lat();
          const lng = e.latLng.lng();
          placeMarker(lat, lng, map);
          reverseGeocode(lat, lng);
        }
      });

      // Initialize Autocomplete for search
      if (searchInputRef.current && window.google.maps.places) {
        console.log("Initializing Places Autocomplete...");
        try {
          const autocomplete = new window.google.maps.places.Autocomplete(searchInputRef.current, {
            types: ["geocode", "establishment"],
            componentRestrictions: { country: "in" }, // Restrict to India
          });

          autocompleteRef.current = autocomplete;

          autocomplete.addListener("place_changed", () => {
            const place = autocomplete.getPlace();
            if (place.geometry?.location) {
              const lat = place.geometry.location.lat();
              const lng = place.geometry.location.lng();
              const address = place.formatted_address || place.name || "";

              // Extract location details from place
              const details = extractLocationDetails(place as any);

              setSelectedLocation({ lat, lng, address });
              placeMarker(lat, lng, map);
              map.setCenter({ lat, lng });
              map.setZoom(15);

              const locationString = `${address} (${lat}, ${lng})`;
              onChange(locationString, lat, lng, details);
              setSearchQuery(address);
            }
          });
          console.log("Places Autocomplete initialized successfully");
        } catch (autocompleteError) {
          console.error("Error initializing Autocomplete:", autocompleteError);
          alert("Failed to initialize Places Autocomplete. Please ensure Places API is enabled in Google Cloud Console.");
        }
      } else {
        console.warn("Search input ref or Places API not available for Autocomplete");
      }
    } catch (error) {
      console.error("Error initializing map:", error);
      const errorMsg = error instanceof Error ? error.message : String(error);
      alert(`Failed to initialize Google Maps.\n\nError: ${errorMsg}\n\nPlease check:\n1. Maps JavaScript API is enabled\n2. Places API is enabled\n3. Billing is enabled for your project`);
      setMapLoaded(false);
    }
  };

  const placeMarker = (lat: number, lng: number, map: any) => {
    if (!window.google || !window.google.maps) return;

    // Remove existing marker
    if (markerRef.current) {
      markerRef.current.setMap(null);
    }

    // Create new marker
    const marker = new window.google.maps.Marker({
      position: { lat, lng },
      map: map,
      draggable: true,
      animation: window.google.maps.Animation.DROP,
    });

    markerRef.current = marker;

    // Update location when marker is dragged
    marker.addListener("dragend", () => {
      const position = marker.getPosition();
      if (position) {
        const newLat = position.lat();
        const newLng = position.lng();
        reverseGeocode(newLat, newLng);
      }
    });
  };

  const useCurrentLocation = () => {
    if (navigator.geolocation) {
      navigator.geolocation.getCurrentPosition(
        (position) => {
          const lat = position.coords.latitude;
          const lng = position.coords.longitude;
          if (mapInstanceRef.current) {
            placeMarker(lat, lng, mapInstanceRef.current);
            mapInstanceRef.current.setCenter({ lat, lng });
            mapInstanceRef.current.setZoom(15);
            reverseGeocode(lat, lng);
          }
        },
        (error) => {
          console.error("Error getting current location:", error);
          alert("Unable to get your current location. Please ensure location services are enabled.");
        }
      );
    } else {
      alert("Geolocation is not supported by your browser.");
    }
  };

  const extractLocationDetails = (result: GeocoderResult): LocationDetails => {
    const details: LocationDetails = {};

    // Extract address components
    if (result.address_components) {
      result.address_components.forEach((component: any) => {
        const types = component.types || [];

        if (types.includes('administrative_area_level_1')) {
          details.state = component.long_name;
        }
        if (types.includes('locality') || types.includes('sublocality')) {
          details.locality = component.long_name;
        }
        if (types.includes('administrative_area_level_2')) {
          details.city = component.long_name;
        }
        if (types.includes('postal_code')) {
          details.pincode = component.long_name;
        }
      });
    }

    // Use formatted address as main address
    if (result.formatted_address) {
      details.address = result.formatted_address;
    }

    return details;
  };

  const reverseGeocode = (lat: number, lng: number) => {
    if (!window.google || !window.google.maps) return;

    const geocoder = new window.google.maps.Geocoder();
    geocoder.geocode({ location: { lat, lng } }, (results: GeocoderResult[] | null, status: GeocoderStatus) => {
      if (status === "OK" && results && results[0]) {
        const result = results[0];
        const address = result.formatted_address;
        const details = extractLocationDetails(result);

        setSelectedLocation({ lat, lng, address });
        const locationString = `${address} (${lat}, ${lng})`;
        onChange(locationString, lat, lng, details);
        setSearchQuery(address);
      } else {
        const locationString = `${lat}, ${lng}`;
        setSelectedLocation({ lat, lng, address: locationString });
        onChange(locationString, lat, lng, {});
        setSearchQuery(`${lat}, ${lng}`);
      }
    });
  };

  const handleSearch = () => {
    if (searchQuery.trim()) {
      if (!window.google || !window.google.maps) {
        alert("Google Maps is still loading. Please wait a moment.");
        return;
      }

      const geocoder = new window.google.maps.Geocoder();
      geocoder.geocode({ address: searchQuery }, (results: GeocoderResult[] | null, status: GeocoderStatus) => {
        if (status === "OK" && results && results[0] && mapInstanceRef.current) {
          const result = results[0];
          const location = result.geometry.location;
          const lat = location.lat();
          const lng = location.lng();
          const address = result.formatted_address;
          const details = extractLocationDetails(result);

          setSelectedLocation({ lat, lng, address });
          placeMarker(lat, lng, mapInstanceRef.current);
          mapInstanceRef.current.setCenter({ lat, lng });
          mapInstanceRef.current.setZoom(15);

          const locationString = `${address} (${lat}, ${lng})`;
          onChange(locationString, lat, lng, details);
        } else {
          alert("Location not found. Please try a different search.");
        }
      });
    }
  };

  const handleSaveLocation = () => {
    if (selectedLocation) {
      onChange(selectedLocation.address, selectedLocation.lat, selectedLocation.lng);
      setShowMap(false);
    }
  };

  return (
    <div className="w-full">
      <div className="flex gap-2 mb-2">
        <div className="flex-1 relative">
          <input
            type="text"
            value={value || searchQuery}
            onChange={(e) => {
              setSearchQuery(e.target.value);
              onChange(e.target.value);
            }}
            placeholder={placeholder}
            className="w-full px-4 py-3 pr-10 rounded-xl bg-theme-input border border-primary-500/20 text-theme-primary focus:border-primary-500 focus:outline-none transition-colors"
          />
          <Search className="absolute right-3 top-1/2 -translate-y-1/2 w-5 h-5 text-gray-400" />
        </div>
        <button
          type="button"
          onClick={() => setShowMap(!showMap)}
          className="px-4 py-3 bg-primary-500 text-white rounded-xl hover:bg-primary-600 transition-colors flex items-center gap-2 whitespace-nowrap"
        >
          <MapPin className="w-4 h-4" />
          {showMap ? "Hide Map" : "Pick Location"}
        </button>
      </div>

      {showMap && (
        <div className="mt-4 border border-primary-500/20 rounded-xl overflow-hidden">
          <div className="bg-gray-50 p-4 border-b border-primary-500/20">
            <div className="flex items-center justify-between mb-3">
              <p className="text-sm font-medium text-theme-secondary">
                Click on the map to set location or search above
              </p>
              <button
                type="button"
                onClick={() => setShowMap(false)}
                className="text-gray-500 hover:text-gray-700"
              >
                <X className="w-5 h-5" />
              </button>
            </div>
            {!mapLoaded && (
              <div className="mb-3 p-3 bg-yellow-50 dark:bg-yellow-900/20 border border-yellow-200 dark:border-yellow-800 rounded-lg">
                <p className="text-sm text-yellow-800 dark:text-yellow-200">
                  Loading Google Maps... If this takes too long, please check your API key configuration.
                </p>
              </div>
            )}
            <div className="flex gap-2">
              <input
                ref={searchInputRef}
                type="text"
                value={searchQuery}
                onChange={(e) => setSearchQuery(e.target.value)}
                onKeyPress={(e) => {
                  if (e.key === "Enter") {
                    e.preventDefault();
                    handleSearch();
                  }
                }}
                placeholder="Search for a place..."
                className="flex-1 px-4 py-2 rounded-lg bg-white border border-gray-300 text-gray-900 focus:border-primary-500 focus:outline-none"
                disabled={!mapLoaded}
              />
              <button
                type="button"
                onClick={handleSearch}
                disabled={!mapLoaded}
                className="px-4 py-2 bg-primary-500 text-white rounded-lg hover:bg-primary-600 transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
              >
                Search
              </button>
              <button
                type="button"
                onClick={useCurrentLocation}
                disabled={!mapLoaded}
                className="px-4 py-2 bg-blue-500 text-white rounded-lg hover:bg-blue-600 transition-colors disabled:opacity-50 disabled:cursor-not-allowed flex items-center gap-2"
                title="Use Current Location"
              >
                <MapPin className="w-4 h-4" />
                Current
              </button>
            </div>
          </div>
          {mapLoaded ? (
            <div
              ref={mapRef}
              className="w-full bg-gray-200 rounded-b-xl"
              style={{ height, minHeight: "300px" }}
            />
          ) : (
            <div className="w-full bg-gray-200 dark:bg-gray-800 flex items-center justify-center rounded-b-xl" style={{ height, minHeight: "300px" }}>
              <div className="text-center">
                <div className="inline-block animate-spin rounded-full h-12 w-12 border-b-2 border-primary-500 mb-4"></div>
                <p className="text-gray-600 dark:text-gray-400">Loading map...</p>
                {!process.env.NEXT_PUBLIC_GOOGLE_MAPS_API_KEY && (
                  <div className="mt-4 p-3 bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800 rounded-lg max-w-md mx-auto">
                    <p className="text-red-600 dark:text-red-400 text-sm font-medium">
                      API key not configured
                    </p>
                    <p className="text-red-500 dark:text-red-500 text-xs mt-1">
                      Please set NEXT_PUBLIC_GOOGLE_MAPS_API_KEY in your .env.local file
                    </p>
                  </div>
                )}
              </div>
            </div>
          )}
          {selectedLocation && (
            <div className="bg-gray-50 p-4 border-t border-primary-500/20">
              <div className="flex items-center justify-between">
                <div>
                  <p className="text-sm font-medium text-gray-700">Selected Location:</p>
                  <p className="text-sm text-gray-600 mt-1">{selectedLocation.address}</p>
                  <p className="text-xs text-gray-500 mt-1">
                    Coordinates: {selectedLocation.lat.toFixed(6)}, {selectedLocation.lng.toFixed(6)}
                  </p>
                </div>
                <button
                  type="button"
                  onClick={handleSaveLocation}
                  className="px-4 py-2 bg-green-600 text-white rounded-lg hover:bg-green-700 transition-colors"
                >
                  Save Location
                </button>
              </div>
            </div>
          )}
        </div>
      )}
    </div>
  );
}

