# API Documentation

## Overview

The AFA Systems Presence Detection API provides RESTful endpoints for managing beacons, settings, and real-time WebSocket communication for live updates.

## Base URL

```
http://localhost:8080
```

## Authentication

Currently, the API does not implement authentication. This should be added for production deployments.

## REST API Endpoints

### Beacon Management

#### Get All Beacons
Retrieves a list of all registered beacons with their current status and location information.

```http
GET /api/beacons
```

**Response:**
```json
{
  "beacons": [
    {
      "name": "Conference Room Beacon",
      "beacon_id": "beacon_001",
      "beacon_type": "ingics",
      "beacon_location": "conference_room",
      "last_seen": 1703078400,
      "distance": 2.5,
      "location_confidence": 85,
      "hs_button_counter": 42,
      "hs_button_battery": 85,
      "hs_button_random": "abc123",
      "hs_button_mode": "normal"
    }
  ]
}
```

#### Create Beacon
Registers a new beacon in the system.

```http
POST /api/beacons
Content-Type: application/json
```

**Request Body:**
```json
{
  "name": "Meeting Room Beacon",
  "beacon_id": "beacon_002",
  "beacon_type": "eddystone",
  "beacon_location": "meeting_room",
  "hs_button_counter": 0,
  "hs_button_battery": 100
}
```

**Response:**
```json
{
  "message": "Beacon created successfully",
  "beacon": {
    "name": "Meeting Room Beacon",
    "beacon_id": "beacon_002",
    "beacon_type": "eddystone",
    "beacon_location": "meeting_room",
    "last_seen": 0,
    "distance": 0,
    "location_confidence": 0,
    "hs_button_counter": 0,
    "hs_button_battery": 100
  }
}
```

#### Update Beacon
Updates an existing beacon's information.

```http
PUT /api/beacons/{id}
Content-Type: application/json
```

**Path Parameters:**
- `id` (string): The beacon ID to update

**Request Body:**
```json
{
  "name": "Updated Conference Room Beacon",
  "beacon_location": "main_conference",
  "location_confidence": 90
}
```

**Response:**
```json
{
  "message": "Beacon updated successfully",
  "beacon": {
    "name": "Updated Conference Room Beacon",
    "beacon_id": "beacon_001",
    "beacon_type": "ingics",
    "beacon_location": "main_conference",
    "last_seen": 1703078400,
    "distance": 2.5,
    "location_confidence": 90,
    "hs_button_counter": 42,
    "hs_button_battery": 85
  }
}
```

#### Delete Beacon
Removes a beacon from the system.

```http
DELETE /api/beacons/{id}
```

**Path Parameters:**
- `id` (string): The beacon ID to delete

**Response:**
```json
{
  "message": "Beacon deleted successfully"
}
```

### Settings Management

#### Get System Settings
Retrieves current system configuration settings.

```http
GET /api/settings
```

**Response:**
```json
{
  "settings": {
    "location_confidence": 80,
    "last_seen_threshold": 300,
    "beacon_metrics_size": 10,
    "ha_send_interval": 60,
    "ha_send_changes_only": true,
    "rssi_min_threshold": -90,
    "enforce_rssi_threshold": true
  }
}
```

#### Update System Settings
Updates system configuration settings.

```http
POST /api/settings
Content-Type: application/json
```

**Request Body:**
```json
{
  "location_confidence": 85,
  "last_seen_threshold": 600,
  "beacon_metrics_size": 15,
  "ha_send_interval": 30,
  "rssi_min_threshold": -85
}
```

**Response:**
```json
{
  "message": "Settings updated successfully",
  "settings": {
    "location_confidence": 85,
    "last_seen_threshold": 600,
    "beacon_metrics_size": 15,
    "ha_send_interval": 30,
    "ha_send_changes_only": true,
    "rssi_min_threshold": -85,
    "enforce_rssi_threshold": true
  }
}
```

### Location Information

#### Get Beacon Locations
Retrieves current location information for all beacons.

```http
GET /api/locations
```

