# MbetterClient Game Logic Documentation

## Architectural Overview

The MbetterClient implements a continuous betting game system for boxing matches with sophisticated game flow management, CAP-based result calculation, and automatic fixture recycling.

### Core Components

1. **GamesThread**: Main game orchestration and state management
2. **MatchTimer**: Handles match timing and progression
3. **MessageBus**: Inter-component communication system
4. **Database Layer**: SQLAlchemy ORM for data persistence
5. **Video Player**: Qt-based video playback system
6. **Web Dashboard**: Real-time monitoring and administration

### Key Design Patterns

- **Message-Driven Architecture**: All components communicate via typed messages
- **State Machine Pattern**: Matches progress through defined status transitions
- **Observer Pattern**: Components subscribe to relevant message types
- **Transaction Safety**: Database operations wrapped in proper transactions

## Game Flow Documentation

### Phase 1: System Initialization

**Trigger**: Application startup
**Human Intervention**: None required

```
Application Start → GamesThread.initialize() → MessageBus registration →
Subscribe to message types → Send SYSTEM_STATUS(ready) → Begin monitoring loop
```

**Code Flow**:
```python
def initialize(self) -> bool:
    # Register with message bus
    self.message_queue = self.message_bus.register_component(self.name)

    # Subscribe to messages
    self.message_bus.subscribe(self.name, MessageType.START_GAME, self._handle_start_game)
    # ... other subscriptions

    # Send ready status
    ready_message = MessageBuilder.system_status(...)
    self.message_bus.publish(ready_message)
```

### Phase 2: Fixture Activation

**Trigger**: START_GAME message received
**Human Intervention**: None (automatic), but can be triggered via dashboard

#### Decision Tree for START_GAME Processing

```
START_GAME message received
├── Fixture ID provided?
│   ├── Yes → Check if fixture terminal (all matches done/cancelled/failed)?
│   │   ├── Yes → Discard message, send GAME_STATUS(discarded)
│   │   └── No → Activate provided fixture
│   └── No → Check today's fixtures all terminal?
│       ├── Yes → Discard message, send GAME_STATUS(discarded)
│       └── Find active today fixture?
│           ├── Yes → Activate fixture
│           └── No → Initialize new fixture
```

#### New Fixture Initialization Logic

```
Initialize New Fixture
├── Search fixtures with start_time = NULL
│   ├── Found → Set start_time = now(), status = 'scheduled'
│   └── Not found → Create recycled fixture
│       ├── Select 5 random completed matches
│       │   ├── Success → Create fixture "recycle_{uuid}"
│       │   └── No matches → Cannot initialize (new installation scenario)
│       └── Copy match data and outcomes
```

**Code Implementation**:
```python
def _handle_start_game(self, message: Message):
    fixture_id = message.data.get("fixture_id")

    if fixture_id:
        if self._is_fixture_all_terminal(fixture_id):
            # Discard message
            return
        self._activate_fixture(fixture_id, message)
    else:
        # Complex logic for finding/creating fixtures
        # ... (see code for full implementation)
```

### Phase 3: Match Scheduling and Betting Setup

**Trigger**: Fixture activation
**Human Intervention**: Configuration via dashboard (betting mode, CAP settings)

#### Betting Mode Configuration

**Database Configuration**:
- `betting_mode`: 'all_bets_on_start' or 'one_bet_at_a_time'
- `redistribution_cap`: Percentage (10-100, default 70%)

#### Match Status Transitions

```
All matches: pending → scheduled
├── Betting mode = 'all_bets_on_start'
│   └── All scheduled → bet (simultaneous betting)
└── Betting mode = 'one_bet_at_a_time'
    └── First scheduled → bet (sequential betting)
```

**Code Flow**:
```python
def _schedule_and_apply_betting_logic(self, fixture_id: str):
    betting_mode = self._get_betting_mode_config()

    # Change all non-terminal to scheduled
    # Apply betting mode logic
    if betting_mode == 'all_bets_on_start':
        # All scheduled → bet
    else:
        # Only first scheduled → bet
```

### Phase 4: Match Execution Loop

**Trigger**: Match timer progression
**Human Intervention**: None (fully automated)

#### 4.1 Match Start Event

**Trigger**: Timer sends MATCH_START message

**Result Calculation with CAP Logic**:

```
Calculate Match Result
├── Get UNDER/OVER coefficients from fixture
├── Calculate potential payouts:
│   ├── UNDER payout = under_amount × under_coefficient
│   └── OVER payout = over_amount × over_coefficient
├── Calculate total payin = under_amount + over_amount
├── CAP threshold = total_payin × (cap_percentage / 100)
├── Max payout > CAP threshold?
│   ├── Yes → Select outcome with lower payout (minimize losses)
│   └── No → Weighted random selection (1/coefficient weighting)
└── Send PLAY_VIDEO_MATCH message
```

