# Phase 5: Future Integration Preparation

## Overview
Design and prepare architecture for future Google Maps integration, location services, station price data, and extensibility for advanced fuel management features.

## Prerequisites
- ✅ Phases 1-4 completed (database, business logic, API, frontend)
- All core fuel logs functionality tested and working
- Location data structure in place

## Google Maps Integration Architecture

### Service Architecture Design

```
Location Services Architecture
├── LocationService (Interface)
│   ├── GoogleMapsService (Implementation)
│   ├── MockLocationService (Testing)
│   └── Future: MapboxService, HereService
├── StationService (Interface)  
│   ├── GooglePlacesStationService
│   └── Future: GasBuddyService, AAA Service
└── PricingService (Interface)
    ├── GooglePlacesPricingService
    └── Future: GasBuddyPricingService
```

### Location Service Interface

**File**: `backend/src/features/fuel-logs/external/location.service.interface.ts`

```typescript
export interface Coordinates {
  latitude: number;
  longitude: number;
}

export interface Address {
  streetNumber?: string;
  streetName?: string;
  city: string;
  state: string;
  zipCode?: string;
  country: string;
  formattedAddress: string;
}

export interface LocationSearchResult {
  placeId: string;
  name: string;
  address: Address;
  coordinates: Coordinates;
  placeTypes: string[];
  rating?: number;
  priceLevel?: number;
  isOpen?: boolean;
  distance?: number; // meters from search center
}

export interface StationSearchOptions {
  coordinates: Coordinates;
  radius?: number; // meters, default 5000 (5km)
  fuelTypes?: string[]; // ['gasoline', 'diesel', 'electric']
  maxResults?: number; // default 20
  openNow?: boolean;
  priceRange?: 'inexpensive' | 'moderate' | 'expensive' | 'very_expensive';
}

export interface FuelPrice {
  fuelType: string;
  fuelGrade?: string;
  pricePerUnit: number;
  currency: string;
  lastUpdated: Date;
  source: string;
}

export interface FuelStation extends LocationSearchResult {
  fuelTypes: string[];
  amenities: string[];
  brands: string[];
  currentPrices?: FuelPrice[];
  hasCarWash?: boolean;
  hasConvenienceStore?: boolean;
  hasRestrooms?: boolean;
  hasAirPump?: boolean;
}

export abstract class LocationService {
  abstract searchNearbyStations(options: StationSearchOptions): Promise<FuelStation[]>;
  abstract getStationDetails(placeId: string): Promise<FuelStation>;
  abstract getCurrentPrices(placeId: string): Promise<FuelPrice[]>;
  abstract geocodeAddress(address: string): Promise<Coordinates>;
  abstract reverseGeocode(coordinates: Coordinates): Promise<Address>;
}
```

### Google Maps Service Implementation

**File**: `backend/src/features/fuel-logs/external/google-maps.service.ts`