**Response:**
```json
{
  "beacons": [
    {
      "method": "location_update",
      "previous_confident_location": "reception",
      "distance": 3.2,
      "id": "beacon_001",
      "location": "conference_room",
      "last_seen": 1703078450
    },
    {
      "method": "location_update",
      "previous_confident_location": "office_a",
      "distance": 1.8,
      "id": "beacon_002",
      "location": "meeting_room",
      "last_seen": 1703078440
    }
  ]
}
```

#### Get Specific Beacon Location
Retrieves location information for a specific beacon.

```http
GET /api/locations/{id}
```

**Path Parameters:**
- `id` (string): The beacon ID

**Response:**
```json
{
  "method": "location_update",
  "previous_confident_location": "reception",
  "distance": 3.2,
  "id": "beacon_001",
  "location": "conference_room",
  "last_seen": 1703078450
}
```

### Health Check

#### System Health
Check if the API server is running and basic systems are operational.

```http
GET /api/health
```

**Response:**
```json
{
  "status": "healthy",
  "timestamp": "2024-12-20T10:30:00Z",
  "services": {
    "database": "connected",
    "kafka": "connected",
    "redis": "connected"
  }
}
```

## WebSocket API

### WebSocket Connection
Connect to the WebSocket endpoint for real-time updates.

```
ws://localhost:8080/ws/broadcast
```

### WebSocket Message Format

#### Beacon Update Notification
```json
{
  "type": "beacon_update",
  "data": {
    "method": "location_update",
    "beacon_info": {
      "name": "Conference Room Beacon",
      "beacon_id": "beacon_001",
      "beacon_type": "ingics",
      "distance": 2.5
    },
    "name": "conference_room",
    "beacon_name": "Conference Room Beacon",
    "previous_location": "reception",
    "new_location": "conference_room",
    "timestamp": 1703078450
  }
}
```

#### Button Press Event
```json
{
  "type": "button_event",
  "data": {
    "beacon_id": "beacon_001",
    "button_counter": 43,
    "button_mode": "normal",
    "timestamp": 1703078460
  }
}
```

#### Battery Alert
```json
{
  "type": "battery_alert",
  "data": {
    "beacon_id": "beacon_002",
    "battery_level": 15,
    "alert_level": "warning",
    "timestamp": 1703078470
  }
}
```

#### Fall Detection Event
```json
{
  "type": "fall_detection",
  "data": {
    "beacon_id": "beacon_001",
    "event_type": "fall_detected",
    "confidence": 92,
    "timestamp": 1703078480
  }
}
```

#### System Status Update
```json
{
  "type": "system_status",
  "data": {
    "active_beacons": 12,
    "total_locations": 8,
    "kafka_status": "connected",
    "redis_status": "connected",
    "timestamp": 1703078490
  }
}
```

## Data Models

### Beacon Model
```typescript
interface Beacon {
  name: string;
  beacon_id: string;
  beacon_type: "ingics" | "eddystone" | "minew_b7" | "ibeacon";
  beacon_location: string;
  last_seen: number;      // Unix timestamp
  distance: number;        // Distance in meters
  previous_location?: string;
  previous_confident_location?: string;
  expired_location?: string;
  location_confidence: number;  // 0-100
  location_history: string[];
  beacon_metrics: BeaconMetric[];

  // Handshake/Button specific fields
  hs_button_counter: number;
  hs_button_prev: number;
  hs_button_battery: number;
  hs_button_random: string;
  hs_button_mode: string;
}
```

### BeaconMetric Model
```typescript
interface BeaconMetric {
  location: string;
  distance: number;
  rssi: number;
  timestamp: number;
}
```

### Settings Model
```typescript
interface Settings {
  location_confidence: number;        // Minimum confidence level (0-100)
  last_seen_threshold: number;         // Seconds before beacon considered offline
  beacon_metrics_size: number;         // Number of RSSI measurements to keep
  ha_send_interval: number;            // Home Assistant update interval (seconds)
  ha_send_changes_only: boolean;        // Only send updates on changes
  rssi_min_threshold: number;          // Minimum RSSI for detection
  enforce_rssi_threshold: boolean;     // Filter weak signals
}
```

