# JackpotAutoSubscription

Enables recurring ticket purchases across multiple drawings. Users prepay for a subscription period and keepers execute daily ticket purchases automatically.

## State Variables

| Variable            | Type                               | Description                             |
| ------------------- | ---------------------------------- | --------------------------------------- |
| `jackpot`           | `IJackpot`                         | Immutable reference to Jackpot contract |
| `usdc`              | `IERC20`                           | Immutable USDC token reference          |
| `batchFacilitator`  | `IBatchPurchaseFacilitator`        | Batch facilitator for large orders      |
| `subscriptions`     | `mapping(address => Subscription)` | Active subscriptions per user           |
| `staticTickets`     | `mapping(address => Ticket[])`     | Static tickets per user                 |
| `ticketPickerNonce` | `uint256`                          | Nonce for dynamic ticket generation     |

## Structs

### Subscription

```solidity
struct Subscription {
    uint64 remainingUSDC;           // USDC balance for remaining days
    uint64 lastExecutedDrawing;     // Last drawing tickets were purchased
    uint64 subscribedTicketPrice;   // Price locked at subscription time
    uint64 dynamicTicketCount;      // Random tickets per day
    address[] referrers;            // Referrer addresses
    uint256[] referralSplit;        // PRECISE_UNIT-scaled weights
}
```

### SubscriptionInfo

```solidity
struct SubscriptionInfo {
    Subscription subscription;       // Subscription details
    IJackpot.Ticket[] staticTickets; // User's static tickets for each day
}
```

## Enums

### ExecutionAction

```solidity
enum ExecutionAction {
    EXECUTE,                       // Execute tickets, subscription continues
    EXECUTE_AND_CLOSE,             // Final execution, subscription completed
    SKIP_ALREADY_EXECUTED,         // Already executed this drawing
    SKIP_NO_ACTIVE_SUBSCRIPTION,   // No active subscription
    SKIP_ACTIVE_BATCH_ORDER,       // Has active batch order, skip
    CANCEL_PRICE_CHANGE,           // Ticket price changed, auto-cancelled
    CANCEL_TOO_MANY_REFERRERS,     // Too many referrers, auto-cancelled
    CANCEL_USER_REQUESTED          // User requested cancellation
}
```

## Events

### SubscriptionCreated

```solidity
event SubscriptionCreated(
    address indexed payer,
    address indexed recipient,
    uint256 totalCost,
    uint256 totalDays,
    uint256 drawingStart,
    uint256 dynamicTicketCount,
    uint256 staticTicketCount,
    uint256 ticketPrice
);
```

### SubscriptionCancelled

```solidity
event SubscriptionCancelled(
    address indexed recipient,
    ExecutionAction indexed executionAction,
    uint64 refundAmount
);
```

### SubscriptionExecuted

```solidity
event SubscriptionExecuted(
    address indexed recipient,
    uint256 indexed drawingId,
    uint256[] ticketIds,
    uint256 dynamicTicketsPurchased,
    uint256 staticTicketsPurchased
);
```

### SubscriptionSkipped

```solidity
event SubscriptionSkipped(
    address indexed recipient,
    uint256 indexed drawingId,
    ExecutionAction indexed executionAction
);
```

## Functions

### createSubscription

Create an auto-subscription for consecutive daily ticket purchases.

```solidity
function createSubscription(
    address _recipient,
    uint64 _totalDays,
    uint64 _dynamicTicketCount,
    IJackpot.Ticket[] calldata _userStaticTickets,
    address[] calldata _referrers,
    uint256[] calldata _referralSplit
) external
```

**Parameters:**

| Name                  | Type        | Description                                |
| --------------------- | ----------- | ------------------------------------------ |
| `_recipient`          | `address`   | Address to receive ticket NFTs each day    |
| `_totalDays`          | `uint64`    | Number of days to run subscription         |
| `_dynamicTicketCount` | `uint64`    | Random tickets to purchase per day         |
| `_userStaticTickets`  | `Ticket[]`  | User-defined static tickets per day        |
| `_referrers`          | `address[]` | Referrer addresses for all purchases       |
| `_referralSplit`      | `uint256[]` | PRECISE\_UNIT-scaled weights (sum to 1e18) |