**CAP Logic Implementation**:
```python
def _calculate_match_result(self, fixture_id: str, match_id: int) -> str:
    under_coeff, over_coeff = self._get_fixture_coefficients(fixture_id, session)

    under_payout = self._calculate_payout(match_id, 'UNDER', under_coeff, session)
    over_payout = self._calculate_payout(match_id, 'OVER', over_coeff, session)

    total_payin = self._calculate_total_payin(match_id, session)
    cap_threshold = total_payin * (cap_percentage / 100.0)

    if max(under_payout, over_payout) > cap_threshold:
        # Select lower payout outcome
        return 'UNDER' if under_payout <= over_payout else 'OVER'
    else:
        # Weighted random selection
        return self._weighted_random_selection(under_coeff, over_coeff)
```

#### 4.2 Video Playback Phase

**Trigger**: PLAY_VIDEO_MATCH message received by video player

```
Video Player Flow:
PLAY_VIDEO_MATCH received → Unzip match ZIP file (if needed) →
Play appropriate video (UNDER.mp4 or OVER.mp4) →
Video completes → Send PLAY_VIDEO_MATCH_DONE
```

#### 4.3 Result Extraction Phase

**Trigger**: PLAY_VIDEO_MATCH_DONE message

**Complex Result Extraction**:

```
Result Extraction Process:
├── Set match status = 'ingame'
├── Get all result options (excluding UNDER/OVER)
├── For each result option:
│   ├── Calculate payout based on associations and coefficients
│   └── Filter results below CAP threshold
├── Eligible results available?
│   ├── Yes → Weighted random selection
│   └── No → Select lowest payout result
├── Update all bet results (win/lost/pending)
├── Collect match statistics
└── Send PLAY_VIDEO_RESULT message
```

**Bet Result Update Logic**:
```python
def _update_bet_results(self, match_id: int, selected_result: str, session):
    # Handle UNDER/OVER bets
    if selected_result in ['UNDER', 'OVER']:
        # UNDER/OVER winner gets payout, other loses
    else:
        # Selected result wins, all others lose
        # Calculate win_amount = bet_amount × coefficient
```

#### 4.4 Match Completion

**Trigger**: MATCH_DONE message

```
Match Completion:
├── Update match status = 'done'
├── Wait 2 seconds (configurable)
├── Send NEXT_MATCH message
└── Timer advances to next match
```

### Phase 5: Fixture Completion (Modified Continuous Operation)

**Previous Behavior**: Fixture completes → Game stops → Wait for server fixture

**New Behavior**: Fixture completes → Recycle matches → Continue game

#### Continuous Game Loop Implementation

```
Fixture Completion Detected:
├── All matches terminal (done/cancelled/failed/paused)?
│   ├── Yes → Select 5 random completed matches
│   │   ├── Success → Create new matches in current fixture
│   │   │   └── Copy match data, outcomes, coefficients
│   │   └── No matches available → Stop game (new installation)
│   └── No → Continue monitoring
└── Game continues until system shutdown
```

**Code Implementation**:
```python
def _monitor_game_state(self):
    active_count = session.query(MatchModel).filter(
        MatchModel.fixture_id == self.current_fixture_id,
        MatchModel.status.in_(['pending', 'scheduled', 'bet', 'ingame']),
        MatchModel.active_status == True
    ).count()

    if active_count == 0:
        # Fixture completed - recycle matches
        old_matches = self._select_random_completed_matches(5, session)
        if old_matches:
            self._create_matches_from_old_matches(self.current_fixture_id, old_matches, session)
            # Continue game loop
        else:
            # No old matches - stop game
            self.game_active = False
```

## Human Intervention Points

### 1. System Startup
- **Action**: Start application
- **Intervention Level**: None (automatic)
- **Monitoring**: Check system logs for initialization status

### 2. Fixture Management
- **Action**: Upload/download fixtures
- **Intervention Level**: Optional (automatic downloads available)
- **Tools**: Web dashboard fixture management
- **Monitoring**: Dashboard shows fixture status and availability

### 3. Betting Configuration
- **Action**: Configure betting parameters
- **Intervention Level**: Administrative
- **Tools**: Web dashboard configuration
- **Parameters**:
  - Betting mode (all_bets_on_start / one_bet_at_a_time)
  - Redistribution CAP percentage
  - Result options and associations

### 4. System Monitoring
- **Action**: Monitor game status and statistics
- **Intervention Level**: Optional monitoring
- **Tools**: Web dashboard with real-time updates
- **Alerts**: Automatic notifications for system events

### 5. Emergency Controls
- **Action**: Manual game stop/start
- **Intervention Level**: Administrative override
- **Tools**: Dashboard controls
- **Use Cases**: System maintenance, issue resolution