### LocationChange Model
```typescript
interface LocationChange {
  method: string;                      // "location_update" | "beacon_added" | "beacon_removed"
  beacon_ref: Beacon;                  // Complete beacon information
  name: string;                        // Beacon name
  beacon_name: string;                 // Beacon name (duplicate)
  previous_location: string;           // Previous location
  new_location: string;                // New location
  timestamp: number;                   // Unix timestamp
}
```

## Error Responses

### Standard Error Format
```json
{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Invalid request data",
    "details": {
      "field": "beacon_id",
      "reason": "Beacon ID is required"
    }
  }
}
```

### Common Error Codes

| Code | HTTP Status | Description |
|------|-------------|-------------|
| `VALIDATION_ERROR` | 400 | Request data validation failed |
| `NOT_FOUND` | 404 | Resource not found |
| `CONFLICT` | 409 | Resource already exists |
| `INTERNAL_ERROR` | 500 | Internal server error |
| `SERVICE_UNAVAILABLE` | 503 | Required service is unavailable |

### Validation Error Example
```http
POST /api/beacons
Content-Type: application/json
```

**Invalid Request:**
```json
{
  "name": "",
  "beacon_type": "invalid_type"
}
```

**Response:**
```json
{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Invalid request data",
    "details": {
      "name": "Name cannot be empty",
      "beacon_type": "Invalid beacon type. Must be one of: ingics, eddystone, minew_b7, ibeacon"
    }
  }
}
```

## Rate Limiting

Currently, the API does not implement rate limiting. Consider implementing rate limiting for production deployments:

- Suggested limits: 100 requests per minute per IP address
- WebSocket connections: Maximum 50 concurrent connections
- Consider authentication-based rate limiting

## CORS Configuration

The API server is configured with CORS enabled for development. Production deployments should restrict CORS origins to specific domains.

## Integration Examples

### JavaScript/TypeScript Client

```typescript
class PresenceAPIClient {
  private baseURL: string;

  constructor(baseURL: string = 'http://localhost:8080') {
    this.baseURL = baseURL;
  }

  async getBeacons(): Promise<Beacon[]> {
    const response = await fetch(`${this.baseURL}/api/beacons`);
    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }
    const data = await response.json();
    return data.beacons;
  }

  async createBeacon(beacon: Partial<Beacon>): Promise<Beacon> {
    const response = await fetch(`${this.baseURL}/api/beacons`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify(beacon),
    });

    if (!response.ok) {
      const error = await response.json();
      throw new Error(error.error?.message || 'Failed to create beacon');
    }

    const data = await response.json();
    return data.beacon;
  }

  connectWebSocket(onMessage: (message: any) => void): WebSocket {
    const ws = new WebSocket(`${this.baseURL.replace('http', 'ws')}/ws/broadcast`);

    ws.onmessage = (event) => {
      try {
        const message = JSON.parse(event.data);
        onMessage(message);
      } catch (error) {
        console.error('Failed to parse WebSocket message:', error);
      }
    };

    ws.onerror = (error) => {
      console.error('WebSocket error:', error);
    };

    ws.onclose = () => {
      console.log('WebSocket connection closed');
    };

    return ws;
  }
}

// Usage example
const client = new PresenceAPIClient();

// Get all beacons
const beacons = await client.getBeacons();
console.log('Active beacons:', beacons);

// Create a new beacon
const newBeacon = await client.createBeacon({
  name: 'Test Beacon',
  beacon_id: 'test_beacon_001',
  beacon_type: 'eddystone',
  beacon_location: 'test_room'
});

// Connect to WebSocket for real-time updates
const ws = client.connectWebSocket((message) => {
  switch (message.type) {
    case 'beacon_update':
      console.log('Beacon location updated:', message.data);
      break;
    case 'button_event':
      console.log('Button pressed:', message.data);
      break;
    case 'battery_alert':
      console.log('Low battery warning:', message.data);
      break;
  }
});
```

### Python Client

