# Daily Login Reward System

## Overview

The Daily Login Reward System tracks player login streaks and awards diamonds, energy, items, or prestige based on consecutive daily logins. The system uses a 7-day cycle that repeats indefinitely.

## Database Tables

### `daily_login_rewards`
Stores reward definitions for each day (1-7).

```sql
CREATE TABLE daily_login_rewards (
    day_number INT PRIMARY KEY,
    reward_type ENUM('diamonds', 'energy', 'item', 'prestige'),
    reward_amount INT,
    reward_item_id INT NULL,
    display_name VARCHAR(100)
);
```

### `player_login_streak`
Tracks each player's login streak.

```sql
CREATE TABLE player_login_streak (
    player_id INT PRIMARY KEY,
    current_streak INT DEFAULT 0,
    last_login_date DATE,
    total_logins INT DEFAULT 0,
    next_reward_day INT DEFAULT 1
);
```

## Reward Calendar

| Day | Reward Type | Amount | Description |
|-----|-------------|--------|-------------|
| 1   | Diamonds    | 5      | 5 Diamonds  |
| 2   | Diamonds    | 10     | 10 Diamonds |
| 3   | Energy      | 50     | 50 Energy   |
| 4   | Diamonds    | 15     | 15 Diamonds |
| 5   | Diamonds    | 20     | 20 Diamonds + Item |
| 6   | Diamonds    | 25     | 25 Diamonds |
| 7   | Diamonds    | 50     | 50 Diamonds Bonus |

After day 7, the cycle repeats starting from day 1.

## API Functions

### `initialize_daily_rewards()`
Inserts or updates reward definitions in the database.
- **When to call:** Server startup (optional - rewards are already in migration)
- **Returns:** None

```python
from retention.daily_rewards import initialize_daily_rewards
initialize_daily_rewards()
```

### `check_daily_login(player_id: int) -> dict`
Checks and updates a player's daily login streak.
- **When to call:** When player connects to server
- **Returns:**
  ```python
  {
      'reward_available': bool,  # Can claim reward today
      'streak': int,             # Current streak count
      'reward': dict or None,    # Today's reward info
      'streak_broken': bool      # Was streak reset today
  }
  ```

**Example:**
```python
from retention.daily_rewards import check_daily_login

result = check_daily_login(player_id=123)
if result['reward_available']:
    print(f"Streak: {result['streak']} days")
    print(f"Reward: {result['reward']['name']}")
```

### `claim_daily_reward(player_id: int) -> dict`
Claims and awards today's reward to the player.
- **When to call:** When player clicks "Claim" button
- **Returns:**
  ```python
  {
      'success': bool,
      'reward': dict or None,
      'message': str
  }
  ```

**Example:**
```python
from retention.daily_rewards import claim_daily_reward

result = claim_daily_reward(player_id=123)
if result['success']:
    print(f"Claimed: {result['reward']['name']}")
```

### `get_daily_reward(day_number: int) -> dict`
Gets reward definition for a specific day.
- **Parameters:** day_number (1-7)
- **Returns:** Reward dict or None

**Example:**
```python
from retention.daily_rewards import get_daily_reward

reward = get_daily_reward(3)
print(f"Day 3: {reward['name']}")
```

### `get_login_streak_info(player_id: int) -> dict`
Gets player's current streak information.
- **Returns:**
  ```python
  {
      'current_streak': int,
      'total_logins': int,
      'next_reward_day': int,
      'last_login_date': str (ISO format)
  }
  ```

**Example:**
```python
from retention.daily_rewards import get_login_streak_info

info = get_login_streak_info(player_id=123)
print(f"Streak: {info['current_streak']} days")
print(f"Total logins: {info['total_logins']}")
```

### `get_all_rewards() -> list`
Gets all reward definitions from database.
- **Returns:** List of reward dicts

**Example:**
```python
from retention.daily_rewards import get_all_rewards

rewards = get_all_rewards()
for reward in rewards:
    print(f"Day {reward['day_number']}: {reward['display_name']}")
```

