# Games Endpoints

Manage the Jackbox game catalog. Games belong to packs (e.g., "Jackbox Party Pack 7"). Each game has player limits, type, audience support, family-friendliness, and favor bias for weighted selection. Packs can also have favor/disfavor bias to influence the picker.

## Endpoint Summary

| Method | Path | Auth | Description |
|--------|------|------|-------------|
| GET | `/api/games` | No | List games with optional filters |
| GET | `/api/games/packs` | No | List all packs |
| GET | `/api/games/meta/packs` | No | Pack metadata (counts, plays) |
| GET | `/api/games/export/csv` | Bearer | Export games as CSV |
| PATCH | `/api/games/packs/{name}/favor` | Bearer | Set pack favor bias |
| GET | `/api/games/{id}` | No | Get single game |
| POST | `/api/games` | Bearer | Create game |
| PUT | `/api/games/{id}` | Bearer | Update game |
| DELETE | `/api/games/{id}` | Bearer | Delete game |
| PATCH | `/api/games/{id}/toggle` | Bearer | Toggle game enabled status |
| PATCH | `/api/games/packs/{name}/toggle` | Bearer | Enable/disable all games in pack |
| POST | `/api/games/import/csv` | Bearer | Import games from CSV |
| PATCH | `/api/games/{id}/favor` | Bearer | Set game favor bias |

---

## GET /api/games

List all games with optional query filters. Results are ordered by `pack_name`, then `title`.

### Authentication

None.

### Parameters

| Name | In | Type | Required | Description |
|------|-----|------|----------|-------------|
| enabled | query | string | No | `"true"` or `"false"` to filter by enabled status |
| playerCount | query | integer | No | Filter games where `min_players ≤ count ≤ max_players` |
| drawing | query | string | No | `"only"` = `game_type='Drawing'`, `"exclude"` = exclude Drawing |
| length | query | string | No | `"short"` (≤15 min or NULL), `"medium"` (16–25 min), `"long"` (>25 min) |
| familyFriendly | query | string | No | `"true"` or `"false"` |
| pack | query | string | No | Exact `pack_name` match |

### Response

**200 OK**

```json
[
  {
    "id": 1,
    "pack_name": "Jackbox Party Pack 7",
    "title": "Quiplash 3",
    "min_players": 3,
    "max_players": 8,
    "length_minutes": 15,
    "has_audience": 1,
    "family_friendly": 0,
    "game_type": "Writing",
    "secondary_type": null,
    "play_count": 0,
    "popularity_score": 0,
    "enabled": 1,
    "favor_bias": 0,
    "created_at": "2024-01-15T12:00:00.000Z"
  }
]
```

### Error Responses

| Status | Body | When |
|--------|------|------|
| 500 | `{ "error": "..." }` | Server error |

### Example

```bash
curl "http://localhost:5000/api/games?playerCount=6&pack=Jackbox%20Party%20Pack%207"
```

---

## GET /api/games/packs

List all packs with their favor bias.

### Authentication

None.

### Response

**200 OK**

```json
[
  {
    "id": 1,
    "name": "Jackbox Party Pack 7",
    "favor_bias": 0,
    "created_at": "2024-01-15T12:00:00.000Z"
  }
]
```

---

## GET /api/games/meta/packs

Return pack metadata: total game count, enabled count, and total plays per pack.

### Authentication

None.

### Response

**200 OK**

```json
[
  {
    "name": "Jackbox Party Pack 7",
    "total_count": 5,
    "enabled_count": 5,
    "total_plays": 42
  }
]
```

---

## GET /api/games/export/csv

Export the full game catalog as a CSV file download.

### Authentication

Bearer token required.

### Response

**200 OK**

- Content-Type: `text/csv`
- Content-Disposition: `attachment; filename="jackbox-games.csv"`
- Columns: Pack Name, Title, Min Players, Max Players, Length (minutes), Audience, Family Friendly, Game Type, Secondary Type

### Example

```bash
curl -o jackbox-games.csv "http://localhost:5000/api/games/export/csv" \
  -H "Authorization: Bearer $TOKEN"
```

---

## PATCH /api/games/packs/{name}/favor

Set favor bias for a pack. Affects weighted random selection in the picker.

### Authentication

Bearer token required.

### Path Parameters

| Name | Type | Description |
|------|------|-------------|
| name | string | Pack name (exact match, URL-encode if spaces) |

