import { ILeadSource, NormalizedLead, SearchParams, SourceCategory } from "./types";
import { z } from "zod";
import { getApiKey } from "../settings";
import { parseGeoInput } from "../utils/geo";

export class GooglePlacesSource implements ILeadSource {
  id = "google-places";
  name = "Google Places";
  description = "Official Google Maps business search for highly accurate business data, addresses, and phone numbers.";
  category: SourceCategory = "maps";

  inputSchema = z.object({
    keyword: z.string().min(1, "Search keyword is required"),
    location: z.string().min(1, "Location is required"),
    limit: z.number().optional().default(60),
  });

  async run(params: SearchParams): Promise<NormalizedLead[]> {
    const apiKey = await getApiKey('google');
    if (!apiKey) {
      throw new Error("Google Maps API key is missing. Please set GOOGLE_PLACES_API_KEY in your settings.");
    }

    const { keyword, location, limit = 60 } = params;
    const geoInput = parseGeoInput(location);
    
    let baseUrl: string;
    if (geoInput) {
      baseUrl = `https://maps.googleapis.com/maps/api/place/textsearch/json?query=${encodeURIComponent(keyword)}&location=${geoInput.lat},${geoInput.lng}&radius=${geoInput.radius || 5000}&key=${apiKey}`;
    } else {
      baseUrl = `https://maps.googleapis.com/maps/api/place/textsearch/json?query=${encodeURIComponent(`${keyword} in ${location}`)}&key=${apiKey}`;
    }

    let allLeads: NormalizedLead[] = [];
    let nextPageToken: string | undefined = undefined;
    let pagesFetched = 0;
    const maxPages = Math.ceil(limit / 20);

    do {
      const url = nextPageToken 
        ? `https://maps.googleapis.com/maps/api/place/textsearch/json?pagetoken=${nextPageToken}&key=${apiKey}`
        : baseUrl;

      if (nextPageToken) {
        // Wait for next_page_token to become valid (mandatory per Google API)
        await new Promise(resolve => setTimeout(resolve, 2000));
      }

      const response = await fetch(url);
      const data = await response.json();

      if (data.status !== "OK" && data.status !== "ZERO_RESULTS") {
        console.error(`[Google] API Error: ${data.status}`, data.error_message);
        break;
      }

      const pageResults = data.results || [];
      const pageLeads: NormalizedLead[] = pageResults.map((place: any) => ({
        businessName: place.name,
        website: undefined, 
        phone: undefined,   
        address: place.formatted_address,
        city: location, 
        category: place.types?.[0],
        confidenceScore: 0.9,
        rawData: place,
      }));

      allLeads = [...allLeads, ...pageLeads];
      nextPageToken = data.next_page_token;
      pagesFetched++;

    } while (nextPageToken && allLeads.length < limit && pagesFetched < maxPages);

    return allLeads.slice(0, limit);
  }

  async isAvailable(): Promise<boolean> {
    const apiKey = await getApiKey('google');
    return !!apiKey;
  }
}