### `handle_daily_login_check(player_id: int, send_to_client: callable)`
WebSocket handler for daily login check.
- **Parameters:**
  - `player_id`: Player's ID
  - `send_to_client`: Function to send messages (player_id, message_dict)
- **Purpose:** Sends daily reward notification to client on login

**Example:**
```python
from retention.daily_rewards import handle_daily_login_check

# In your WebSocket handler
handle_daily_login_check(player_id, send_to_client_function)
```

## Integration with WebSocket Server

### 1. On Player Connection (app.py)

```python
# In handler() or start() function after player connects
from retention.daily_rewards import handle_daily_login_check

async def start(websocket):
    player_id = get_player_id(websocket)

    # Check daily login and send notification
    handle_daily_login_check(player_id, lambda pid, msg: asyncio.create_task(
        websocket.send(json.dumps(msg))
    ))
```

### 2. Handle Claim Request

```python
# In consumer() function
if event['type'] == 'claimDailyReward':
    from retention.daily_rewards import claim_daily_reward

    result = claim_daily_reward(player_id)
    await websocket.send(json.dumps({
        'type': 'dailyRewardClaimed',
        'success': result['success'],
        'reward': result['reward'],
        'message': result['message']
    }))
```

### 3. Get Streak Info

```python
# Handle request for streak info
if event['type'] == 'getLoginStreak':
    from retention.daily_rewards import get_login_streak_info

    info = get_login_streak_info(player_id)
    await websocket.send(json.dumps({
        'type': 'loginStreakInfo',
        'data': info
    }))
```

## WebSocket Message Format

### Server → Client: Reward Available
```json
{
    "type": "dailyRewardAvailable",
    "streak": 5,
    "streak_broken": false,
    "reward": {
        "day": 5,
        "type": "diamonds",
        "amount": 20,
        "name": "20 Diamonds + Item"
    }
}
```

### Server → Client: No Reward Today
```json
{
    "type": "dailyLoginStatus",
    "streak": 5,
    "reward_available": false
}
```

### Client → Server: Claim Reward
```json
{
    "type": "claimDailyReward"
}
```

### Server → Client: Reward Claimed
```json
{
    "type": "dailyRewardClaimed",
    "success": true,
    "reward": {
        "day": 5,
        "type": "diamonds",
        "amount": 20,
        "name": "20 Diamonds + Item"
    },
    "message": "Reward claimed successfully"
}
```

## Business Logic

### Streak Calculation
1. **First login:** Streak = 1, Day = 1
2. **Login next day:** Streak increments, Day = (current_day % 7) + 1
3. **Miss a day (2+ days gap):** Streak resets to 1, Day = 1
4. **Already logged in today:** No reward, return current streak

### Reward Types
- **diamonds:** Added to player's diamond balance, logged in transactions
- **energy:** Added to player's energy (capped at max_energy)
- **prestige:** Added to player's prestige points
- **item:** Random luxury item from store_items table

## Testing

Run the test suite:
```bash
cd /home/user/lichun/ws
python3 test_daily_rewards.py
```

## Migration

The database tables and initial reward data are created by:
- **File:** `/home/user/lichun/ws/migrations/001_monetization_and_retention.sql`
- **Tables:** `daily_login_rewards`, `player_login_streak`
- **Initial data:** 7-day reward cycle

## Error Handling

All functions include comprehensive error handling:
- Database connection errors
- Missing player records (creates new streak on first login)
- Missing reward definitions
- Transaction rollback on failures
- Detailed logging for debugging

## Logging

All major events are logged:
- First-time logins
- Streak continuations
- Streak breaks
- Reward claims
- Errors and exceptions

Check logs for:
```
Player {id} first login - starting streak
Player {id} daily login - streak: {n}, day: {d}
Player {id} streak broken after {n} days
Player {id} claimed daily reward: Day {d}
```