### Request Body

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| favor_bias | integer | Yes | `1` = favor, `-1` = disfavor, `0` = neutral |

```json
{
  "favor_bias": 1
}
```

### Response

**200 OK**

```json
{
  "message": "Pack favor bias updated successfully",
  "favor_bias": 1
}
```

### Error Responses

| Status | Body | When |
|--------|------|------|
| 400 | `{ "error": "favor_bias must be 1 (favor), -1 (disfavor), or 0 (neutral)" }` | Invalid value |

### Example

```bash
curl -X PATCH "http://localhost:5000/api/games/packs/Jackbox%20Party%20Pack%207/favor" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"favor_bias": 1}'
```

---

## GET /api/games/{id}

Get a single game by ID.

### Authentication

None.

### Path Parameters

| Name | Type | Description |
|------|------|-------------|
| id | integer | Game ID |

### Response

**200 OK**

```json
{
  "id": 1,
  "pack_name": "Jackbox Party Pack 7",
  "title": "Quiplash 3",
  "min_players": 3,
  "max_players": 8,
  "length_minutes": 15,
  "has_audience": 1,
  "family_friendly": 0,
  "game_type": "Writing",
  "secondary_type": null,
  "play_count": 0,
  "popularity_score": 0,
  "enabled": 1,
  "favor_bias": 0,
  "created_at": "2024-01-15T12:00:00.000Z"
}
```

### Error Responses

| Status | Body | When |
|--------|------|------|
| 404 | `{ "error": "Game not found" }` | Invalid ID |

### Example

```bash
curl "http://localhost:5000/api/games/1"
```

---

## POST /api/games

Create a new game. Pack is created automatically if it does not exist.

### Authentication

Bearer token required.

### Request Body

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| pack_name | string | Yes | Pack name (e.g., "Jackbox Party Pack 7") |
| title | string | Yes | Game title |
| min_players | integer | Yes | Minimum players |
| max_players | integer | Yes | Maximum players |
| length_minutes | integer | No | Approx. play length |
| has_audience | boolean | No | Audience mode supported |
| family_friendly | boolean | No | Family-friendly rating |
| game_type | string | No | Primary type (e.g., "Writing", "Drawing") |
| secondary_type | string | No | Secondary type |

```json
{
  "pack_name": "Jackbox Party Pack 7",
  "title": "Quiplash 3",
  "min_players": 3,
  "max_players": 8,
  "length_minutes": 15,
  "has_audience": true,
  "family_friendly": false,
  "game_type": "Writing",
  "secondary_type": null
}
```

### Response

**201 Created**

Returns the created game object.

### Error Responses

| Status | Body | When |
|--------|------|------|
| 400 | `{ "error": "Missing required fields" }` | Missing pack_name, title, min_players, or max_players |

### Example

```bash
curl -X POST "http://localhost:5000/api/games" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "pack_name": "Jackbox Party Pack 7",
    "title": "Quiplash 3",
    "min_players": 3,
    "max_players": 8,
    "length_minutes": 15,
    "has_audience": true,
    "family_friendly": false,
    "game_type": "Writing",
    "secondary_type": null
  }'
```

---

## PUT /api/games/{id}

Update a game. All fields are optional; uses COALESCE (only provided fields are updated).

### Authentication

Bearer token required.

### Path Parameters

| Name | Type | Description |
|------|------|-------------|
| id | integer | Game ID |

### Request Body

All fields optional. Include only the fields to update.

```json
{
  "pack_name": "Jackbox Party Pack 7",
  "title": "Quiplash 3",
  "min_players": 3,
  "max_players": 8,
  "length_minutes": 20,
  "has_audience": true,
  "family_friendly": false,
  "game_type": "Writing",
  "secondary_type": null,
  "enabled": true
}
```

### Response

**200 OK**

Returns the updated game object.

### Error Responses

| Status | Body | When |
|--------|------|------|
| 404 | `{ "error": "Game not found" }` | Invalid ID |

### Example

```bash
curl -X PUT "http://localhost:5000/api/games/1" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"length_minutes": 20, "enabled": true}'
```

---

## DELETE /api/games/{id}

Delete a game permanently.

### Authentication

Bearer token required.

### Path Parameters

| Name | Type | Description |
|------|------|-------------|
| id | integer | Game ID |

### Response

**200 OK**

```json
{
  "message": "Game deleted successfully"
}
```

### Error Responses