```python
import requests
import websocket
import json
from typing import List, Dict, Any

class PresenceAPIClient:
    def __init__(self, base_url: str = "http://localhost:8080"):
        self.base_url = base_url
        self.ws_url = base_url.replace("http", "ws")

    def get_beacons(self) -> List[Dict[str, Any]]:
        """Get all registered beacons."""
        response = requests.get(f"{self.base_url}/api/beacons")
        response.raise_for_status()
        data = response.json()
        return data["beacons"]

    def create_beacon(self, beacon_data: Dict[str, Any]) -> Dict[str, Any]:
        """Create a new beacon."""
        response = requests.post(
            f"{self.base_url}/api/beacons",
            json=beacon_data
        )
        response.raise_for_status()
        data = response.json()
        return data["beacon"]

    def update_beacon(self, beacon_id: str, beacon_data: Dict[str, Any]) -> Dict[str, Any]:
        """Update an existing beacon."""
        response = requests.put(
            f"{self.base_url}/api/beacons/{beacon_id}",
            json=beacon_data
        )
        response.raise_for_status()
        data = response.json()
        return data["beacon"]

    def delete_beacon(self, beacon_id: str) -> None:
        """Delete a beacon."""
        response = requests.delete(f"{self.base_url}/api/beacons/{beacon_id}")
        response.raise_for_status()

    def get_settings(self) -> Dict[str, Any]:
        """Get system settings."""
        response = requests.get(f"{self.base_url}/api/settings")
        response.raise_for_status()
        return response.json()["settings"]

    def update_settings(self, settings_data: Dict[str, Any]) -> Dict[str, Any]:
        """Update system settings."""
        response = requests.post(
            f"{self.base_url}/api/settings",
            json=settings_data
        )
        response.raise_for_status()
        return response.json()["settings"]

# Usage example
client = PresenceAPIClient()

# Get all beacons
beacons = client.get_beacons()
print(f"Found {len(beacons)} beacons")

# Create a new beacon
new_beacon = client.create_beacon({
    "name": "Python Test Beacon",
    "beacon_id": "python_test_001",
    "beacon_type": "eddystone",
    "beacon_location": "python_room"
})
print(f"Created beacon: {new_beacon['name']}")

# Update settings
settings = client.update_settings({
    "location_confidence": 85,
    "ha_send_interval": 30
})
print(f"Updated settings: {settings}")
```

## Testing

### Unit Testing Example (Go)

```go
package api_test

import (
    "bytes"
    "encoding/json"
    "net/http"
    "net/http/httptest"
    "testing"
    "github.com/stretchr/testify/assert"
)

func TestGetBeacons(t *testing.T) {
    // Setup test server
    router := setupTestRouter()

    req, _ := http.NewRequest("GET", "/api/beacons", nil)
    w := httptest.NewRecorder()
    router.ServeHTTP(w, req)

    assert.Equal(t, http.StatusOK, w.Code)

    var response map[string]interface{}
    err := json.Unmarshal(w.Body.Bytes(), &response)
    assert.NoError(t, err)
    assert.Contains(t, response, "beacons")
}

func TestCreateBeacon(t *testing.T) {
    router := setupTestRouter()

    beaconData := map[string]interface{}{
        "name":           "Test Beacon",
        "beacon_id":      "test_001",
        "beacon_type":    "eddystone",
        "beacon_location": "test_room",
    }

    jsonData, _ := json.Marshal(beaconData)
    req, _ := http.NewRequest("POST", "/api/beacons", bytes.NewBuffer(jsonData))
    req.Header.Set("Content-Type", "application/json")

    w := httptest.NewRecorder()
    router.ServeHTTP(w, req)

    assert.Equal(t, http.StatusCreated, w.Code)

    var response map[string]interface{}
    err := json.Unmarshal(w.Body.Bytes(), &response)
    assert.NoError(t, err)
    assert.Contains(t, response, "beacon")
}
```

## Security Considerations

For production deployments, consider implementing:

1. **Authentication**: JWT tokens or API key authentication
2. **Authorization**: Role-based access control (RBAC)
3. **Rate Limiting**: Prevent API abuse
4. **Input Validation**: Comprehensive input sanitization
5. **HTTPS**: TLS encryption for all API communications
6. **CORS**: Restrict origins to trusted domains
7. **Logging**: Comprehensive audit logging
8. **Security Headers**: Implement security HTTP headers

## API Versioning

The current API is version 1. Future versions will be:

- Version 1: `/api/v1/...` (current, implied)
- Version 2: `/api/v2/...` (future breaking changes)

Backward compatibility will be maintained within major versions.