**Requirements:**

* Recipient must not have an active subscription
* `_totalDays` must be > 0
* Per-day ticket count (dynamic + static) must be > 0
* Static tickets must have valid numbers
* Caller must have approved sufficient USDC for all days

**Example:**

```solidity
// Subscribe for 30 days with 5 random tickets + 2 lucky numbers per day
uint64 days = 30;
uint64 dynamicPerDay = 5;

// My lucky numbers for each day
IJackpot.Ticket[] memory myTickets = new IJackpot.Ticket[](2);
myTickets[0] = IJackpot.Ticket({
    normals: [1, 7, 14, 21, 28],
    bonusball: 7
});
myTickets[1] = IJackpot.Ticket({
    normals: [5, 10, 15, 20, 25],
    bonusball: 5
});

// Calculate total cost: 30 days × 7 tickets × price
uint256 ticketPrice = jackpot.ticketPrice();
uint256 totalCost = days * (dynamicPerDay + myTickets.length) * ticketPrice;

// Approve and subscribe
usdc.approve(address(autoSubscription), totalCost);
autoSubscription.createSubscription(
    msg.sender,
    days,
    dynamicPerDay,
    myTickets,
    new address[](0),   // no referrers
    new uint256[](0)    // no splits
);
```

***

### cancelSubscription

Cancel your active subscription and receive a refund.

```solidity
function cancelSubscription() external
```

**Requirements:**

* Caller must have an active subscription

**Example:**

```solidity
// Cancel and get remaining USDC back
autoSubscription.cancelSubscription();
```

***

### getSubscriptionInfo

Get subscription details for a user.

```solidity
function getSubscriptionInfo(address _recipient) external view returns (SubscriptionInfo memory)
```

**Parameters:**

| Name         | Type      | Description      |
| ------------ | --------- | ---------------- |
| `_recipient` | `address` | Address to query |

**Returns:**

| Type               | Description                             |
| ------------------ | --------------------------------------- |
| `SubscriptionInfo` | Subscription details and static tickets |

**Example:**

```solidity
IJackpotAutoSubscription.SubscriptionInfo memory info =
    autoSubscription.getSubscriptionInfo(msg.sender);

uint64 remainingUSDC = info.subscription.remainingUSDC;
uint64 lastExecuted = info.subscription.lastExecutedDrawing;
uint64 ticketsPerDay = info.subscription.dynamicTicketCount +
                       uint64(info.staticTickets.length);

// Calculate remaining days
uint256 ticketPrice = info.subscription.subscribedTicketPrice;
uint256 remainingDays = remainingUSDC / (ticketsPerDay * ticketPrice);
```

***

### getSubscriptionsAction

Get recommended actions for a batch of subscriptions (for keepers).

```solidity
function getSubscriptionsAction(
    address[] calldata _subscriptions
) external view returns (ExecutionAction[] memory)
```

**Parameters:**

| Name             | Type        | Description           |
| ---------------- | ----------- | --------------------- |
| `_subscriptions` | `address[]` | Addresses to evaluate |

**Returns:**

| Type                | Description                         |
| ------------------- | ----------------------------------- |
| `ExecutionAction[]` | Recommended action for each address |

## Subscription Flow

1. **Create**: User approves USDC and calls `createSubscription`
2. **Daily Execution**: Keepers call `executeSubscriptions` each day
3. **Ticket Purchase**: Subscription buys tickets for current drawing
4. **Completion**: Subscription ends when USDC runs out or user cancels

### Price Protection

Subscriptions lock in the ticket price at creation time:

* If ticket price increases, subscription is auto-cancelled with refund
* This protects users from unexpected cost increases

### Cancellation Scenarios

Subscriptions are automatically cancelled when:

* Ticket price changes from subscribed price
* Too many referrers (exceeds max allowed)

### Integration with Batch Facilitator

Large subscriptions (>= minimum batch size) are routed through the BatchPurchaseFacilitator for efficient execution.
