import { Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { resolveGoogleMapsApiKey } from '../config/runtime-config';
import { chunkArray, type LatLng } from './map-matching.util';

interface SnapToRoadsResponse {
  snappedPoints?: Array<{
    location: { latitude: number; longitude: number };
    originalIndex?: number;
    placeId?: string;
  }>;
  warningMessage?: string;
}

@Injectable()
export class GoogleRoadsClient {

  constructor(private readonly config: ConfigService) {}

  hasApiKey(): boolean {
    return !!resolveGoogleMapsApiKey(this.config);
  }

  /**
   * Snap path via Google Roads Snap-to-Roads (max 100 points per request).
   * Returns empty array when no API key or on hard failure.
   */
  async snapToRoads(path: LatLng[], interpolate = true): Promise<LatLng[]> {
    const key = resolveGoogleMapsApiKey(this.config);
    if (!key || path.length < 2) return [];

    const snapped: LatLng[] = [];
    for (const part of chunkArray(path, 100)) {
      const pathParam = part.map((p) => `${p.lat},${p.lng}`).join('|');
      const url =
        `https://roads.googleapis.com/v1/snapToRoads` +
        `?path=${encodeURIComponent(pathParam)}` +
        `&interpolate=${interpolate ? 'true' : 'false'}` +
        `&key=${encodeURIComponent(key)}`;

      try {
        const res = await fetch(url);
        if (!res.ok) {
          const body = await res.text();
          continue;
        }
        const data = (await res.json()) as SnapToRoadsResponse & {
          error?: { message?: string; status?: string };
        };
        if (data.error?.message) {
          continue;
        }
        if (data.warningMessage) {
        }
        const batch = data.snappedPoints ?? [];
        if (batch.length === 0) {
        }
        for (const sp of batch) {
          snapped.push({
            lat: sp.location.latitude,
            lng: sp.location.longitude,
          });
        }
      } catch (err) {
      }
    }
    return snapped;
  }
}