```typescript
import { LocationService, StationSearchOptions, FuelStation, Coordinates, Address, FuelPrice } from './location.service.interface';
import { logger } from '../../../core/logging/logger';

export class GoogleMapsService extends LocationService {
  private apiKey: string;
  private baseUrl = 'https://maps.googleapis.com/maps/api';
  
  constructor() {
    super();
    this.apiKey = process.env.GOOGLE_MAPS_API_KEY || '';
    if (!this.apiKey) {
      throw new Error('GOOGLE_MAPS_API_KEY environment variable is required');
    }
  }

  async searchNearbyStations(options: StationSearchOptions): Promise<FuelStation[]> {
    try {
      logger.info('Searching nearby fuel stations', { 
        coordinates: options.coordinates, 
        radius: options.radius 
      });

      const radius = options.radius || 5000;
      const location = `${options.coordinates.latitude},${options.coordinates.longitude}`;
      
      // Use Google Places API to find gas stations
      const url = `${this.baseUrl}/place/nearbysearch/json`;
      const params = new URLSearchParams({
        location,
        radius: radius.toString(),
        type: 'gas_station',
        key: this.apiKey
      });

      if (options.openNow) {
        params.append('opennow', 'true');
      }

      const response = await fetch(`${url}?${params}`);
      const data = await response.json();

      if (data.status !== 'OK' && data.status !== 'ZERO_RESULTS') {
        throw new Error(`Google Places API error: ${data.status}`);
      }

      const stations = await Promise.all(
        data.results.slice(0, options.maxResults || 20).map(async (place: any) => {
          return this.transformPlaceToStation(place, options.coordinates);
        })
      );

      return stations.filter(Boolean);
    } catch (error) {
      logger.error('Error searching nearby stations', { error, options });
      throw error;
    }
  }

  async getStationDetails(placeId: string): Promise<FuelStation> {
    try {
      const url = `${this.baseUrl}/place/details/json`;
      const params = new URLSearchParams({
        place_id: placeId,
        fields: 'name,formatted_address,geometry,rating,price_level,opening_hours,types,photos',
        key: this.apiKey
      });

      const response = await fetch(`${url}?${params}`);
      const data = await response.json();

      if (data.status !== 'OK') {
        throw new Error(`Google Places API error: ${data.status}`);
      }

      return this.transformPlaceToStation(data.result);
    } catch (error) {
      logger.error('Error getting station details', { error, placeId });
      throw error;
    }
  }

  async getCurrentPrices(placeId: string): Promise<FuelPrice[]> {
    // Note: Google Maps API doesn't provide real-time fuel prices
    // This would need integration with fuel price services like GasBuddy
    logger.warn('Current prices not available from Google Maps API', { placeId });
    return [];
  }

  async geocodeAddress(address: string): Promise<Coordinates> {
    try {
      const url = `${this.baseUrl}/geocode/json`;
      const params = new URLSearchParams({
        address,
        key: this.apiKey
      });

      const response = await fetch(`${url}?${params}`);
      const data = await response.json();

      if (data.status !== 'OK' || data.results.length === 0) {
        throw new Error(`Geocoding failed: ${data.status}`);
      }

      const location = data.results[0].geometry.location;
      return {
        latitude: location.lat,
        longitude: location.lng
      };
    } catch (error) {
      logger.error('Error geocoding address', { error, address });
      throw error;
    }
  }

  async reverseGeocode(coordinates: Coordinates): Promise<Address> {
    try {
      const url = `${this.baseUrl}/geocode/json`;
      const params = new URLSearchParams({
        latlng: `${coordinates.latitude},${coordinates.longitude}`,
        key: this.apiKey
      });

      const response = await fetch(`${url}?${params}`);
      const data = await response.json();

      if (data.status !== 'OK' || data.results.length === 0) {
        throw new Error(`Reverse geocoding failed: ${data.status}`);
      }

      return this.parseAddressComponents(data.results[0]);
    } catch (error) {
      logger.error('Error reverse geocoding', { error, coordinates });
      throw error;
    }
  }

  private async transformPlaceToStation(place: any, searchCenter?: Coordinates): Promise<FuelStation> {
    const station: FuelStation = {
      placeId: place.place_id,
      name: place.name,
      address: this.parseAddressComponents(place),
      coordinates: {
        latitude: place.geometry.location.lat,
        longitude: place.geometry.location.lng
      },
      placeTypes: place.types || [],
      rating: place.rating,
      priceLevel: place.price_level,
      isOpen: place.opening_hours?.open_now,
      fuelTypes: this.inferFuelTypes(place),
      amenities: this.inferAmenities(place),
      brands: this.inferBrands(place.name)
    };

    if (searchCenter) {
      station.distance = this.calculateDistance(searchCenter, station.coordinates);
    }

    return station;
  }

  private parseAddressComponents(place: any): Address {
    const components = place.address_components || [];
    const address: Partial<Address> = {
      formattedAddress: place.formatted_address || ''
    };

    components.forEach((component: any) => {
      const types = component.types;
      if (types.includes('street_number')) {
        address.streetNumber = component.long_name;
      } else if (types.includes('route')) {
        address.streetName = component.long_name;
      } else if (types.includes('locality')) {
        address.city = component.long_name;
      } else if (types.includes('administrative_area_level_1')) {
        address.state = component.short_name;
      } else if (types.includes('postal_code')) {
        address.zipCode = component.long_name;
      } else if (types.includes('country')) {
        address.country = component.long_name;
      }
    });

    return address as Address;
  }

  private inferFuelTypes(place: any): string[] {
    // Basic inference - could be enhanced with more sophisticated logic
    const fuelTypes = ['gasoline']; // Default assumption
    
    if (place.name?.toLowerCase().includes('diesel')) {
      fuelTypes.push('diesel');
    }
    
    if (place.name?.toLowerCase().includes('electric') || 
        place.name?.toLowerCase().includes('ev') ||
        place.name?.toLowerCase().includes('tesla')) {
      fuelTypes.push('electric');
    }

    return fuelTypes;
  }

  private inferAmenities(place: any): string[] {
    const amenities: string[] = [];
    const name = place.name?.toLowerCase() || '';

    if (name.includes('car wash')) amenities.push('car_wash');
    if (name.includes('convenience') || name.includes('store')) amenities.push('convenience_store');
    if (name.includes('restroom') || name.includes('bathroom')) amenities.push('restrooms');
    if (name.includes('air')) amenities.push('air_pump');

    return amenities;
  }

  private inferBrands(name: string): string[] {
    const knownBrands = [
      'shell', 'exxon', 'mobil', 'chevron', 'bp', 'citgo', 'sunoco', 
      'marathon', 'speedway', 'wawa', '7-eleven', 'circle k'
    ];
    
    return knownBrands.filter(brand => 
      name.toLowerCase().includes(brand)
    );
  }

  private calculateDistance(coord1: Coordinates, coord2: Coordinates): number {
    const R = 6371000; // Earth's radius in meters
    const dLat = (coord2.latitude - coord1.latitude) * Math.PI / 180;
    const dLon = (coord2.longitude - coord1.longitude) * Math.PI / 180;
    const a = 
      Math.sin(dLat/2) * Math.sin(dLat/2) +
      Math.cos(coord1.latitude * Math.PI / 180) * Math.cos(coord2.latitude * Math.PI / 180) * 
      Math.sin(dLon/2) * Math.sin(dLon/2);
    const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
    return R * c;
  }
}
```