| Status | Body | When |
|--------|------|------|
| 404 | `{ "error": "Game not found" }` | Invalid ID |

### Example

```bash
curl -X DELETE "http://localhost:5000/api/games/1" \
  -H "Authorization: Bearer $TOKEN"
```

---

## PATCH /api/games/{id}/toggle

Toggle the game's `enabled` field (0↔1). Use to quickly enable/disable a game without a full PUT.

### Authentication

Bearer token required.

### Path Parameters

| Name | Type | Description |
|------|------|-------------|
| id | integer | Game ID |

### Response

**200 OK**

Returns the updated game object with the flipped `enabled` value.

### Error Responses

| Status | Body | When |
|--------|------|------|
| 404 | `{ "error": "Game not found" }` | Invalid ID |

### Example

```bash
curl -X PATCH "http://localhost:5000/api/games/1/toggle" \
  -H "Authorization: Bearer $TOKEN"
```

---

## PATCH /api/games/packs/{name}/toggle

Enable or disable all games in a pack at once.

### Authentication

Bearer token required.

### Path Parameters

| Name | Type | Description |
|------|------|-------------|
| name | string | Pack name (URL-encode if spaces) |

### Request Body

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| enabled | boolean | Yes | `true` to enable, `false` to disable |

```json
{
  "enabled": true
}
```

### Response

**200 OK**

```json
{
  "message": "Pack enabled successfully",
  "gamesAffected": 12
}
```

Message varies: "Pack enabled successfully" or "Pack disabled successfully" based on the `enabled` value.

### Error Responses

| Status | Body | When |
|--------|------|------|
| 400 | `{ "error": "enabled status required" }` | Missing `enabled` field |

### Example

```bash
curl -X PATCH "http://localhost:5000/api/games/packs/Jackbox%20Party%20Pack%207/toggle" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"enabled": true}'
```

---

## POST /api/games/import/csv

Import games from CSV data. Default mode is `append`. Use `"replace"` to delete all existing games before importing.

### Authentication

Bearer token required.

### Request Body

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| csvData | string | Yes | Raw CSV content (header + rows) |
| mode | string | No | `"append"` (default) or `"replace"` |

**CSV columns:** Game Pack, Game Title, Min. Players, Max. Players, Length, Audience, Family Friendly?, Game Type, Secondary Type

```json
{
  "csvData": "Game Pack,Game Title,Min. Players,Max. Players,Length,Audience,Family Friendly?,Game Type,Secondary Type\nJackbox Party Pack 7,Quiplash 3,3,8,15,Yes,No,Writing,\nJackbox Party Pack 7,The Devils and the Details,3,7,25,Yes,No,Strategy,",
  "mode": "append"
}
```

### Response

**200 OK**

```json
{
  "message": "Successfully imported 5 games",
  "count": 5,
  "mode": "append"
}
```

### Error Responses

| Status | Body | When |
|--------|------|------|
| 400 | `{ "error": "CSV data required" }` | Missing `csvData` |

### Example

```bash
curl -X POST "http://localhost:5000/api/games/import/csv" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "csvData": "Game Pack,Game Title,Min. Players,Max. Players,Length,Audience,Family Friendly?,Game Type,Secondary Type\nJackbox Party Pack 7,Quiplash 3,3,8,15,Yes,No,Writing,\nJackbox Party Pack 7,The Devils and the Details,3,7,25,Yes,No,Strategy,",
    "mode": "append"
  }'
```

---

## PATCH /api/games/{id}/favor

Set favor bias for a single game. Affects weighted random selection in the picker.

### Authentication

Bearer token required.

### Path Parameters

| Name | Type | Description |
|------|------|-------------|
| id | integer | Game ID |

### Request Body

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| favor_bias | integer | Yes | `1` = favor, `-1` = disfavor, `0` = neutral |

```json
{
  "favor_bias": -1
}
```

### Response

**200 OK**

```json
{
  "message": "Favor bias updated successfully",
  "favor_bias": -1
}
```

### Error Responses

| Status | Body | When |
|--------|------|------|
| 400 | `{ "error": "favor_bias must be 1 (favor), -1 (disfavor), or 0 (neutral)" }` | Invalid value |
| 404 | `{ "error": "Game not found" }` | Invalid ID |

### Example

```bash
curl -X PATCH "http://localhost:5000/api/games/1/favor" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"favor_bias": -1}'
```
