# Notification System

Multi-channel notification system with support for email, database, push, SMS, and webhooks.

## Features

- **Multi-Channel Delivery**: Email, Database (in-app), Push, SMS, Webhook
- **Queue Integration**: Async delivery via framework Queue system
- **Event System**: NotificationSent and NotificationFailed events
- **Priority Levels**: LOW, NORMAL, HIGH, URGENT
- **Read Tracking**: Mark notifications as read, count unread
- **Action Buttons**: Optional action URL and label
- **Type Safety**: Fully typed with Value Objects and Enums
- **Framework Integration**: Uses existing Mail, Queue, EventBus, Database modules

## Basic Usage

### Creating and Sending a Notification

```php
use App\Framework\Notification\Notification;
use App\Framework\Notification\NotificationDispatcher;
use App\Framework\Notification\ValueObjects\NotificationChannel;
use App\Framework\Notification\ValueObjects\NotificationPriority;
use App\Framework\Notification\ValueObjects\NotificationType;

// Create notification
$notification = Notification::create(
    recipientId: 'user-123',
    type: NotificationType::system(),
    title: 'System Update',
    body: 'Your system has been updated to version 2.0',
    NotificationChannel::DATABASE,
    NotificationChannel::EMAIL
);

// Add optional features
$notification = $notification
    ->withPriority(NotificationPriority::HIGH)
    ->withAction('/changelog', 'View Changelog')
    ->withData([
        'version' => '2.0.0',
        'features' => ['performance', 'security']
    ]);

// Send asynchronously (via Queue)
$dispatcher->sendLater($notification);

// Or send immediately
$result = $dispatcher->sendNow($notification);
```

### Common Notification Types

```php
// System notifications
NotificationType::system()

// Security alerts
NotificationType::security()

// Marketing messages
NotificationType::marketing()

// Social interactions
NotificationType::social()

// Transactional emails
NotificationType::transactional()

// Custom types
NotificationType::fromString('order-status')
```

### Retrieving Notifications

```php
use App\Framework\Notification\Storage\NotificationRepository;

// Get user's notifications
$notifications = $repository->findByUser('user-123', limit: 20);

// Get unread notifications
$unread = $repository->findUnreadByUser('user-123');

// Count unread
$count = $repository->countUnreadByUser('user-123');

// Mark as read
$repository->markAsRead($notificationId);

// Mark all as read
$repository->markAllAsReadForUser('user-123');
```

## Channels

### Database Channel (In-App Notifications)

Stores notifications in database for user inbox/notification center.

```php
NotificationChannel::DATABASE
```

**Features**:
- Persistent storage
- Read/unread tracking
- Pagination support
- Automatic cleanup of old notifications

### Email Channel

Sends notifications via email using framework's Mail module.

```php
NotificationChannel::EMAIL
```

**Features**:
- HTML and plain text emails
- Priority mapping
- Action buttons in email
- Automatic HTML formatting

**Requirements**:
- UserEmailResolver implementation to map user IDs to email addresses

```php
class DatabaseUserEmailResolver implements UserEmailResolver
{
    public function resolveEmail(string $userId): ?Email
    {
        // Lookup user email from database
        return $this->userRepository->findEmailById($userId);
    }
}
```

### Push Channel (Placeholder)

For web push and mobile push notifications.

```php
NotificationChannel::PUSH
```

**Status**: Interface defined, implementation needed.

### SMS Channel (Placeholder)

For SMS notifications via external provider.

```php
NotificationChannel::SMS
```

**Status**: Interface defined, implementation needed.

### Webhook Channel (Placeholder)

For sending notifications to external systems via HTTP webhooks.

```php
NotificationChannel::WEBHOOK
```

**Status**: Interface defined, implementation needed.

## Queue Integration

The notification system integrates seamlessly with the framework's Queue system for asynchronous delivery.

### Async Delivery

```php
// Queue for background processing
$dispatcher->sendLater($notification);

// Priority is mapped from notification priority:
// URGENT → HIGH
// HIGH → MEDIUM
// NORMAL → LOW
// LOW → LOW
```

### Immediate Delivery

```php
// Send immediately (blocks until complete)
$result = $dispatcher->sendNow($notification);

if ($result->isSuccess()) {
    echo "Sent via: " . count($result->getSuccessful()) . " channels\n";
} else {
    echo "Errors: " . implode(', ', $result->getErrors()) . "\n";
}
```

## Event System

The notification system dispatches events via the framework's EventBus.

### NotificationSent Event

Dispatched when a notification is successfully sent via at least one channel.

```php
use App\Framework\Notification\Events\NotificationSent;
use App\Framework\EventBus\Attributes\EventHandler;

#[EventHandler]
final class NotificationLogger
{
    public function handleNotificationSent(NotificationSent $event): void
    {
        $this->logger->info('Notification sent', [
            'notification_id' => $event->notification->id->toString(),
            'recipient' => $event->notification->recipientId,
            'channels' => count($event->result->getSuccessful())
        ]);
    }
}
```

### NotificationFailed Event

Dispatched when a notification fails on all channels.

```php
use App\Framework\Notification\Events\NotificationFailed;
use App\Framework\EventBus\Attributes\EventHandler;

#[EventHandler]
final class NotificationFailureHandler
{
    public function handleNotificationFailure(NotificationFailed $event): void
    {
        $this->alerting->sendAlert(
            'Notification delivery failed',
            $event->result->getErrors()
        );
    }
}
```