### Mock Location Service for Development

**File**: `backend/src/features/fuel-logs/external/mock-location.service.ts`

```typescript
import { LocationService, StationSearchOptions, FuelStation, Coordinates, Address, FuelPrice } from './location.service.interface';

export class MockLocationService extends LocationService {
  private mockStations: FuelStation[] = [
    {
      placeId: 'mock-station-1',
      name: 'Shell Station',
      address: {
        city: 'Anytown',
        state: 'CA',
        zipCode: '12345',
        country: 'USA',
        formattedAddress: '123 Main St, Anytown, CA 12345'
      },
      coordinates: { latitude: 37.7749, longitude: -122.4194 },
      placeTypes: ['gas_station'],
      rating: 4.2,
      fuelTypes: ['gasoline', 'diesel'],
      amenities: ['convenience_store', 'car_wash'],
      brands: ['shell'],
      currentPrices: [
        {
          fuelType: 'gasoline',
          fuelGrade: '87',
          pricePerUnit: 3.49,
          currency: 'USD',
          lastUpdated: new Date(),
          source: 'mock'
        },
        {
          fuelType: 'gasoline',
          fuelGrade: '91',
          pricePerUnit: 3.79,
          currency: 'USD',
          lastUpdated: new Date(),
          source: 'mock'
        }
      ]
    },
    {
      placeId: 'mock-station-2',
      name: 'EV Charging Station',
      address: {
        city: 'Anytown',
        state: 'CA',
        zipCode: '12345',
        country: 'USA',
        formattedAddress: '456 Electric Ave, Anytown, CA 12345'
      },
      coordinates: { latitude: 37.7849, longitude: -122.4094 },
      placeTypes: ['gas_station', 'electric_vehicle_charging_station'],
      rating: 4.5,
      fuelTypes: ['electric'],
      amenities: ['restrooms'],
      brands: ['tesla'],
      currentPrices: [
        {
          fuelType: 'electric',
          pricePerUnit: 0.28,
          currency: 'USD',
          lastUpdated: new Date(),
          source: 'mock'
        }
      ]
    }
  ];

  async searchNearbyStations(options: StationSearchOptions): Promise<FuelStation[]> {
    // Simulate network delay
    await new Promise(resolve => setTimeout(resolve, 500));
    
    let results = [...this.mockStations];
    
    // Filter by fuel types if specified
    if (options.fuelTypes && options.fuelTypes.length > 0) {
      results = results.filter(station => 
        station.fuelTypes.some(type => options.fuelTypes!.includes(type))
      );
    }
    
    // Add distance calculation
    results = results.map(station => ({
      ...station,
      distance: this.calculateMockDistance(options.coordinates, station.coordinates)
    }));
    
    // Sort by distance and limit results
    results.sort((a, b) => (a.distance || 0) - (b.distance || 0));
    
    return results.slice(0, options.maxResults || 20);
  }

  async getStationDetails(placeId: string): Promise<FuelStation> {
    const station = this.mockStations.find(s => s.placeId === placeId);
    if (!station) {
      throw new Error(`Station not found: ${placeId}`);
    }
    
    // Simulate network delay
    await new Promise(resolve => setTimeout(resolve, 300));
    
    return station;
  }

  async getCurrentPrices(placeId: string): Promise<FuelPrice[]> {
    const station = this.mockStations.find(s => s.placeId === placeId);
    return station?.currentPrices || [];
  }

  async geocodeAddress(address: string): Promise<Coordinates> {
    // Return mock coordinates for any address
    return { latitude: 37.7749, longitude: -122.4194 };
  }

  async reverseGeocode(coordinates: Coordinates): Promise<Address> {
    return {
      city: 'Anytown',
      state: 'CA',
      zipCode: '12345',
      country: 'USA',
      formattedAddress: '123 Mock St, Anytown, CA 12345'
    };
  }

  private calculateMockDistance(coord1: Coordinates, coord2: Coordinates): number {
    // Simple mock distance calculation
    const dLat = coord2.latitude - coord1.latitude;
    const dLon = coord2.longitude - coord1.longitude;
    return Math.sqrt(dLat * dLat + dLon * dLon) * 111000; // Rough conversion to meters
  }
}
```

