# Task 01 — Google Maps Integration

Implement the real Google Places Autocomplete, Place Details, and Routes API
calls. Currently these are stubs in `apps/api/src/modules/places/places.service.ts`
and `apps/api/src/modules/routes/routes.service.ts`.

## Prerequisites

- Google Cloud project with **Places API (New)** and **Routes API** enabled
- API key created with HTTP referrer restriction (frontend) AND a separate
  key with IP restriction (backend)
- Both keys added to `.env`:
  - `GOOGLE_MAPS_BACKEND_KEY`
  - `NEXT_PUBLIC_GOOGLE_MAPS_FRONTEND_KEY` (used in Task 02)

## Files to modify

```
apps/api/src/modules/places/places.service.ts
apps/api/src/modules/routes/routes.service.ts
apps/api/src/modules/places/places.controller.ts   (verify session token plumbing)
```

## Implementation

### PlacesService.autocomplete

Endpoint: `POST https://places.googleapis.com/v1/places:autocomplete`

```ts
const 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: {
      // Bias to Mumbai - tune for the pilot's city later by passing in
      circle: {
        center: { latitude: 19.0760, longitude: 72.8777 },
        radius: 50000,
      },
    },
  }),
});
```

Map the response `suggestions[].placePrediction` to the
`AutocompletePrediction` interface already defined in the service.

### PlacesService.fetchPlaceDetails

Endpoint: `GET https://places.googleapis.com/v1/places/{placeId}?sessionToken={sessionToken}`

```ts
const res = await fetch(
  `https://places.googleapis.com/v1/places/${placeId}?sessionToken=${sessionToken}`,
  {
    headers: {
      'X-Goog-Api-Key': this.apiKey,
      'X-Goog-FieldMask': 'id,displayName,formattedAddress,location',
    },
  },
);
```

Map response to the `PlaceDetails` interface. Note: `location` is
`{ latitude: number, longitude: number }`.

### RoutesService.fetchFromGoogle

Endpoint: `POST https://routes.googleapis.com/directions/v2:computeRoutes`

```ts
const res = await fetch('https://routes.googleapis.com/directions/v2:computeRoutes', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'X-Goog-Api-Key': this.apiKey,
    'X-Goog-FieldMask':
      'routes.distanceMeters,routes.duration,routes.polyline.encodedPolyline',
  },
  body: JSON.stringify({
    origin:      { placeId: originPlaceId },
    destination: { placeId: destinationPlaceId },
    travelMode: 'WALK',
    polylineEncoding: 'ENCODED_POLYLINE',
    units: 'METRIC',
  }),
});
const json = await res.json();
const route = json.routes?.[0];
return {
  distanceMeters: route.distanceMeters,
  durationSeconds: parseInt(String(route.duration).replace('s', ''), 10),
  polyline: route.polyline?.encodedPolyline,
};
```

Note the `duration` field comes back as `"1234s"` (string with trailing 's').

## Error handling

- Wrap each fetch in try/catch. Log the failed URL and a non-PII slice of the
  body. Throw `InternalServerErrorException` with a clean message.
- Handle 4xx specifically — log Google's error message; on 404 from
  Place Details, throw NotFoundException.

## Acceptance

```bash
# 1. Start API: pnpm dev:api
# 2. Login as captain to get a cookie

# 3. Autocomplete (replace COOKIE):
curl 'http://localhost:4001/api/places/autocomplete?q=walkeshwar&sessionToken=test-session-1' \
  -H "Cookie: vihar_session=COOKIE"
# Should return predictions with placeId values

# 4. Pick one, then fetch details + create location:
curl -X POST http://localhost:4001/api/locations/from-place-id \
  -H "Cookie: vihar_session=COOKIE" \
  -H 'Content-Type: application/json' \
  -d '{"placeId":"PLACE_ID_FROM_STEP_3","sessionToken":"test-session-1","locationType":"upashray"}'
# Should return the created location row

# 5. Routes:
curl 'http://localhost:4001/api/routes/walking?from=1&to=2' \
  -H "Cookie: vihar_session=COOKIE"
# Should return { distanceMeters, durationSeconds, cached: false }
# Re-run - should return cached: true
```

## Gotchas

- The session token is per UI flow, not per request. Generate one when the user
  opens the autocomplete widget; reuse for every keystroke; terminate by Place
  Details. Generating a new one per keystroke is what kills your free tier.
- Routes API responses sometimes have `routes: []` for unreachable pairs.
  Handle this cleanly — throw a meaningful error.
- The cache table uses `cacheKey` (sorted-pair). Don't store both directions.

## Out of scope

- Frontend Autocomplete widget — that's Task 02
- Static Maps / map rendering — Phase 2
- Distance Matrix API — we use Routes API instead (newer, cheaper, better)