## Database Schema

The notifications table is created via migration:

```php
src/Framework/Notification/Migrations/CreateNotificationsTable.php
```

**Table Structure**:
- `id` (ULID) - Primary key
- `recipient_id` - User/entity receiving notification
- `type` - Notification category
- `title` - Notification title
- `body` - Notification message
- `data` - JSON structured data
- `channels` - JSON array of delivery channels
- `priority` - Delivery priority
- `status` - Current status (pending, sent, delivered, failed, read, archived)
- `created_at` - Creation timestamp
- `sent_at` - Delivery timestamp
- `read_at` - Read timestamp
- `action_url` - Optional action URL
- `action_label` - Optional action button label

**Indexes**:
- `recipient_id` + `status` + `created_at` (composite)
- `recipient_id` + `type` (composite)
- `read_at` (for unread queries)

## Configuration

### Setting Up Channels

```php
// In your Initializer
use App\Framework\Notification\Channels\DatabaseChannel;
use App\Framework\Notification\Channels\EmailChannel;
use App\Framework\Notification\NotificationDispatcher;

$container->singleton(NotificationDispatcher::class, function($c) {
    return new NotificationDispatcher(
        channels: [
            $c->get(DatabaseChannel::class),
            $c->get(EmailChannel::class),
            // Add more channels as needed
        ],
        queue: $c->get(Queue::class),
        eventBus: $c->get(EventBus::class)
    );
});
```

### Email Channel Setup

```php
$container->singleton(EmailChannel::class, function($c) {
    return new EmailChannel(
        mailer: $c->get(MailerInterface::class),
        fromAddress: new Email('notifications@example.com'),
        userEmailResolver: $c->get(UserEmailResolver::class)
    );
});
```

## Best Practices

1. **Use Async Delivery**: Always prefer `sendLater()` for better performance
2. **Set Appropriate Priority**: Reserve URGENT for critical notifications
3. **Include Actions**: Add action URLs when user interaction is expected
4. **Structured Data**: Use `withData()` for additional context
5. **Type Classification**: Use proper NotificationType for filtering
6. **Cleanup Old Notifications**: Periodically delete old read/archived notifications

## Examples

### Welcome Notification

```php
$notification = Notification::create(
    recipientId: $user->id,
    type: NotificationType::system(),
    title: 'Welcome to Our Platform!',
    body: 'Thank you for signing up. Get started by completing your profile.',
    NotificationChannel::DATABASE,
    NotificationChannel::EMAIL
)->withAction('/profile/complete', 'Complete Profile');

$dispatcher->sendLater($notification);
```

### Security Alert

```php
$notification = Notification::create(
    recipientId: $user->id,
    type: NotificationType::security(),
    title: 'New Login Detected',
    body: "We detected a login from {$location} at {$time}",
    NotificationChannel::DATABASE,
    NotificationChannel::EMAIL
)
->withPriority(NotificationPriority::HIGH)
->withData([
    'ip_address' => $ipAddress,
    'location' => $location,
    'device' => $device
]);

$dispatcher->sendNow($notification); // Immediate for security
```

### Order Confirmation

```php
$notification = Notification::create(
    recipientId: $order->userId,
    type: NotificationType::transactional(),
    title: 'Order Confirmed',
    body: "Your order #{$order->number} has been confirmed",
    NotificationChannel::EMAIL
)
->withData([
    'order_id' => $order->id,
    'total' => $order->total->toDecimal(),
    'items' => count($order->items)
])
->withAction("/orders/{$order->id}", 'View Order');

$dispatcher->sendLater($notification);
```

## Testing

Run tests with:

```bash
./vendor/bin/pest tests/Feature/NotificationSystemTest.php
```

## Extending the System

### Adding a New Channel

1. Implement `NotificationChannelInterface`
2. Add channel to `NotificationChannel` enum
3. Register channel in dispatcher initialization
4. Implement `send()` method with delivery logic

```php
final readonly class SmsChannel implements NotificationChannelInterface
{
    public function __construct(
        private SmsProvider $provider
    ) {}

    public function send(Notification $notification): ChannelResult
    {
        // Implementation
    }

    public function supports(Notification $notification): bool
    {
        return $notification->supportsChannel(NotificationChannel::SMS);
    }

    public function getChannel(): NotificationChannel
    {
        return NotificationChannel::SMS;
    }
}
```

## Architecture

The notification system follows framework principles:

- ✅ **Readonly Value Objects**: Notification, NotificationId, etc.
- ✅ **Final Classes**: All implementation classes are final
- ✅ **Composition over Inheritance**: Channel interface composition
- ✅ **Event-Driven**: Integration with EventBus
- ✅ **Queue Integration**: Async delivery via Queue system
- ✅ **Module Reuse**: Leverages Mail, Queue, EventBus, Database modules

## Future Enhancements

- [ ] User preference management for notification types
- [ ] Notification templates with variables
- [ ] Push notification implementation (Web Push API)
- [ ] SMS channel implementation
- [ ] Webhook channel implementation
- [ ] Notification batching/digest mode
- [ ] Quiet hours / Do Not Disturb
- [ ] A/B testing for notification content
- [ ] Analytics tracking
