# Statistics & Photo Album Integration Guide

## Overview

The statistics and photo album system tracks lifetime player statistics and captures memorable life moments. This guide explains how to integrate these features into existing game events.

## Database Tables

The system uses three main tables (created in `migrations/001_monetization_and_retention.sql`):

1. **`player_statistics`** - Tracks 15+ lifetime statistics
2. **`player_photo_album`** - Stores memorable life moments with metadata
3. **`player_inventory`** - Tracks item ownership (used by achievements)

## Module Location

**File:** `/home/user/lichun/ws/retention/statistics.py`

## Core Functions

### Statistics Tracking

```python
from retention.statistics import (
    increment_stat,
    update_stat,
    set_boolean_stat,
    get_player_statistics,
    initialize_player_statistics
)

# Initialize stats for new player (call on account creation)
initialize_player_statistics(player_id)

# Increment a stat by amount (default 1)
increment_stat(player_id, 'total_activities', 1)
increment_stat(player_id, 'lifetime_earnings', 5000)

# Set a stat to specific value (for "highest" or "max" stats)
update_stat(player_id, 'highest_job_level', 5)

# Set boolean stat
set_boolean_stat(player_id, 'ever_married', True)

# Get all player statistics
stats = get_player_statistics(player_id)
# Returns: {'lifetime_earnings': 50000, 'total_deaths': 2, ...}
```

### Photo Album

```python
from retention.statistics import (
    capture_photo_memory,
    get_photo_album,
    get_photo_album_count,
    get_photos_by_type
)

# Capture a memorable moment
photo_id = capture_photo_memory(
    player_id=1,
    event_type='graduation',
    description='Graduated from Harvard University',
    snapshot_data={
        'level': 'college',
        'gpa': 3.8,
        'major': 'Computer Science'
    },
    character_age=22,  # Optional, will fetch from DB if not provided
    game_date=datetime.now()  # Optional, uses current time if not provided
)

# Get player's photo album (50 most recent photos)
photos = get_photo_album(player_id, limit=50, offset=0)

# Get total photo count
count = get_photo_album_count(player_id)

# Get photos of specific type
graduations = get_photos_by_type(player_id, 'graduation')
```

### Helper Functions

```python
from retention.statistics import (
    track_money_earned,
    track_money_spent,
    track_relationship_formed,
    track_activity_completed,
    track_conversation
)

# Quick helpers for common operations
track_money_earned(player_id, 5000)  # Increment lifetime_earnings
track_money_spent(player_id, 1000)   # Increment lifetime_spending
track_relationship_formed(player_id)  # Increment total_relationships
track_activity_completed(player_id)   # Increment total_activities
track_conversation(player_id)         # Increment total_conversations
```

## Statistics Available

The following statistics are tracked:

| Stat Name | Type | Description |
|-----------|------|-------------|
| `lifetime_earnings` | BIGINT | Total money earned across all lives |
| `lifetime_spending` | BIGINT | Total money spent across all lives |
| `total_relationships` | INT | Total relationships formed |
| `total_activities` | INT | Total activities completed |
| `total_conversations` | INT | Total conversations held |
| `total_years_lived` | INT | Total years lived across all lives |
| `total_deaths` | INT | Number of times died/reincarnated |
| `highest_job_level` | INT | Highest job level reached |
| `max_affinity_reached` | INT | Maximum affinity reached with anyone |
| `people_dated` | INT | Number of people dated |
| `times_fired` | INT | Number of times fired from jobs |
| `years_married` | INT | Total years spent married |
| `job_count` | INT | Total number of jobs held |
| `children_count` | INT | Total number of children |
| `friends_count` | INT | Total number of friends made |
| `ever_married` | BOOLEAN | Whether player has ever been married |

## Photo Album Event Types

Common event types to use:

- `'graduation'` - School/college graduations
- `'marriage'` - Wedding events
- `'birth'` - Birth of children
- `'promotion'` - Job promotions
- `'death'` - End of life
- `'best_friend'` - Achieving best friend status
- `'dating'` - Starting to date someone
- `'first_job'` - First job obtained
- `'achievement'` - Major achievements unlocked
- `'milestone'` - Other significant life milestones

## Integration Points

### 1. Server Initialization (`ws/app.py`)

Initialize player statistics when a new player account is created:

```python
from retention.statistics import initialize_player_statistics

# In player creation code
def create_new_player(user_id):
    # ... existing player creation logic ...

    # Initialize statistics
    initialize_player_statistics(user_id)

    # ... rest of initialization ...
```

### 2. Graduation Events (`ws/dayEvents.py` or `ws/events.py`)

