import { mapsAPI } from "./api";

interface AddressComponents {
  address1: string;
  address2?: string;
  city: string;
  state: string;
  zipCode: string;
  country: string;
}

interface GeocodeResult {
  latitude: number;
  longitude: number;
  formattedAddress?: string;
}

interface GeocodeError {
  error: string;
  details?: string;
}

type GeocodeResponse = GeocodeResult | GeocodeError;

class GeocodingService {
  private cache: Map<string, GeocodeResult> = new Map();

  /**
   * Convert address components to lat/lng coordinates using backend geocoding proxy
   */
  async geocodeAddress(address: AddressComponents): Promise<GeocodeResponse> {
    // Create address string for geocoding
    const addressParts = [
      address.address1,
      address.address2,
      address.city,
      address.state,
      address.zipCode,
      address.country,
    ].filter((part) => part && part.trim());

    const addressString = addressParts.join(", ");
    const cacheKey = addressString.toLowerCase();

    // Check cache first
    if (this.cache.has(cacheKey)) {
      return this.cache.get(cacheKey)!;
    }

    try {
      const response = await mapsAPI.geocode({
        address: addressString,
        componentRestrictions: {
          country: address.country?.toLowerCase() || "us",
        },
      });

      if (response.data.latitude && response.data.longitude) {
        const geocodeResult: GeocodeResult = {
          latitude: response.data.latitude,
          longitude: response.data.longitude,
          formattedAddress: response.data.formattedAddress || addressString,
        };

        // Cache successful result
        this.cache.set(cacheKey, geocodeResult);
        return geocodeResult;
      } else if (response.data.error) {
        return {
          error: "Geocoding failed",
          details: response.data.error,
        };
      } else {
        return {
          error: "Geocoding failed",
          details: "No coordinates returned",
        };
      }
    } catch (error: any) {
      console.error("Geocoding API error:", error.message);

      if (error.response?.status === 429) {
        return {
          error: "Too many geocoding requests",
          details: "Please slow down and try again",
        };
      } else if (error.response?.status === 401) {
        return {
          error: "Authentication required",
          details: "Please log in to use geocoding",
        };
      } else {
        return {
          error: "Network error during geocoding",
          details: error.message || "Unknown error",
        };
      }
    }
  }

  /**
   * Check if address has sufficient components for geocoding
   */
  isAddressComplete(address: AddressComponents): boolean {
    return !!(
      address.address1?.trim() &&
      address.city?.trim() &&
      address.state?.trim() &&
      address.zipCode?.trim()
    );
  }
}

// Create and export a singleton instance
export const geocodingService = new GeocodingService();

// Export types for use in other components
export type { AddressComponents, GeocodeResult, GeocodeError, GeocodeResponse };