## Frontend Integration Preparation

### Location Input Component Enhancement

**File**: `frontend/src/features/fuel-logs/components/LocationInput.tsx` (Enhanced)

```tsx
import React, { useState, useEffect } from 'react';
import {
  TextField,
  Autocomplete,
  Box,
  Typography,
  Chip,
  CircularProgress,
  Paper,
  List,
  ListItem,
  ListItemText,
  ListItemIcon,
  Button,
  Dialog,
  DialogTitle,
  DialogContent,
  DialogActions
} from '@mui/material';
import {
  LocationOn,
  LocalGasStation,
  Star,
  AttachMoney,
  MyLocation
} from '@mui/icons-material';

import { LocationData, FuelStation } from '../types/fuel-logs.types';
import { useGeolocation } from '../hooks/useGeolocation';
import { useNearbyStations } from '../hooks/useNearbyStations';

interface LocationInputProps {
  value?: LocationData;
  onChange: (location?: LocationData) => void;
  placeholder?: string;
  disabled?: boolean;
}

export const LocationInput: React.FC<LocationInputProps> = ({
  value,
  onChange,
  placeholder = "Enter station location or search nearby",
  disabled = false
}) => {
  const [inputValue, setInputValue] = useState('');
  const [showStationPicker, setShowStationPicker] = useState(false);
  const { getCurrentLocation, isGettingLocation } = useGeolocation();
  const { 
    nearbyStations, 
    searchNearbyStations, 
    isSearching 
  } = useNearbyStations();

  // Initialize input value from existing location data
  useEffect(() => {
    if (value?.address) {
      setInputValue(value.address);
    } else if (value?.stationName) {
      setInputValue(value.stationName);
    }
  }, [value]);

  const handleLocationSearch = async () => {
    try {
      const position = await getCurrentLocation();
      if (position) {
        await searchNearbyStations({
          coordinates: {
            latitude: position.latitude,
            longitude: position.longitude
          },
          radius: 5000, // 5km
          maxResults: 10
        });
        setShowStationPicker(true);
      }
    } catch (error) {
      console.error('Failed to get location or search stations:', error);
    }
  };

  const handleStationSelect = (station: FuelStation) => {
    const locationData: LocationData = {
      address: station.address.formattedAddress,
      coordinates: station.coordinates,
      googlePlaceId: station.placeId,
      stationName: station.name,
      // Future: include pricing and amenity data
      stationDetails: {
        rating: station.rating,
        fuelTypes: station.fuelTypes,
        amenities: station.amenities,
        brands: station.brands,
        currentPrices: station.currentPrices
      }
    };

    onChange(locationData);
    setInputValue(`${station.name} - ${station.address.formattedAddress}`);
    setShowStationPicker(false);
  };

  const handleManualInput = (input: string) => {
    setInputValue(input);
    if (input.trim()) {
      onChange({
        address: input.trim()
      });
    } else {
      onChange(undefined);
    }
  };

  return (
    <>
      <Box>
        <TextField
          label="Station Location"
          value={inputValue}
          onChange={(e) => handleManualInput(e.target.value)}
          placeholder={placeholder}
          fullWidth
          disabled={disabled}
          InputProps={{
            endAdornment: (
              <Box display="flex" gap={1}>
                <Button
                  size="small"
                  onClick={handleLocationSearch}
                  disabled={disabled || isGettingLocation || isSearching}
                  startIcon={
                    isGettingLocation || isSearching ? (
                      <CircularProgress size={16} />
                    ) : (
                      <MyLocation />
                    )
                  }
                >
                  Nearby
                </Button>
              </Box>
            )
          }}
        />
        
        {value?.stationDetails && (
          <Box mt={1}>
            <Typography variant="caption" color="text.secondary">
              Selected Station Details:
            </Typography>
            <Box display="flex" gap={1} mt={0.5} flexWrap="wrap">
              {value.stationDetails.rating && (
                <Chip
                  size="small"
                  icon={<Star />}
                  label={`${value.stationDetails.rating}/5`}
                  variant="outlined"
                />
              )}
              {value.stationDetails.fuelTypes.map(fuelType => (
                <Chip
                  key={fuelType}
                  size="small"
                  label={fuelType}
                  variant="outlined"
                />
              ))}
            </Box>
          </Box>
        )}
      </Box>

      {/* Station Picker Dialog */}
      <Dialog
        open={showStationPicker}
        onClose={() => setShowStationPicker(false)}
        maxWidth="sm"
        fullWidth
      >
        <DialogTitle>
          <Box display="flex" alignItems="center" gap={1}>
            <LocalGasStation />
            Nearby Fuel Stations
          </Box>
        </DialogTitle>
        <DialogContent>
          {isSearching ? (
            <Box display="flex" justifyContent="center" p={3}>
              <CircularProgress />
            </Box>
          ) : (
            <List>
              {nearbyStations.map((station) => (
                <ListItem
                  key={station.placeId}
                  button
                  onClick={() => handleStationSelect(station)}
                >
                  <ListItemIcon>
                    <LocalGasStation />
                  </ListItemIcon>
                  <ListItemText
                    primary={
                      <Box display="flex" alignItems="center" gap={1}>
                        <Typography variant="body1">
                          {station.name}
                        </Typography>
                        {station.rating && (
                          <Chip
                            size="small"
                            icon={<Star />}
                            label={station.rating}
                            variant="outlined"
                          />
                        )}
                        {station.distance && (
                          <Typography variant="caption" color="text.secondary">
                            {Math.round(station.distance)}m away
                          </Typography>
                        )}
                      </Box>
                    }
                    secondary={
                      <Box>
                        <Typography variant="body2" color="text.secondary">
                          {station.address.formattedAddress}
                        </Typography>
                        <Box display="flex" gap={0.5} mt={0.5} flexWrap="wrap">
                          {station.fuelTypes.map(fuelType => (
                            <Chip
                              key={fuelType}
                              size="small"
                              label={fuelType}
                              variant="outlined"
                            />
                          ))}
                        </Box>
                        {station.currentPrices && station.currentPrices.length > 0 && (
                          <Box mt={0.5}>
                            <Typography variant="caption" color="text.secondary">
                              Prices: {station.currentPrices.map(price => 
                                `${price.fuelGrade || price.fuelType}: $${price.pricePerUnit.toFixed(2)}`
                              ).join(', ')}
                            </Typography>
                          </Box>
                        )}
                      </Box>
                    }
                  />
                </ListItem>
              ))}
            </List>
          )}
        </DialogContent>
        <DialogActions>
          <Button onClick={() => setShowStationPicker(false)}>
            Cancel
          </Button>
        </DialogActions>
      </Dialog>
    </>
  );
};
```