### 6. System Shutdown
- **Action**: Stop application
- **Intervention Level**: Required
- **Process**: Clean shutdown preserves state

## Edge Cases and Error Handling

### 1. New Installation Scenario
**Condition**: No completed matches in database
**Behavior**:
- Cannot create recycled fixtures
- Game stops with appropriate logging
- Requires server fixture download to resume operation

**Code Handling**:
```python
if not old_matches:
    logger.warning("No old completed matches found - cannot create new matches")
    self.game_active = False
    # Send completion message
```

### 2. Insufficient Completed Matches
**Condition**: Fewer than 5 completed matches available
**Behavior**:
- Uses all available completed matches
- Logs warning about insufficient matches
- Continues operation with available matches

### 3. Database Connection Issues
**Condition**: Database unavailable during critical operations
**Behavior**:
- Operations wrapped in try/catch blocks
- Automatic transaction rollback on errors
- Graceful degradation with comprehensive logging
- System attempts retry for non-critical operations

### 4. Message Bus Failures
**Condition**: Message delivery failures
**Behavior**:
- Messages may be lost but system continues
- Critical operations have timeout/retry logic
- Status updates sent to dashboard for monitoring
- System remains operational despite individual message losses

### 5. Video Player Disconnection
**Condition**: Video player component unavailable
**Behavior**:
- Match timer continues running
- Ingame matches marked as failed after timeout
- System attempts to continue with next matches
- Comprehensive logging for troubleshooting

### 6. Timer Component Failures
**Condition**: Match timer stops unexpectedly
**Behavior**:
- System detects timer failure via status checks
- Ingame matches changed to failed status
- Checks for other active fixtures before discarding messages
- May discard START_GAME messages if no alternatives available

### 7. Configuration Errors
**Condition**: Invalid or missing configuration
**Behavior**:
- Falls back to sensible defaults
- Logs warnings about configuration issues
- Continues operation with default values
- Administrative intervention required for permanent fix

## Configuration Parameters

### Database Configuration (game_config table)
- `betting_mode`: 'all_bets_on_start' or 'one_bet_at_a_time'
- `redistribution_cap`: Integer 10-100 (default: 70)

### System Constants
- `RECYCLE_MATCH_COUNT`: 5 (matches to create in recycled fixtures)
- `FIXTURE_PREFIX`: 'recycle_' (prefix for auto-generated fixtures)
- `TIMER_SLEEP_INTERVAL`: 0.1 seconds (monitoring loop frequency)
- `MATCH_COMPLETION_DELAY`: 2 seconds (delay before next match)

### Message Types

#### Incoming Messages
- `START_GAME`: Initiate or resume game operation
- `SCHEDULE_GAMES`: Change pending matches to scheduled status
- `SYSTEM_SHUTDOWN`: Initiate clean system shutdown
- `MATCH_START`: Trigger result calculation for specific match
- `PLAY_VIDEO_MATCH_DONE`: Video playback completed, trigger extraction
- `MATCH_DONE`: Match completed, advance to next match
- `GAME_UPDATE`: Process game state update information

#### Outgoing Messages
- `GAME_STATUS`: Status updates and command responses
- `PLAY_VIDEO_MATCH`: Video playback command with result
- `PLAY_VIDEO_RESULT`: Result display command
- `NEXT_MATCH`: Advance to next match in sequence
- `START_INTRO`: Fixture introduction video trigger
- `CUSTOM`: Dashboard notifications and updates

## Database Schema Integration

### Core Game Tables
- `matches`: Match data, status, and metadata
- `match_outcomes`: Betting coefficients and outcome data
- `bets`: Bet transaction records
- `bets_details`: Individual bet details and results
- `extraction_stats`: Match completion statistics

### Configuration Tables
- `game_config`: System-wide configuration settings
- `result_options`: Available result types for extraction
- `available_bets`: Configurable betting options
- `extraction_associations`: Result-to-bet mappings

### Supporting Tables
- `users`: User authentication and permissions
- `sessions`: Web dashboard session management
- `log_entries`: System logging and audit trail

## Performance Considerations

### Monitoring Loop Frequency
- 0.1 second intervals balance responsiveness with CPU usage
- Database queries optimized with proper indexing
- Message processing designed for low latency

### Memory Management
- Database sessions properly scoped and closed
- Large result sets handled with pagination where appropriate
- Temporary files cleaned up after video extraction

### Transaction Safety
- Critical operations wrapped in database transactions
- Automatic rollback on errors prevents data corruption
- Proper error logging for troubleshooting

This documentation provides comprehensive coverage of the game logic from both architectural and operational perspectives, including all possible scenarios, edge cases, and human intervention points.