```python
from retention.statistics import increment_stat, capture_photo_memory
from retention.achievements import check_achievements

def graduationEvent(player, level):
    # ... existing graduation logic ...

    # Track statistics
    increment_stat(player.userID, 'total_activities', 1)

    # Capture photo memory
    capture_photo_memory(
        player_id=player.userID,
        event_type='graduation',
        description=f'Graduated from {level}',
        snapshot_data={
            'level': level,
            'gpa': getattr(player.c, 'gpa', 0),
            'age': player.c.age
        }
    )

    # Check achievements
    check_achievements(player.userID, 'graduate', {
        'level': level,
        'gpa': getattr(player.c, 'gpa', 0)
    })
```

### 3. Marriage Events

```python
from retention.statistics import increment_stat, set_boolean_stat, capture_photo_memory

def marriageEvent(player, spouse):
    # ... existing marriage logic ...

    # Track statistics
    increment_stat(player.userID, 'total_relationships', 1)
    set_boolean_stat(player.userID, 'ever_married', True)

    # Capture photo memory
    capture_photo_memory(
        player_id=player.userID,
        event_type='marriage',
        description=f'Married {spouse.firstname} {spouse.lastname}',
        snapshot_data={
            'spouse_name': f'{spouse.firstname} {spouse.lastname}',
            'age': player.c.age
        }
    )

    # Check achievements
    from retention.achievements import check_achievements
    check_achievements(player.userID, 'marriage', {})
```

### 4. Job/Promotion Events

```python
from retention.statistics import increment_stat, update_stat, get_player_statistics, capture_photo_memory

def promotionEvent(player, new_title, new_level, salary):
    # ... existing promotion logic ...

    # Track job count
    increment_stat(player.userID, 'job_count', 1)

    # Update highest job level if this is a new record
    stats = get_player_statistics(player.userID)
    if new_level > stats.get('highest_job_level', 0):
        update_stat(player.userID, 'highest_job_level', new_level)

    # Capture photo memory
    capture_photo_memory(
        player_id=player.userID,
        event_type='promotion',
        description=f'Promoted to {new_title}',
        snapshot_data={
            'title': new_title,
            'level': new_level,
            'salary': salary
        }
    )

    # Check achievements
    from retention.achievements import check_achievements
    check_achievements(player.userID, 'promotion', {'title': new_title})
```

### 5. Birth of Child Events

```python
from retention.statistics import increment_stat, capture_photo_memory, get_player_statistics

def birthEvent(player, child_name):
    # ... existing birth logic ...

    # Track statistics
    increment_stat(player.userID, 'children_count', 1)
    increment_stat(player.userID, 'total_relationships', 1)

    # Capture photo memory
    capture_photo_memory(
        player_id=player.userID,
        event_type='birth',
        description=f'{child_name} was born',
        snapshot_data={
            'child_name': child_name,
            'parent_age': player.c.age
        }
    )

    # Check achievements
    from retention.achievements import check_achievements
    stats = get_player_statistics(player.userID)
    check_achievements(player.userID, 'birth_child', {
        'children_count': stats.get('children_count', 1)
    })
```

### 6. Death/End of Life Events

```python
from retention.statistics import increment_stat, capture_photo_memory

def deathEvent(player):
    # ... existing death logic ...

    # Track statistics
    increment_stat(player.userID, 'total_deaths', 1)
    increment_stat(player.userID, 'total_years_lived', player.c.age)

    # Capture photo memory
    capture_photo_memory(
        player_id=player.userID,
        event_type='death',
        description=f'Passed away at age {player.c.age}',
        snapshot_data={
            'age': player.c.age,
            'money': player.c.money,
            'occupation': getattr(player.c, 'occupation', None)
        }
    )

    # Check achievements
    from retention.achievements import check_achievements
    check_achievements(player.userID, 'death', {
        'age': player.c.age,
        'money': player.c.money
    })
```

### 7. Friendship/Affinity Events

```python
from retention.statistics import increment_stat, update_stat, get_player_statistics, capture_photo_memory

def affinityChangeEvent(player, npc, new_affinity, old_affinity):
    # ... existing affinity logic ...

    # Update max affinity if this is a new record
    stats = get_player_statistics(player.userID)
    if new_affinity > stats.get('max_affinity_reached', 0):
        update_stat(player.userID, 'max_affinity_reached', new_affinity)

    # If crossing friendship threshold (50+)
    if old_affinity < 50 and new_affinity >= 50:
        increment_stat(player.userID, 'friends_count', 1)

        from retention.achievements import check_achievements
        check_achievements(player.userID, 'make_friend', {})

    # If reaching best friend status (100+)
    if old_affinity < 100 and new_affinity >= 100:
        capture_photo_memory(
            player_id=player.userID,
            event_type='best_friend',
            description=f'Became best friends with {npc.firstname}',
            snapshot_data={
                'friend_name': f'{npc.firstname} {npc.lastname}',
                'affinity': new_affinity
            }
        )

        from retention.achievements import check_achievements
        check_achievements(player.userID, 'affinity_milestone', {
            'affinity': new_affinity
        })
```

### 8. Dating Events

