# Hook Examples

This directory contains example hook implementations for the Django Wallet Utils hook system.

## Available Examples

### 1. **Daily Limit Hook** (`daily_limit.py`)

Prevents users from exceeding daily transaction limits.

```python
from decimal import Decimal
from wallet_utils.hooks import register_hook, HookType
from examples.hooks.daily_limit import check_daily_limit, record_daily_transaction

# Register PRE hook to check limit
register_hook(
    name="daily_limit_checker",
    hook_type=HookType.PRE,
    callback=check_daily_limit,
    operation="deduct",  # Apply to deductions
    priority=50,  # High priority
)

# Register POST hook to track successful transactions
register_hook(
    name="daily_limit_recorder",
    hook_type=HookType.POST,
    callback=record_daily_transaction,
    operation="deduct",
    priority=100,
)
```

**Features:**
- Configurable daily limits per user
- Tracks cumulative daily transactions
- Rejects transactions that exceed limit with detailed error
- Stores transaction history for tracking

### 2. **Fraud Detection Hook** (`fraud_detection.py`)

Identifies suspicious transaction patterns and flags or rejects them.

```python
from wallet_utils.hooks import register_hook, HookType
from examples.hooks.fraud_detection import (
    check_fraud_patterns,
    record_transaction_for_fraud_detection,
)

# Register PRE hook for fraud detection
register_hook(
    name="fraud_detector",
    hook_type=HookType.PRE,
    callback=check_fraud_patterns,
    operation="*",  # Check all operations
    priority=10,  # Highest priority
)

# Register POST hook to track patterns
register_hook(
    name="fraud_tracker",
    hook_type=HookType.POST,
    callback=record_transaction_for_fraud_detection,
    operation="*",
    priority=100,
)
```

**Detection Patterns:**
- Large amounts (>$10,000 by default)
- High transaction frequency
- Rapid-fire transactions (< 5 seconds apart)
- Suspicious amount patterns (e.g., $9,999.99)
- Unusual repetitive patterns

### 3. **Audit Logging Hook** (`audit_logger.py`)

Logs all wallet transactions for compliance and tracking.

```python
from wallet_utils.hooks import register_hook, HookType
from examples.hooks.audit_logger import log_transaction_to_audit

register_hook(
    name="audit_logger",
    hook_type=HookType.POST,
    callback=log_transaction_to_audit,
    operation="*",  # Log all operations
    priority=900,  # Low priority, run after other hooks
)
```

**Features:**
- Comprehensive transaction logging
- Captures all transaction details and metadata
- Separate logging for large transactions
- Query interface for audit trails

### 4. **Notification Hooks** (`notifications.py`)

Sends notifications to users after wallet transactions.

```python
from wallet_utils.hooks import register_hook, HookType
from examples.hooks.notifications import (
    send_transaction_notification,
    send_low_balance_alert,
    send_large_transaction_alert,
    send_transfer_recipient_notification,
)

# Basic transaction notification
register_hook(
    name="transaction_notifier",
    hook_type=HookType.POST,
    callback=send_transaction_notification,
    operation="*",
    priority=800,
)

# Low balance alerts (deductions only)
register_hook(
    name="low_balance_alerter",
    hook_type=HookType.POST,
    callback=send_low_balance_alert,
    operation="deduct",
    priority=750,
)

# Large transaction security alerts
register_hook(
    name="large_tx_alerter",
    hook_type=HookType.POST,
    callback=send_large_transaction_alert,
    operation="*",
    priority=750,
)

# Notify recipient of transfers
register_hook(
    name="transfer_recipient_notifier",
    hook_type=HookType.POST,
    callback=send_transfer_recipient_notification,
    operation="transfer",
    priority=800,
)
```

**Notification Types:**
- Transaction confirmations (email, SMS, push)
- Low balance alerts
- Large transaction security alerts
- Transfer recipient notifications
- Configurable channels based on amount

### 5. **Balance Alert Hook** (`balance_alert.py`)

Monitors balance thresholds and sends graduated alerts.

```python
from wallet_utils.hooks import register_hook, HookType
from examples.hooks.balance_alert import (
    check_low_balance,
    check_balance_milestone,
    configure_balance_thresholds,
)
from decimal import Decimal

# Configure thresholds
configure_balance_thresholds(
    critical=Decimal("10.00"),
    low=Decimal("100.00"),
    medium=Decimal("500.00"),
)

# Register balance monitoring hook
register_hook(
    name="balance_monitor",
    hook_type=HookType.POST,
    callback=check_low_balance,
    operation="*",
    priority=700,
)

# Optional: Celebrate milestones
register_hook(
    name="milestone_checker",
    hook_type=HookType.POST,
    callback=check_balance_milestone,
    operation="add",
    priority=700,
)
```

**Alert Levels:**
- **Critical**: Balance ≤ $10 (red alert)
- **Low**: Balance ≤ $100 (warning)
- **Medium**: Balance ≤ $500 (notice)
- **Milestones**: Celebrate positive thresholds ($1K, $5K, $10K, etc.)

## Complete Integration Example

Here's how to set up multiple hooks together:

```python
from wallet_utils import WalletService, WalletRepository
from wallet_utils.hooks import register_hook, HookType
from examples.hooks.daily_limit import check_daily_limit, record_daily_transaction
from examples.hooks.fraud_detection import check_fraud_patterns, record_transaction_for_fraud_detection
from examples.hooks.audit_logger import log_transaction_to_audit
from examples.hooks.notifications import send_transaction_notification
from examples.hooks.balance_alert import check_low_balance

# Create service with hooks enabled
repository = WalletRepository(user_model=User, point_types={"cash": 2})
service = WalletService(repository, enable_hooks=True)

# Register security hooks (highest priority)
register_hook("fraud_check", HookType.PRE, check_fraud_patterns, "*", priority=10)
register_hook("daily_limit", HookType.PRE, check_daily_limit, "deduct", priority=50)

# Register tracking hooks (POST)
register_hook("fraud_tracker", HookType.POST, record_transaction_for_fraud_detection, "*", priority=100)
register_hook("daily_tracker", HookType.POST, record_daily_transaction, "deduct", priority=100)

# Register notification hooks
register_hook("balance_monitor", HookType.POST, check_low_balance, "*", priority=700)
register_hook("notifier", HookType.POST, send_transaction_notification, "*", priority=800)

# Register audit hook (lowest priority, runs last)
register_hook("audit", HookType.POST, log_transaction_to_audit, "*", priority=900)

# Now all transactions go through the hook system
result = service.add_point(
    user_id=123,
    point_type="cash",
    amount=Decimal("100.00"),
    remarks="Test transaction"
)

if result.success:
    print(f"Transaction successful: {result.transaction_id}")
else:
    print(f"Transaction failed: {result.error_code} - {result.error_message}")
```

## Execution Order

Hooks execute in priority order (lower number = higher priority):

### PRE Hooks (Before Transaction)
1. **Priority 10**: Fraud detection (security)
2. **Priority 50**: Daily limit check (business rules)
3. **Priority 100**: Custom validation hooks

### Transaction Executes

### POST Hooks (After Transaction)
1. **Priority 100**: Fraud tracker, daily tracker (tracking)
2. **Priority 700**: Balance monitoring
3. **Priority 800**: Notifications
4. **Priority 900**: Audit logging

## Error Handling

### PRE Hook Rejection

```python
# Transaction rejected by hook
result = service.deduct_point(...)
if not result.success:
    print(f"Error: {result.error_code}")
    print(f"Message: {result.error_message}")
    print(f"Details: {result.error_details}")
```

### POST Hook Warnings

```python
# Transaction succeeded but POST hook failed
result = service.add_point(...)
if result.success and result.post_hook_errors:
    print(f"Transaction succeeded: {result.transaction_id}")
    for error in result.post_hook_errors:
        print(f"Warning - {error.hook_name}: {error.message}")
```

## Production Considerations

### 1. Storage
Replace in-memory storage with persistent storage:
- **Redis**: For rate limiting and temporary data
- **Database**: For audit trails and transaction history
- **Cache**: For frequently accessed data

### 2. Services
Integrate with real services:
- **Email**: SendGrid, AWS SES, Mailgun
- **SMS**: Twilio, Nexmo
- **Push**: Firebase Cloud Messaging, OneSignal
- **Monitoring**: Sentry, DataDog

### 3. Performance
- Use async operations for POST hooks when possible
- Cache frequently accessed data (limits, thresholds)
- Batch database writes where appropriate
- Monitor hook execution times

### 4. Security
- Validate all hook configurations
- Log security-critical events
- Implement rate limiting per user
- Review fraud detection patterns regularly

### 5. Testing
Test hooks in isolation and integration:
```python
from wallet_utils.hooks import clear_hooks

def test_daily_limit():
    clear_hooks()  # Clear between tests
    register_hook("test", HookType.PRE, check_daily_limit, "deduct")
    
    # Test within limit
    result = service.deduct_point(...)
    assert result.success
    
    # Test exceeding limit
    result = service.deduct_point(...)
    assert not result.success
    assert result.error_code == "DAILY_LIMIT_EXCEEDED"
```

## Custom Hooks

Create your own hooks following this pattern:

```python
from wallet_utils.hooks import HookContext
from wallet_utils.exceptions import HookRejectionError

def my_custom_pre_hook(context: HookContext) -> bool:
    """
    PRE hook example.
    
    Returns:
        True to allow transaction
        False to reject (generic rejection)
        
    Raises:
        HookRejectionError: For detailed rejection with error code
    """
    # Your validation logic here
    if not is_valid(context):
        raise HookRejectionError(
            error_code="MY_ERROR_CODE",
            message="Human readable message",
            details={"extra": "context"}
        )
    
    # Store data for other hooks
    context.metadata["my_data"] = "value"
    
    return True


def my_custom_post_hook(context: HookContext) -> None:
    """
    POST hook example.
    
    Cannot reject transaction. Exceptions are captured as warnings.
    """
    transaction_id = context.metadata.get("transaction_id")
    
    # Your side-effect logic here
    # (logging, notifications, external API calls, etc.)
    
    # Access data from PRE hooks
    pre_data = context.metadata.get("my_data")
```

## Documentation

- **Design Document**: `docs/hook-system-design.md`
- **Guidelines**: `docs/hook-system-guidelines.md`
- **Usage**: `docs/usage.md`
- **Tests**: `tests/test_hooks.py`, `tests/test_hooks_integration.py`

## Support

For questions or issues, refer to the main documentation or create an issue in the repository.