## Database Schema for Station Data

### Future Station Data Tables

**File**: `backend/src/features/fuel-logs/migrations/003_add_station_data_support.sql`

```sql
-- Migration: 003_add_station_data_support.sql
-- Purpose: Add tables for caching station data and prices

BEGIN;

-- Stations cache table
CREATE TABLE IF NOT EXISTS fuel_stations (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  google_place_id VARCHAR(255) UNIQUE NOT NULL,
  name VARCHAR(200) NOT NULL,
  formatted_address TEXT,
  latitude DECIMAL(10,8),
  longitude DECIMAL(11,8),
  rating DECIMAL(2,1),
  price_level INTEGER,
  fuel_types TEXT[], -- Array of fuel types
  amenities TEXT[], -- Array of amenities
  brands TEXT[], -- Array of brand names
  is_active BOOLEAN DEFAULT true,
  created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
  updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);

-- Fuel prices cache table
CREATE TABLE IF NOT EXISTS fuel_prices (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  station_id UUID REFERENCES fuel_stations(id) ON DELETE CASCADE,
  fuel_type VARCHAR(20) NOT NULL,
  fuel_grade VARCHAR(10),
  price_per_unit DECIMAL(6,3) NOT NULL,
  currency VARCHAR(3) DEFAULT 'USD',
  source VARCHAR(50) NOT NULL,
  reported_at TIMESTAMP WITH TIME ZONE NOT NULL,
  created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
  
  -- Ensure unique price per station/fuel combination
  UNIQUE(station_id, fuel_type, fuel_grade, source)
);

-- Add indexes for performance
CREATE INDEX IF NOT EXISTS idx_fuel_stations_location ON fuel_stations USING GIST (
  ll_to_earth(latitude, longitude)
);
CREATE INDEX IF NOT EXISTS idx_fuel_stations_place_id ON fuel_stations(google_place_id);
CREATE INDEX IF NOT EXISTS idx_fuel_prices_station ON fuel_prices(station_id);
CREATE INDEX IF NOT EXISTS idx_fuel_prices_reported_at ON fuel_prices(reported_at);

-- Update triggers
CREATE OR REPLACE FUNCTION update_fuel_stations_updated_at()
RETURNS TRIGGER AS $$
BEGIN
  NEW.updated_at = NOW();
  RETURN NEW;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER trigger_fuel_stations_updated_at
  BEFORE UPDATE ON fuel_stations
  FOR EACH ROW EXECUTE FUNCTION update_fuel_stations_updated_at();

COMMIT;
```

