# Rich Media Notification System

Flexible media support for notification channels using a driver-based architecture with atomic capability interfaces.

## Overview

The Rich Media system provides optional media support for notification channels, allowing each channel to implement only the capabilities it supports (photos, videos, audio, documents, location sharing).

## Architecture

```
┌─────────────────┐    ┌─────────────────┐    ┌─────────────────┐
│  MediaManager   │───▶│  MediaDriver    │───▶│ TelegramClient  │
│  (Coordinator)  │    │  (Telegram)     │    │  (Bot API)      │
└─────────────────┘    └─────────────────┘    └─────────────────┘
         │                      │
    Capability              Atomic
    Detection           Interfaces
```

### Key Components

1. **MediaManager** - Central coordinator for media operations
   - Driver registration per channel
   - Capability detection using `instanceof`
   - Unified API for sending media
   - Runtime validation

2. **MediaDriver** (Marker Interface) - Minimal interface for drivers
   ```php
   interface MediaDriver
   {
       public function getName(): string;
   }
   ```

3. **Atomic Capability Interfaces** - Small, focused interfaces
   - `SupportsPhotoAttachments`
   - `SupportsVideoAttachments`
   - `SupportsAudioAttachments`
   - `SupportsDocumentAttachments`
   - `SupportsLocationSharing`

4. **MediaCapabilities** - Value object describing driver capabilities
   ```php
   final readonly class MediaCapabilities
   {
       public bool $supportsPhoto;
       public bool $supportsVideo;
       // ...
   }
   ```

## Usage

### 1. Accessing MediaManager

MediaManager is available as a public property on notification channels:

```php
$telegramChannel = $container->get(TelegramChannel::class);
$mediaManager = $telegramChannel->mediaManager;
```

### 2. Checking Capabilities

Always check capabilities before sending media:

```php
// Check specific capability
if ($mediaManager->supportsPhoto(NotificationChannel::TELEGRAM)) {
    // Send photo
}

// Get all capabilities
$capabilities = $mediaManager->getCapabilities(NotificationChannel::TELEGRAM);

if ($capabilities->supportsPhoto) {
    // Photo supported
}

if ($capabilities->hasAnyMediaSupport()) {
    // Channel supports some form of media
}
```

### 3. Sending Media

#### Send Photo

```php
$notification = new Notification(
    userId: 'user_123',
    title: 'Photo Notification',
    body: 'Check out this image',
    channel: NotificationChannel::TELEGRAM,
    type: 'photo'
);

$mediaManager->sendPhoto(
    NotificationChannel::TELEGRAM,
    $notification,
    photoPath: '/path/to/image.jpg',  // or file_id or URL
    caption: 'Beautiful landscape'
);
```

#### Send Video

```php
$mediaManager->sendVideo(
    NotificationChannel::TELEGRAM,
    $notification,
    videoPath: '/path/to/video.mp4',
    caption: 'Tutorial video',
    thumbnailPath: '/path/to/thumbnail.jpg'
);
```

#### Send Audio

```php
$mediaManager->sendAudio(
    NotificationChannel::TELEGRAM,
    $notification,
    audioPath: '/path/to/audio.mp3',
    caption: 'Podcast episode',
    duration: 300  // 5 minutes in seconds
);
```

#### Send Document

```php
$mediaManager->sendDocument(
    NotificationChannel::TELEGRAM,
    $notification,
    documentPath: '/path/to/document.pdf',
    caption: 'Monthly report',
    filename: 'Report_2024.pdf'
);
```

#### Send Location

```php
$mediaManager->sendLocation(
    NotificationChannel::TELEGRAM,
    $notification,
    latitude: 52.5200,   // Berlin
    longitude: 13.4050,
    title: 'Meeting Point',
    address: 'Brandenburger Tor, Berlin'
);
```

### 4. Graceful Fallback Pattern

Always provide fallback for unsupported media:

```php
try {
    if ($mediaManager->supportsPhoto($channel)) {
        $mediaManager->sendPhoto($channel, $notification, $photoPath, $caption);
    } else {
        // Fallback to text-only notification
        $channel->send($notification);
    }
} catch (\Exception $e) {
    // Log error and fallback
    error_log("Media sending failed: {$e->getMessage()}");
    $channel->send($notification);
}
```

## Creating a Custom Media Driver

To add media support for a new channel:

### 1. Create Driver Class

```php
final readonly class EmailMediaDriver implements
    MediaDriver,
    SupportsPhotoAttachments,
    SupportsDocumentAttachments
{
    public function __construct(
        private EmailClient $client
    ) {}

    public function getName(): string
    {
        return 'email';
    }

    public function sendWithPhoto(
        Notification $notification,
        string $photoPath,
        ?string $caption = null
    ): void {
        // Implement photo as email attachment
        $this->client->sendWithAttachment(
            to: $notification->getUserEmail(),
            subject: $notification->getTitle(),
            body: $caption ?? $notification->getBody(),
            attachments: [$photoPath]
        );
    }

    public function sendWithDocument(
        Notification $notification,
        string $documentPath,
        ?string $caption = null,
        ?string $filename = null
    ): void {
        // Implement document as email attachment
        $this->client->sendWithAttachment(
            to: $notification->getUserEmail(),
            subject: $notification->getTitle(),
            body: $caption ?? $notification->getBody(),
            attachments: [$documentPath],
            filename: $filename
        );
    }
}
```

### 2. Register Driver

```php
// In EmailNotificationInitializer
$mediaManager = new MediaManager();

$emailDriver = new EmailMediaDriver(
    client: $c->get(EmailClient::class)
);

$mediaManager->registerDriver(
    NotificationChannel::EMAIL,
    $emailDriver
);

$container->singleton(MediaManager::class, $mediaManager);
```

### 3. Add to Channel

```php
final readonly class EmailChannel implements NotificationChannelInterface
{
    public function __construct(
        private EmailClient $client,
        public MediaManager $mediaManager
    ) {}

    public function send(Notification $notification): bool
    {
        // Text-only implementation
    }
}
```

## Atomic Capability Interfaces

Each interface defines a single media capability:

### SupportsPhotoAttachments

```php
interface SupportsPhotoAttachments
{
    public function sendWithPhoto(
        Notification $notification,
        string $photoPath,
        ?string $caption = null
    ): void;
}
```

### SupportsVideoAttachments

```php
interface SupportsVideoAttachments
{
    public function sendWithVideo(
        Notification $notification,
        string $videoPath,
        ?string $caption = null,
        ?string $thumbnailPath = null
    ): void;
}
```

### SupportsAudioAttachments

```php
interface SupportsAudioAttachments
{
    public function sendWithAudio(
        Notification $notification,
        string $audioPath,
        ?string $caption = null,
        ?int $duration = null
    ): void;
}
```

### SupportsDocumentAttachments

```php
interface SupportsDocumentAttachments
{
    public function sendWithDocument(
        Notification $notification,
        string $documentPath,
        ?string $caption = null,
        ?string $filename = null
    ): void;
}
```

### SupportsLocationSharing

```php
interface SupportsLocationSharing
{
    public function sendWithLocation(
        Notification $notification,
        float $latitude,
        float $longitude,
        ?string $title = null,
        ?string $address = null
    ): void;
}
```

## MediaCapabilities Factory Methods

Convenient factory methods for common capability sets:

```php
// All capabilities enabled
MediaCapabilities::all()

// No capabilities (text-only)
MediaCapabilities::none()

// Typical messaging app capabilities
MediaCapabilities::messaging()
// -> photo, video, audio, document, location, voice

// Email-like capabilities
MediaCapabilities::email()
// -> photo, document
```

## Error Handling

### Runtime Validation

MediaManager validates capabilities at runtime:

```php
// Throws RuntimeException if channel doesn't support photos
$mediaManager->sendPhoto(
    NotificationChannel::EMAIL,  // Doesn't support photos
    $notification,
    $photoPath
);
// RuntimeException: "Channel email does not support photo attachments"
```

