import {
  Injectable,
  InternalServerErrorException,
  Logger,
  NotFoundException,
} from '@nestjs/common';
import { ConfigService } from '@nestjs/config';

export interface AutocompletePrediction {
  placeId: string;
  primaryText: string;
  secondaryText: string;
  fullText: string;
}

export interface PlaceDetails {
  placeId: string;
  displayName: string;
  formattedAddress: string;
  latitude: number;
  longitude: number;
}

@Injectable()
export class PlacesService {
  private readonly logger = new Logger(PlacesService.name);
  private readonly apiKey: string;

  constructor(config: ConfigService) {
    this.apiKey = config.get<string>('GOOGLE_MAPS_BACKEND_KEY') ?? '';
    if (!this.apiKey) {
      this.logger.warn('GOOGLE_MAPS_BACKEND_KEY not set — Places endpoints will fail until configured');
    }
  }

  async autocomplete(query: string, sessionToken: string): Promise<AutocompletePrediction[]> {
    if (!this.apiKey) throw new InternalServerErrorException('Google Maps key not configured');

    let res: Response;
    try {
      res = await fetch('https://places.googleapis.com/v1/places:autocomplete', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'X-Goog-Api-Key': this.apiKey,
          'X-Goog-FieldMask':
            'suggestions.placePrediction.placeId,' +
            'suggestions.placePrediction.text,' +
            'suggestions.placePrediction.structuredFormat',
        },
        body: JSON.stringify({
          input: query,
          sessionToken,
          regionCode: 'IN',
          languageCode: 'en',
          locationBias: {
            circle: {
              center: { latitude: 19.076, longitude: 72.8777 },
              radius: 50000,
            },
          },
        }),
      });
    } catch (e) {
      this.logger.error('Places autocomplete network error', e instanceof Error ? e.message : String(e));
      throw new InternalServerErrorException('Failed to reach Google Places API');
    }

    if (!res.ok) {
      const body = await res.text().catch(() => '');
      this.logger.error(`Places autocomplete HTTP ${res.status}: ${body.slice(0, 200)}`);
      throw new InternalServerErrorException(`Google Places API error (${res.status})`);
    }

    const json = await res.json() as { suggestions?: any[] };
    return (json.suggestions ?? []).map((s: any) => {
      const p = s.placePrediction;
      return {
        placeId: p.placeId as string,
        primaryText: (p.structuredFormat?.mainText?.text ?? p.text?.text ?? '') as string,
        secondaryText: (p.structuredFormat?.secondaryText?.text ?? '') as string,
        fullText: (p.text?.text ?? '') as string,
      };
    });
  }

  async fetchPlaceDetails(placeId: string, sessionToken: string): Promise<PlaceDetails> {
    if (!this.apiKey) throw new InternalServerErrorException('Google Maps key not configured');

    let res: Response;
    try {
      res = await fetch(
        `https://places.googleapis.com/v1/places/${encodeURIComponent(placeId)}?sessionToken=${encodeURIComponent(sessionToken)}`,
        {
          headers: {
            'X-Goog-Api-Key': this.apiKey,
            'X-Goog-FieldMask': 'id,displayName,formattedAddress,location',
          },
        },
      );
    } catch (e) {
      this.logger.error('Place Details network error', e instanceof Error ? e.message : String(e));
      throw new InternalServerErrorException('Failed to reach Google Places API');
    }

    if (res.status === 404) {
      throw new NotFoundException(`Place not found: ${placeId}`);
    }
    if (!res.ok) {
      const body = await res.text().catch(() => '');
      this.logger.error(`Place Details HTTP ${res.status}: ${body.slice(0, 200)}`);
      throw new InternalServerErrorException(`Google Places API error (${res.status})`);
    }

    const json = await res.json() as any;
    return {
      placeId: json.id as string,
      displayName: (json.displayName?.text ?? json.displayName ?? '') as string,
      formattedAddress: (json.formattedAddress ?? '') as string,
      latitude: (json.location?.latitude ?? 0) as number,
      longitude: (json.location?.longitude ?? 0) as number,
    };
  }
}
