# Location Model

## Overview
The Location model provides polymorphic location management for parks, areas, and other entities in ThrillWiki. It handles geocoding, coordinate management, and location-based search capabilities.

## Structure

### Database Table
- Table Name: `locations`
- Primary Key: `id` (bigint)
- Polymorphic Fields: `locatable_type`, `locatable_id`
- Timestamps: `created_at`, `updated_at`

### Fields
- **Address Components**
  - `address` (string, nullable) - Street address
  - `city` (string) - City name
  - `state` (string, nullable) - State/province
  - `country` (string) - Country name
  - `postal_code` (string, nullable) - Postal/ZIP code

- **Spatial Data**
  - `coordinates` (point) - PostGIS point geometry with SRID 4326
  - `elevation` (decimal, 8,2, nullable) - Elevation in meters

- **Additional Details**
  - `timezone` (string, nullable) - Location timezone
  - `metadata` (json, nullable) - Additional location data
  - `is_approximate` (boolean) - Indicates if location is approximate
  - `source` (string, nullable) - Data source identifier

- **Geocoding**
  - `geocoding_data` (json, nullable) - Cached geocoding response
  - `geocoded_at` (timestamp, nullable) - Last geocoding timestamp

### Indexes
- Spatial: `coordinates` (spatial index for efficient queries)
- Location: `(country, state, city)`
- Postal: `postal_code`

### PostGIS Integration
- Uses PostGIS point type for coordinates
- SRID 4326 (WGS 84) for global coordinates
- Spatial indexing for efficient queries
- Native distance calculations
- Geographic vs Geometric operations

## Relationships

### Polymorphic
- `locatable()` - Polymorphic relationship to parent model (Park, Area, etc.)

## Accessors & Mutators
- `coordinates` - Returns [lat, lng] array
- `formatted_address` - Returns formatted address string
- `map_url` - Returns Google Maps URL

## Methods

### Location Management
- `updateCoordinates(float $lat, float $lng)` - Update coordinates
- `setAddress(array $components)` - Set address components
- `geocode()` - Trigger geocoding refresh
- `reverseGeocode()` - Get address from coordinates

### Queries
- `scopeNearby($query, $lat, $lng, $radius)` - Find nearby locations
- `scopeInBounds($query, $ne, $sw)` - Find locations in bounds
- `scopeInCountry($query, $country)` - Filter by country
- `scopeInState($query, $state)` - Filter by state
- `scopeInCity($query, $city)` - Filter by city

### Calculations
- `distanceTo($lat, $lng)` - Calculate distance to point
- `bearingTo($lat, $lng)` - Calculate bearing to point

## Usage Examples

```php
// Create location for park
$park->location()->create([
    'address' => '123 Main St',
    'city' => 'Orlando',
    'state' => 'FL',
    'country' => 'USA',
    'latitude' => 28.538336,
    'longitude' => -81.379234
]);

// Find parks within 50km
$nearbyParks = Park::whereHas('location', function ($query) {
    $query->nearby(28.538336, -81.379234, 50);
})->get();
```

## Integration Points

### Services
- GeocodeService - Address/coordinate lookup
- LocationSearchService - Advanced location search

### Components
- LocationSelector - Map-based location picker
- LocationDisplay - Location visualization

## Notes
- Coordinates use high precision for accuracy
- Geocoding results are cached to reduce API calls
- Polymorphic design allows reuse across models
- Search methods use spatial indexes for performance