```python
from retention.statistics import increment_stat, capture_photo_memory

def startDatingEvent(player, partner):
    # ... existing dating logic ...

    # Track people dated
    increment_stat(player.userID, 'people_dated', 1)

    # Capture photo memory
    capture_photo_memory(
        player_id=player.userID,
        event_type='dating',
        description=f'Started dating {partner.firstname}',
        snapshot_data={
            'partner_name': f'{partner.firstname} {partner.lastname}',
            'age': player.c.age
        }
    )
```

### 9. Job Termination Events

```python
from retention.statistics import increment_stat, get_player_statistics

def firedEvent(player, reason):
    # ... existing fired logic ...

    # Track times fired
    increment_stat(player.userID, 'times_fired', 1)

    # Check achievements
    from retention.achievements import check_achievements
    stats = get_player_statistics(player.userID)
    check_achievements(player.userID, 'fired', {
        'times_fired': stats.get('times_fired', 0)
    })
```

### 10. Money Transactions

```python
from retention.statistics import track_money_earned, track_money_spent

# In salary/income events
def receiveSalary(player, amount):
    # ... existing logic ...
    player.c.money += amount

    # Track earnings
    track_money_earned(player.userID, amount)

# In purchase events
def purchaseItem(player, item, cost):
    # ... existing logic ...
    player.c.money -= cost

    # Track spending
    track_money_spent(player.userID, cost)
```

### 11. Conversation Events

```python
from retention.statistics import track_conversation

def handleConversation(player, npc):
    # ... existing conversation logic ...

    # Track conversation
    track_conversation(player.userID)
```

## Best Practices

1. **Initialize on Player Creation**: Always call `initialize_player_statistics(player_id)` when creating a new player account.

2. **Track Before Checking Achievements**: Update statistics before calling `check_achievements()` so achievements can use the updated stats.

3. **Use Helper Functions**: Use `track_money_earned()`, `track_conversation()`, etc. for common operations instead of calling `increment_stat()` directly.

4. **Photo Memory Guidelines**:
   - Only capture truly memorable moments (graduations, marriages, major milestones)
   - Include relevant context in `snapshot_data`
   - Use consistent `event_type` strings across the codebase

5. **Error Handling**: All functions return success/failure indicators. Check return values for critical operations.

6. **Performance**: The statistics functions are optimized with database indexing and efficient queries. Safe to call frequently.

## Testing

Test the integration with:

```python
# Create test player
test_player_id = 1

# Initialize
from retention.statistics import initialize_player_statistics
initialize_player_statistics(test_player_id)

# Track some stats
from retention.statistics import increment_stat, capture_photo_memory
increment_stat(test_player_id, 'total_activities', 5)
increment_stat(test_player_id, 'lifetime_earnings', 10000)

# Capture a photo
capture_photo_memory(
    player_id=test_player_id,
    event_type='test',
    description='Test memory',
    snapshot_data={'test': True}
)

# Verify
from retention.statistics import get_player_statistics, get_photo_album
stats = get_player_statistics(test_player_id)
print(f"Stats: {stats}")

photos = get_photo_album(test_player_id)
print(f"Photos: {len(photos)}")
```

## WebSocket Message Types

When photo memories are captured or statistics reach milestones, consider sending these messages to the client:

```python
# Photo captured notification
{
    'type': 'photoMemoryCaptured',
    'event_type': 'graduation',
    'description': 'Graduated from Harvard',
    'snapshot_data': {...}
}

# Statistics milestone reached
{
    'type': 'statisticMilestone',
    'stat_name': 'lifetime_earnings',
    'value': 1000000,
    'milestone': 'First Million'
}
```

## Frontend Integration

The iOS app (`lichunWebsocket`) should display:

1. **Statistics View** - Show all lifetime statistics
2. **Photo Album** - Grid/timeline view of memorable moments
3. **Achievement Gallery** - Unlocked achievements with statistics

See the frontend documentation for UI implementation details.

## Related Systems

- **Achievement System** (`retention/achievements.py`) - Checks statistics for achievement unlocks
- **Diamond Economy** (`monetization/diamond_economy.py`) - Awards diamonds for achievements
- **Daily Quests** (`retention/daily_quests.py`) - Uses statistics for quest progress

## Troubleshooting

**Statistics not updating?**
- Check that `initialize_player_statistics(player_id)` was called for the player
- Verify player_id is correct
- Check logs for errors

**Photos not appearing?**
- Verify `snapshot_data` is JSON-serializable (no custom objects)
- Check that event_type string is valid
- Ensure database table exists (run migration)

**Performance issues?**
- Batch statistic updates when possible
- Don't capture photo memories for trivial events
- Use pagination when fetching photo album

## Support

For questions or issues, check:
- Database migration: `/home/user/lichun/ws/migrations/001_monetization_and_retention.sql`
- Implementation: `/home/user/lichun/ws/retention/statistics.py`
- Tests: `/home/user/lichun/ws/tests/unit/test_stats.py`