## Configuration and Environment Setup

### Environment Variables for Location Services

**File**: `.env.example` (additions)

```bash
# Google Maps Integration
GOOGLE_MAPS_API_KEY=your_google_maps_api_key_here
GOOGLE_PLACES_CACHE_TTL=3600  # 1 hour in seconds
GOOGLE_GEOCODING_CACHE_TTL=86400  # 24 hours in seconds

# Location Service Configuration  
LOCATION_SERVICE_PROVIDER=google  # 'google' | 'mock'
STATION_SEARCH_DEFAULT_RADIUS=5000  # meters
STATION_SEARCH_MAX_RESULTS=20
STATION_PRICE_CACHE_TTL=1800  # 30 minutes in seconds

# Future: Additional service integrations
GASBUDDY_API_KEY=your_gasbuddy_api_key_here
MAPBOX_API_KEY=your_mapbox_api_key_here
```

### Service Factory Pattern

**File**: `backend/src/features/fuel-logs/external/location-service.factory.ts`

```typescript
import { LocationService } from './location.service.interface';
import { GoogleMapsService } from './google-maps.service';
import { MockLocationService } from './mock-location.service';

export class LocationServiceFactory {
  static create(): LocationService {
    const provider = process.env.LOCATION_SERVICE_PROVIDER || 'mock';
    
    switch (provider.toLowerCase()) {
      case 'google':
        return new GoogleMapsService();
      case 'mock':
        return new MockLocationService();
      default:
        throw new Error(`Unsupported location service provider: ${provider}`);
    }
  }
}
```

