import { mapsAPI } from "./api";

// Define types for place details
export interface PlaceDetails {
  formattedAddress: string;
  addressComponents: {
    streetNumber?: string;
    route?: string;
    locality?: string;
    administrativeAreaLevel1?: string;
    administrativeAreaLevel1Long?: string;
    postalCode?: string;
    country?: string;
  };
  geometry: {
    latitude: number;
    longitude: number;
  };
  placeId: string;
}

export interface AutocompletePrediction {
  placeId: string;
  description: string;
  types: string[];
  mainText: string;
  secondaryText: string;
}

class PlacesService {
  private sessionToken: string | null = null;
  private debounceTimer: NodeJS.Timeout | null = null;
  private abortController: AbortController | null = null;

  /**
   * Generate a new session token for cost optimization
   */
  private generateSessionToken(): string {
    return (
      Math.random().toString(36).substring(2, 15) +
      Math.random().toString(36).substring(2, 15)
    );
  }

  /**
   * Get autocomplete predictions for a query (debounced)
   */
  async getAutocompletePredictions(
    input: string,
    options?: {
      types?: string[];
      componentRestrictions?: { country: string };
      bounds?: any;
    }
  ): Promise<AutocompletePrediction[]> {
    if (input.trim().length < 2) {
      return [];
    }

    // Clear existing debounce timer
    if (this.debounceTimer) {
      clearTimeout(this.debounceTimer);
    }

    // Cancel any pending request
    if (this.abortController) {
      this.abortController.abort();
    }

    // Return a promise that resolves after debounce delay
    return new Promise((resolve, reject) => {
      this.debounceTimer = setTimeout(async () => {
        try {
          const predictions = await this.makeAutocompleteRequest(
            input.trim(),
            options
          );
          resolve(predictions);
        } catch (error) {
          reject(error);
        }
      }, 300); // 300ms debounce delay
    });
  }

  /**
   * Make the actual autocomplete API request
   */
  private async makeAutocompleteRequest(
    input: string,
    options?: {
      types?: string[];
      componentRestrictions?: { country: string };
      bounds?: any;
    }
  ): Promise<AutocompletePrediction[]> {
    // Generate new session token if not exists
    if (!this.sessionToken) {
      this.sessionToken = this.generateSessionToken();
    }

    // Create new abort controller for this request
    this.abortController = new AbortController();

    try {
      const response = await mapsAPI.placesAutocomplete({
        input: input,
        types: options?.types || ["address"],
        componentRestrictions: options?.componentRestrictions,
        sessionToken: this.sessionToken || undefined,
      });

      if (response.data.predictions) {
        return response.data.predictions;
      } else if (response.data.error) {
        console.error("Places Autocomplete API error:", response.data.error);
        throw new Error(response.data.error);
      }

      return [];
    } catch (error: any) {
      // Don't throw error if request was aborted (user is still typing)
      if (error.name === "AbortError" || error.code === "ERR_CANCELED") {
        return [];
      }

      console.error("Error fetching place predictions:", error.message);
      if (error.response?.status === 429) {
        throw new Error("Too many requests. Please slow down.");
      } else if (error.response?.status === 401) {
        throw new Error("Authentication required. Please log in.");
      } else {
        throw new Error("Failed to fetch place suggestions");
      }
    }
  }

  /**
   * Get detailed place information by place ID
   */
  async getPlaceDetails(placeId: string): Promise<PlaceDetails> {
    if (!placeId) {
      throw new Error("Place ID is required");
    }

    try {
      const response = await mapsAPI.placeDetails({
        placeId,
        sessionToken: this.sessionToken || undefined,
      });

      // Clear session token after successful place details request
      this.sessionToken = null;

      if (response.data.placeId) {
        return {
          formattedAddress: response.data.formattedAddress,
          addressComponents: response.data.addressComponents,
          geometry: response.data.geometry,
          placeId: response.data.placeId,
        };
      } else if (response.data.error) {
        console.error("Place Details API error:", response.data.error);
        throw new Error(response.data.error);
      }

      throw new Error("Invalid response from place details API");
    } catch (error: any) {
      console.error("Error fetching place details:", error.message);
      if (error.response?.status === 429) {
        throw new Error("Too many requests. Please slow down.");
      } else if (error.response?.status === 401) {
        throw new Error("Authentication required. Please log in.");
      } else {
        throw new Error("Failed to fetch place details");
      }
    }
  }
}

// Create and export singleton instance
export const placesService = new PlacesService();