### Best Practices

1. **Check before sending**
   ```php
   if (!$mediaManager->supportsPhoto($channel)) {
       throw new UnsupportedMediaException('Photo not supported');
   }
   ```

2. **Try-catch with fallback**
   ```php
   try {
       $mediaManager->sendPhoto($channel, $notification, $photoPath);
   } catch (\Exception $e) {
       $channel->send($notification);  // Text fallback
   }
   ```

3. **Capability-based logic**
   ```php
   $capabilities = $mediaManager->getCapabilities($channel);

   if ($capabilities->supportsPhoto && $hasPhoto) {
       $mediaManager->sendPhoto($channel, $notification, $photoPath);
   } elseif ($capabilities->supportsDocument && $hasDocument) {
       $mediaManager->sendDocument($channel, $notification, $documentPath);
   } else {
       $channel->send($notification);
   }
   ```

## Examples

See practical examples:

1. **Capability Demonstration**: `examples/notification-rich-media-example.php`
   - Shows all atomic interfaces
   - Runtime capability checking
   - Error handling patterns

2. **Practical Sending**: `examples/send-telegram-media-example.php`
   - Actual media sending via Telegram
   - Graceful fallback patterns
   - Multi-media notifications

Run examples:
```bash
# Capability demonstration
php examples/notification-rich-media-example.php

# Practical sending
php examples/send-telegram-media-example.php
```

## Framework Compliance

The Rich Media system follows all framework principles:

- ✅ **Readonly Classes**: All VOs and drivers are `final readonly`
- ✅ **Composition Over Inheritance**: Atomic interfaces instead of inheritance
- ✅ **Marker Interface**: MediaDriver is minimal, capabilities via additional interfaces
- ✅ **Value Objects**: MediaCapabilities as immutable VO
- ✅ **Dependency Injection**: All components registered in container
- ✅ **Runtime Capability Detection**: Uses `instanceof` instead of static configuration

## Channel Support Matrix

| Channel  | Photo | Video | Audio | Document | Location |
|----------|-------|-------|-------|----------|----------|
| Telegram | ✅    | ✅    | ✅    | ✅       | ✅       |
| Email    | ❌    | ❌    | ❌    | ❌       | ❌       |
| SMS      | ❌    | ❌    | ❌    | ❌       | ❌       |

To add support for email/SMS, create corresponding MediaDriver implementations.

## Performance Considerations

- **Capability Checks**: `instanceof` checks are fast (~0.001ms)
- **Driver Registration**: One-time cost during bootstrap
- **Media Sending**: Performance depends on underlying API (Telegram, etc.)
- **No Overhead**: Zero overhead for text-only notifications

## Future Enhancements

Potential additions:

1. **Voice Message Support**: `SupportsVoiceMessages` interface
2. **Sticker Support**: `SupportsStickers` interface for messaging apps
3. **Poll Support**: `SupportsPollCreation` interface
4. **Media Streaming**: `SupportsMediaStreaming` for large files
5. **Media Transcoding**: Automatic format conversion based on channel requirements

## Testing

Unit tests for MediaManager and drivers:

```php
it('detects photo capability via instanceof', function () {
    $driver = new TelegramMediaDriver($client, $resolver);

    expect($driver)->toBeInstanceOf(SupportsPhotoAttachments::class);
});

it('throws when sending unsupported media', function () {
    $mediaManager->sendPhoto(
        NotificationChannel::EMAIL,  // No driver registered
        $notification,
        '/path/to/photo.jpg'
    );
})->throws(\RuntimeException::class);
```

## Summary

The Rich Media system provides:

- ✅ **Flexible Architecture**: Each channel can support different media types
- ✅ **Type Safety**: Interface-based with runtime validation
- ✅ **Easy Extension**: Add new channels and capabilities easily
- ✅ **Graceful Degradation**: Fallback to text when media unsupported
- ✅ **Unified API**: Same methods across all channels
- ✅ **Framework Compliance**: Follows all framework patterns

For questions or issues, see the main notification system documentation.