## API Endpoints for Location Integration

### Station Search Endpoints

**File**: `backend/src/features/fuel-logs/api/station-search.controller.ts`

```typescript
import { FastifyRequest, FastifyReply } from 'fastify';
import { LocationServiceFactory } from '../external/location-service.factory';
import { StationSearchOptions } from '../external/location.service.interface';
import { logger } from '../../../core/logging/logger';

export class StationSearchController {
  private locationService = LocationServiceFactory.create();
  
  async searchNearbyStations(
    request: FastifyRequest<{
      Body: {
        latitude: number;
        longitude: number;
        radius?: number;
        fuelTypes?: string[];
        maxResults?: number;
        openNow?: boolean;
      }
    }>,
    reply: FastifyReply
  ) {
    try {
      const { latitude, longitude, radius, fuelTypes, maxResults, openNow } = request.body;
      
      const options: StationSearchOptions = {
        coordinates: { latitude, longitude },
        radius,
        fuelTypes,
        maxResults,
        openNow
      };
      
      const stations = await this.locationService.searchNearbyStations(options);
      
      return reply.code(200).send({
        stations,
        searchOptions: options,
        resultCount: stations.length
      });
    } catch (error: any) {
      logger.error('Error searching nearby stations', { 
        error, 
        userId: (request as any).user?.sub 
      });
      
      return reply.code(500).send({
        error: 'Internal server error',
        message: 'Failed to search nearby stations'
      });
    }
  }
  
  async getStationDetails(
    request: FastifyRequest<{ Params: { placeId: string } }>,
    reply: FastifyReply
  ) {
    try {
      const { placeId } = request.params;
      
      const station = await this.locationService.getStationDetails(placeId);
      
      return reply.code(200).send(station);
    } catch (error: any) {
      logger.error('Error getting station details', { 
        error, 
        placeId: request.params.placeId,
        userId: (request as any).user?.sub 
      });
      
      if (error.message.includes('not found')) {
        return reply.code(404).send({
          error: 'Not Found',
          message: 'Station not found'
        });
      }
      
      return reply.code(500).send({
        error: 'Internal server error',
        message: 'Failed to get station details'
      });
    }
  }
  
  async getCurrentPrices(
    request: FastifyRequest<{ Params: { placeId: string } }>,
    reply: FastifyReply
  ) {
    try {
      const { placeId } = request.params;
      
      const prices = await this.locationService.getCurrentPrices(placeId);
      
      return reply.code(200).send({
        placeId,
        prices,
        lastUpdated: new Date().toISOString()
      });
    } catch (error: any) {
      logger.error('Error getting current prices', { 
        error, 
        placeId: request.params.placeId,
        userId: (request as any).user?.sub 
      });
      
      return reply.code(500).send({
        error: 'Internal server error',
        message: 'Failed to get current prices'
      });
    }
  }
}
```

## Testing Strategy for Location Services

### Mock Service Testing

