# PayoutCalculator

Calculates prize payouts using a two-tier system with guaranteed minimums and premium pool allocation. Implements the 12-tier prize distribution based on match combinations.

## State Variables

| Variable                   | Type                                              | Description                                  |
| -------------------------- | ------------------------------------------------- | -------------------------------------------- |
| `jackpot`                  | `IJackpot`                                        | Immutable reference to Jackpot contract      |
| `minimumPayout`            | `uint256`                                         | Base minimum payout amount (USDC)            |
| `premiumTierMinAllocation` | `uint256`                                         | Min % of pool for premium tiers (1e18 scale) |
| `minPayoutTiers`           | `bool[12]`                                        | Which tiers receive minimum payouts          |
| `premiumTierWeights`       | `uint256[12]`                                     | Premium pool allocation weights              |
| `drawingTierInfo`          | `mapping(uint256 => DrawingTierInfo)`             | Frozen tier config per drawing               |
| `tierPayouts`              | `mapping(uint256 => mapping(uint256 => uint256))` | Calculated payouts                           |

## Constants

```solidity
uint256 PRECISE_UNIT = 1e18;
uint8 NORMAL_BALL_COUNT = 5;
uint8 TOTAL_TIER_COUNT = 12;  // matches(0-5) × bonusball(0,1) = 12 tiers
```

## Structs

### DrawingTierInfo

```solidity
struct DrawingTierInfo {
    uint256 minPayout;                    // Minimum payout for eligible tiers
    uint256 premiumTierMinAllocation;     // Min allocation for premium tiers
    bool[12] minPayoutTiers;              // Tier eligibility for min payouts
    uint256[12] premiumTierWeights;       // Premium pool weights
}
```

## Events

### PrizeTierPayoutsCalculated

```solidity
event PrizeTierPayoutsCalculated(uint256 drawingId, uint256[12] tierPayouts);
```

## Prize Tier System

The system uses 12 tiers based on matches and bonusball:

| Tier | Normal Matches | Bonusball | Formula                  |
| ---- | -------------- | --------- | ------------------------ |
| 0    | 0              | No        | `0*2 + 0 = 0`            |
| 1    | 0              | Yes       | `0*2 + 1 = 1`            |
| 2    | 1              | No        | `1*2 + 0 = 2`            |
| 3    | 1              | Yes       | `1*2 + 1 = 3`            |
| 4    | 2              | No        | `2*2 + 0 = 4`            |
| 5    | 2              | Yes       | `2*2 + 1 = 5`            |
| 6    | 3              | No        | `3*2 + 0 = 6`            |
| 7    | 3              | Yes       | `3*2 + 1 = 7`            |
| 8    | 4              | No        | `4*2 + 0 = 8`            |
| 9    | 4              | Yes       | `4*2 + 1 = 9`            |
| 10   | 5              | No        | `5*2 + 0 = 10`           |
| 11   | 5              | Yes       | `5*2 + 1 = 11` (Jackpot) |

## Functions

### getTierPayout

Get the calculated payout for a specific tier in a drawing.

```solidity
function getTierPayout(uint256 _drawingId, uint256 _tierId) external view returns (uint256)
```

**Parameters:**

| Name         | Type      | Description      |
| ------------ | --------- | ---------------- |
| `_drawingId` | `uint256` | Drawing to query |
| `_tierId`    | `uint256` | Tier ID (0-11)   |

**Returns:**

| Type      | Description                                 |
| --------- | ------------------------------------------- |
| `uint256` | Payout amount per winning ticket (USDC wei) |

**Example:**

```solidity
// Get jackpot (tier 11) payout for current drawing
uint256 drawingId = jackpot.currentDrawingId();
uint256 jackpotPayout = payoutCalculator.getTierPayout(drawingId, 11);
```

***

### getDrawingTierPayouts

Get all tier payouts for a specific drawing.

```solidity
function getDrawingTierPayouts(uint256 _drawingId) external view returns (uint256[12] memory)
```

**Parameters:**

| Name         | Type      | Description      |
| ------------ | --------- | ---------------- |
| `_drawingId` | `uint256` | Drawing to query |

**Returns:**

| Type          | Description                              |
| ------------- | ---------------------------------------- |
| `uint256[12]` | Array of payout amounts for all 12 tiers |

**Example:**

