# ConverseDriver Setup for Separate BotMan Application

## Overview

This guide explains how to set up and use the `ConverseDriver` in a **separate BotMan application** that communicates with your main WhatsApp chat application via HTTP API.

## Architecture

```
WhatsApp Message
    ↓
Main App (Webhook Handler)
    ↓
Forward to BotMan App → ConverseDriver
    ↓
Bot Logic Processing
    ↓
ConverseDriver → HTTP API Call
    ↓
Main App (API Endpoint)
    ↓
WhatsappService → Facebook Graph API
    ↓
WhatsApp User
```

## Installation Steps

### 1. Create/Setup Your BotMan Application

```bash
# Create a new Laravel app for BotMan
composer create-project laravel/laravel botman-app
cd botman-app

# Install BotMan
composer require botman/botman
composer require botman/driver-web
```

### 2. Copy the ConverseDriver

Copy the `ConverseDriver.php` file to your BotMan application:

```bash
mkdir -p app/Drivers/WhatsApp
# Copy app/Drivers/ConverseDriver.php to your BotMan app
cp /path/to/main-app/app/Drivers/ConverseDriver.php app/Drivers/WhatsApp/
```

### 3. Configure BotMan

Create `config/botman/converse.php`:

```php
<?php

return [
    'converse' => [
        // Main app API URL (where WhatsappService is running)
        'url' => env('CONVERSE_API_URL', 'https://your-main-app.com'),
        
        // API Bearer token for authentication
        'token' => env('CONVERSE_API_TOKEN', 'your-api-token'),
        
        // Enable/disable driver
        'enabled' => env('CONVERSE_ENABLED', true),
    ],
];
```

### 4. Environment Variables

Add to your `.env` file:

```env
# Main App API Configuration
CONVERSE_API_URL=https://your-main-app.com
CONVERSE_API_TOKEN=your-bearer-token-here
CONVERSE_ENABLED=true

# Redis for duplicate detection
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
```

### 5. Register the Driver

In `app/Providers/AppServiceProvider.php`:

```php
<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use BotMan\BotMan\Drivers\DriverManager;
use App\Drivers\WhatsApp\ConverseDriver;

class AppServiceProvider extends ServiceProvider
{
    public function boot()
    {
        // Load the Converse driver
        DriverManager::loadDriver(ConverseDriver::class);
    }

    public function register()
    {
        //
    }
}
```

### 6. Create BotMan Controller

Create `app/Http/Controllers/BotManController.php`:

```php
<?php

namespace App\Http\Controllers;

use BotMan\BotMan\BotMan;
use BotMan\BotMan\Messages\Incoming\Answer;
use BotMan\BotMan\Messages\Outgoing\Question;
use BotMan\BotMan\Messages\Outgoing\Actions\Button;
use Illuminate\Http\Request;

class BotManController extends Controller
{
    /**
     * Handle incoming webhook from main app
     */
    public function handle()
    {
        $botman = app('botman');

        // Define your bot conversations
        $this->setupConversations($botman);

        // Listen for incoming messages
        $botman->listen();
    }

    /**
     * Setup bot conversations
     */
    protected function setupConversations(BotMan $botman)
    {
        // Welcome message
        $botman->hears('hi|hello|hey|start', function (BotMan $bot) {
            $bot->reply('👋 Hello! Welcome to our chatbot. How can I help you today?');
            
            $question = Question::create('What would you like to do?')
                ->addButton(Button::create('View Products')->value('products'))
                ->addButton(Button::create('Check Order')->value('orders'))
                ->addButton(Button::create('Get Support')->value('support'));
            
            $bot->ask($question, function (Answer $answer) use ($bot) {
                if ($answer->isInteractiveMessageReply()) {
                    $value = $answer->getValue();
                    $this->handleMenuSelection($bot, $value);
                }
            });
        });

        // Products
        $botman->hears('products', function (BotMan $bot) {
            $question = Question::create('Select a category:')
                ->addButton(Button::create('Electronics')->value('electronics'))
                ->addButton(Button::create('Clothing')->value('clothing'))
                ->addButton(Button::create('Home & Garden')->value('home'))
                ->addButton(Button::create('Sports')->value('sports'))
                ->addButton(Button::create('Books')->value('books'));
            
            $bot->ask($question, function (Answer $answer) use ($bot) {
                if ($answer->isInteractiveMessageReply()) {
                    $category = $answer->getValue();
                    $bot->reply("You selected: $category\n\nHere are our top products in this category...");
                }
            });
        });

        // Orders
        $botman->hears('orders|order|my order', function (BotMan $bot) {
            $bot->reply('Please provide your order number:');
            
            $bot->ask(function(Answer $answer) use ($bot) {
                $orderNumber = $answer->getText();
                $bot->reply("Looking up order: $orderNumber...");
                // Add your order lookup logic here
            });
        });

        // Support
        $botman->hears('support|help|assistance', function (BotMan $bot) {
            $question = Question::create('What do you need help with?')
                ->addButton(Button::create('Technical Issue')->value('technical'))
                ->addButton(Button::create('Billing')->value('billing'))
                ->addButton(Button::create('Returns')->value('returns'))
                ->addButton(Button::create('Talk to Human')->value('human'));
            
            $bot->ask($question, function (Answer $answer) use ($bot) {
                if ($answer->isInteractiveMessageReply()) {
                    $value = $answer->getValue();
                    
                    if ($value === 'human') {
                        $bot->reply('Connecting you to a human agent. Please wait...');
                        // Add logic to notify support team
                    } else {
                        $bot->reply("I'll help you with $value. Please describe your issue:");
                    }
                }
            });
        });

        // Fallback for unrecognized messages
        $botman->fallback(function (BotMan $bot) {
            $bot->reply("I didn't understand that. Type 'help' to see available options.");
        });
    }

    /**
     * Handle menu selections
     */
    protected function handleMenuSelection(BotMan $bot, $selection)
    {
        switch ($selection) {
            case 'products':
                $bot->reply('products');
                break;
            case 'orders':
                $bot->reply('orders');
                break;
            case 'support':
                $bot->reply('support');
                break;
            default:
                $bot->reply('Invalid selection');
        }
    }
}
```