**File**: `backend/src/features/fuel-logs/tests/unit/location-services.test.ts`

```typescript
import { MockLocationService } from '../../external/mock-location.service';
import { StationSearchOptions } from '../../external/location.service.interface';

describe('Location Services', () => {
  let mockLocationService: MockLocationService;
  
  beforeEach(() => {
    mockLocationService = new MockLocationService();
  });
  
  describe('MockLocationService', () => {
    it('should search nearby stations', async () => {
      const options: StationSearchOptions = {
        coordinates: { latitude: 37.7749, longitude: -122.4194 },
        radius: 5000,
        maxResults: 10
      };
      
      const stations = await mockLocationService.searchNearbyStations(options);
      
      expect(stations).toHaveLength(2);
      expect(stations[0].name).toBe('Shell Station');
      expect(stations[0].fuelTypes).toContain('gasoline');
    });
    
    it('should filter by fuel type', async () => {
      const options: StationSearchOptions = {
        coordinates: { latitude: 37.7749, longitude: -122.4194 },
        fuelTypes: ['electric']
      };
      
      const stations = await mockLocationService.searchNearbyStations(options);
      
      expect(stations).toHaveLength(1);
      expect(stations[0].name).toBe('EV Charging Station');
      expect(stations[0].fuelTypes).toEqual(['electric']);
    });
    
    it('should get station details', async () => {
      const station = await mockLocationService.getStationDetails('mock-station-1');
      
      expect(station.name).toBe('Shell Station');
      expect(station.currentPrices).toBeDefined();
      expect(station.currentPrices!.length).toBeGreaterThan(0);
    });
  });
});
```

## Future Enhancement Opportunities

### Advanced Features for Future Development

1. **Price Comparison & Alerts**
   - Real-time price comparison across stations
   - Price alert notifications when fuel prices drop
   - Historical price tracking and trends

2. **Route Optimization**
   - Find cheapest stations along a planned route
   - Integration with navigation apps
   - Multi-stop route planning with fuel considerations

3. **Loyalty Program Integration**
   - Connect with fuel station loyalty programs
   - Automatic discount application
   - Cashback and rewards tracking

4. **Predictive Analytics**
   - Predict fuel needs based on driving patterns
   - Suggest optimal refueling timing
   - Maintenance reminder integration

5. **Social Features**
   - User-reported prices and reviews
   - Station amenity crowdsourcing
   - Community-driven station information

6. **Fleet Management**
   - Multi-vehicle fleet tracking
   - Fuel budget management
   - Driver behavior analytics

## Implementation Tasks

### Backend Tasks
1. ✅ Create location service interface and implementations
2. ✅ Implement Google Maps service integration
3. ✅ Create mock service for development/testing
4. ✅ Design station data caching schema
5. ✅ Implement service factory pattern
6. ✅ Add API endpoints for station search
7. ✅ Create comprehensive testing strategy

### Frontend Tasks
1. ✅ Enhance location input component
2. ✅ Create station picker interface
3. ✅ Add geolocation functionality
4. ✅ Implement nearby station search
5. ✅ Design station details display
6. ✅ Add price display integration

### Configuration Tasks
1. ✅ Add environment variables for API keys
2. ✅ Create service configuration options
3. ✅ Implement caching strategies
4. ✅ Add error handling and fallbacks

## Success Criteria

### Phase 5 Complete When:
- ✅ Location service architecture designed and documented
- ✅ Google Maps integration interface implemented
- ✅ Mock location service functional for development
- ✅ Database schema ready for station data caching
- ✅ Frontend components prepared for location integration
- ✅ API endpoints designed and documented
- ✅ Testing strategy implemented
- ✅ Configuration management in place
- ✅ Future enhancement roadmap documented

### Ready for Google Maps Integration When:
- All interfaces and architecture in place
- Mock services tested and functional
- Frontend components integrated and tested
- API endpoints ready for production
- Caching strategy implemented
- Error handling comprehensive
- Documentation complete for future developers

---

**Implementation Complete**: All phases documented and ready for sequential implementation by future AI developers.