```solidity
uint256[12] memory payouts = payoutCalculator.getDrawingTierPayouts(drawingId);

// Display all payouts
for (uint256 i = 0; i < 12; i++) {
    uint256 matches = i / 2;
    bool bonusball = i % 2 == 1;
    console.log("Matches:", matches, "Bonusball:", bonusball, "Payout:", payouts[i]);
}
```

***

### getExpectedDrawingTierPayouts

Estimate expected payouts for a drawing (settled or current).

```solidity
function getExpectedDrawingTierPayouts(
    uint256 _drawingId,
    uint256 _prizePool,
    uint8 _normalMax,
    uint8 _bonusballMax
) external view returns (uint256[12] memory)
```

**Parameters:**

| Name            | Type      | Description                |
| --------------- | --------- | -------------------------- |
| `_drawingId`    | `uint256` | Drawing to calculate for   |
| `_prizePool`    | `uint256` | Total prize pool available |
| `_normalMax`    | `uint8`   | Maximum normal ball number |
| `_bonusballMax` | `uint8`   | Maximum bonusball number   |

**Returns:**

| Type          | Description                            |
| ------------- | -------------------------------------- |
| `uint256[12]` | Estimated payout amounts for all tiers |

**Example:**

```solidity
uint256 drawingId = jackpot.currentDrawingId();
IJackpot.DrawingState memory state = jackpot.getDrawingState(drawingId);

uint256[12] memory expectedPayouts = payoutCalculator.getExpectedDrawingTierPayouts(
    drawingId,
    state.prizePool,
    state.ballMax,
    state.bonusballMax
);

// Show expected jackpot
uint256 expectedJackpot = expectedPayouts[11];
```

***

### getMinPayoutTiers

Get current minimum payout tier configuration.

```solidity
function getMinPayoutTiers() external view returns (bool[12] memory)
```

**Returns:**

| Type       | Description                                              |
| ---------- | -------------------------------------------------------- |
| `bool[12]` | Boolean array indicating min payout eligibility per tier |

***

### getPremiumTierWeights

Get current premium pool allocation weights.

```solidity
function getPremiumTierWeights() external view returns (uint256[12] memory)
```

**Returns:**

| Type          | Description                                   |
| ------------- | --------------------------------------------- |
| `uint256[12]` | Weight allocation for each tier (sum to 1e18) |

***

### getDrawingTierInfo

Get the frozen tier configuration for a specific drawing.

```solidity
function getDrawingTierInfo(uint256 _drawingId) external view returns (DrawingTierInfo memory)
```

**Parameters:**

| Name         | Type      | Description      |
| ------------ | --------- | ---------------- |
| `_drawingId` | `uint256` | Drawing to query |

**Returns:**

| Type              | Description                                       |
| ----------------- | ------------------------------------------------- |
| `DrawingTierInfo` | Complete tier configuration used for that drawing |

## Payout Calculation Logic

### Two-Phase System

1. **Minimum Payouts**: Guaranteed minimum amount for eligible tiers
2. **Premium Pool**: Remaining pool distributed by weight allocation

### Calculation Flow

```
Prize Pool
    │
    ├─► Minimum Payout Allocation (if enabled)
    │   └─► Distributed to eligible tiers
    │
    └─► Premium Pool (remaining)
        └─► Distributed by tier weights
```

### Premium Protection

If minimum payouts would consume too much of the pool:

* `(premiumMinAllocation × prizePool) + minimumPayoutAllocation >= prizePool`
* Minimum payouts are disabled for that drawing
* Entire pool distributed by premium weights

## Integration Example

```solidity
contract PayoutDisplay {
    IPayoutCalculator public calculator;
    IJackpot public jackpot;

    function displayExpectedPayouts() external view returns (string memory) {
        uint256 drawingId = jackpot.currentDrawingId();
        IJackpot.DrawingState memory state = jackpot.getDrawingState(drawingId);

        uint256[12] memory payouts = calculator.getExpectedDrawingTierPayouts(
            drawingId,
            state.prizePool,
            state.ballMax,
            state.bonusballMax
        );

        // Format payouts for display
        // Tier 11 (5 matches + bonusball) = Jackpot
        // Tier 10 (5 matches, no bonusball) = 2nd prize
        // etc.
    }

    function getTierForTicket(uint256 matches, bool bonusballMatch)
        external
        pure
        returns (uint256)
    {
        return matches * 2 + (bonusballMatch ? 1 : 0);
    }
}
```