### 7. Setup Routes

In `routes/web.php` or `routes/api.php`:

```php
<?php

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\BotManController;

// Webhook endpoint for receiving messages from main app
Route::match(['get', 'post'], '/botman/webhook', [BotManController::class, 'handle']);
```

## Main App Configuration

### 1. Create API Endpoints

In your main app, create these endpoints (if they don't exist):

```php
// routes/api.php

use App\Http\Controllers\ApiController;

Route::middleware([AuthenticateBearerToken::class])->group(function () {
    // These endpoints should already exist
    Route::post('/send', [ApiController::class, 'sendMessage']);
    Route::post('/send/media', [ApiController::class, 'sendMediaMessage']);
    Route::get('/getMedia/{mediaId}', [ApiController::class, 'getMedia']);
});
```

### 2. Add getMedia Endpoint (if not exists)

Add this to your `ApiController.php`:

```php
/**
 * Get media URL from media ID
 */
public function getMedia(Request $request, $mediaId)
{
    if(!SubscriptionService::isSubscriptionActive($request->organization)){
        return response()->json([
            'statusCode' => 403,
            'message' => __('Please renew or subscribe to a plan to continue!'),
        ], 403);
    }

    if(!$this->isWhatsAppConnected($request->organization)){
        return response()->json([
            'statusCode' => 403,
            'message' => __('Please setup your whatsapp account!'),
        ], 403);
    }

    $this->initializeWhatsappService($request->organization);
    $response = $this->whatsappService->getMedia($mediaId);

    if($response->success){
        return response()->json([
            'statusCode' => 200,
            'url' => $response->data->url
        ], 200);
    }

    return response()->json([
        'statusCode' => 500,
        'message' => __('Failed to retrieve media')
    ], 500);
}
```

### 3. Forward Webhooks to BotMan App

In your main app's `WebhookController.php`, forward messages to your BotMan app:

```php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;

class WebhookController extends Controller
{
    public function handle(Request $request, $identifier = null)
    {
        // Verify webhook (for GET requests)
        if ($request->isMethod('GET')) {
            $mode = $request->query('hub_mode');
            $token = $request->query('hub_verify_token');
            $challenge = $request->query('hub_challenge');

            if ($mode === 'subscribe' && $token === config('services.whatsapp.verify_token')) {
                return response($challenge, 200)->header('Content-Type', 'text/plain');
            }
            
            return response('Forbidden', 403);
        }

        // Handle POST webhook
        $payload = $request->all();
        
        // Extract organization ID from identifier or payload
        $organizationId = $this->getOrganizationId($identifier);
        
        // Add organization ID to payload for BotMan
        $payload['organization_id'] = $organizationId;
        
        // Forward to BotMan app
        $botmanUrl = config('services.botman.url');
        if ($botmanUrl) {
            try {
                Http::timeout(10)->post($botmanUrl . '/botman/webhook', $payload);
            } catch (\Exception $e) {
                Log::error('Failed to forward to BotMan: ' . $e->getMessage());
            }
        }

        // Continue with regular webhook processing
        // ... your existing webhook logic ...

        return response('OK', 200);
    }

    protected function getOrganizationId($identifier)
    {
        // Your logic to get organization ID from identifier
        // For example:
        // return Organization::where('identifier', $identifier)->value('id');
        return 1; // Replace with actual logic
    }
}
```

### 4. Add BotMan Config to Main App

In your main app's `config/services.php`:

```php
'botman' => [
    'url' => env('BOTMAN_URL', 'https://your-botman-app.com'),
],
```

And in `.env`:

```env
BOTMAN_URL=https://your-botman-app.com
```

## Testing

### 1. Test the Connection

```bash
# In your BotMan app, run:
php artisan serve

# Test the webhook endpoint:
curl -X POST http://localhost:8000/botman/webhook \
  -H "Content-Type: application/json" \
  -d '{
    "event": "message.received",
    "organization_id": 1,
    "data": {
      "value": {
        "messaging_product": "whatsapp",
        "metadata": {
          "display_phone_number": "1234567890",
          "phone_number_id": "123456789"
        },
        "contacts": [
          {
            "profile": {"name": "Test User"},
            "wa_id": "1234567890"
          }
        ],
        "messages": [
          {
            "from": "1234567890",
            "id": "wamid.test123",
            "timestamp": "1234567890",
            "type": "text",
            "text": {"body": "hello"}
          }
        ]
      }
    }
  }'
```

### 2. Test Message Sending

Make sure your main app API endpoints are accessible from the BotMan app:

```bash
# Test from BotMan app server
curl -X POST https://your-main-app.com/api/send \
  -H "Authorization: Bearer your-api-token" \
  -H "Content-Type: application/json" \
  -d '{
    "phone": "+1234567890",
    "message": "Test message from BotMan"
  }'
```

## Deployment

### Production Checklist

- [ ] Set proper API URLs in environment variables
- [ ] Use secure API tokens (store in secrets management)
- [ ] Configure HTTPS for both apps
- [ ] Set up proper logging and monitoring
- [ ] Configure Redis for production use
- [ ] Set up rate limiting on webhook endpoints
- [ ] Implement proper error handling and retries
- [ ] Test all message types (text, media, buttons, lists)
- [ ] Set up backup/failover for critical paths
- [ ] Monitor API response times

### Scaling Considerations

1. **Load Balancing**: Use a load balancer for the BotMan app
2. **Caching**: Implement Redis caching for frequently accessed data
3. **Queue**: Use Laravel queues for processing heavy operations
4. **CDN**: Serve media files through a CDN
5. **Database**: Consider read replicas if needed

## Troubleshooting

### Messages Not Being Forwarded

1. Check main app webhook is receiving messages
2. Verify BotMan URL is correct in main app config
3. Check network connectivity between apps
4. Review logs in both applications

### Messages Not Being Sent

1. Verify API token is correct
2. Check API endpoints are accessible
3. Verify phone numbers are in correct format
4. Check WhatsApp configuration in main app
5. Review API response errors

### Duplicate Messages

1. Verify Redis is working properly
2. Check Redis connection in BotMan app
3. Ensure message IDs are unique

## Example Payload Structure

### Incoming Message (Text)

```json
{
  "event": "message.received",
  "organization_id": 1,
  "data": {
    "value": {
      "messaging_product": "whatsapp",
      "metadata": {
        "display_phone_number": "1234567890",
        "phone_number_id": "123456789"
      },
      "contacts": [
        {
          "profile": {
            "name": "John Doe"
          },
          "wa_id": "1234567890"
        }
      ],
      "messages": [
        {
          "from": "1234567890",
          "id": "wamid.xxx",
          "timestamp": "1234567890",
          "type": "text",
          "text": {
            "body": "Hello"
          }
        }
      ]
    }
  }
}
```

### Outgoing Message (Text)

```json
{
  "phone": "+1234567890",
  "message": "Hello! How can I help you?",
  "type": "text"
}
```

### Outgoing Message (Buttons)

```json
{
  "phone": "+1234567890",
  "message": "Choose an option:",
  "type": "interactive buttons",
  "buttons": [
    {
      "id": "id_0",
      "title": "Option 1"
    },
    {
      "id": "id_1",
      "title": "Option 2"
    }
  ]
}
```

### Outgoing Message (Media)

```json
{
  "phone": "+1234567890",
  "media_type": "image",
  "media_url": "https://example.com/image.jpg",
  "file_name": "image_123456.jpg",
  "caption": "Check out this image!"
}
```

## Best Practices

1. **Error Handling**: Always implement try-catch blocks
2. **Logging**: Log all important events for debugging
3. **Validation**: Validate all incoming data
4. **Security**: Use HTTPS and secure tokens
5. **Testing**: Test thoroughly before production
6. **Monitoring**: Set up alerts for failures
7. **Documentation**: Keep your bot commands documented
8. **User Experience**: Provide clear instructions and feedback

## Support

For issues or questions about the ConverseDriver integration, check:
- Application logs (`storage/logs/laravel.log`)
- Redis connection status
- API endpoint accessibility
- Token validity


