# WhatsApp Multi-Provider Architecture

Esta arquitectura permite usar múltiples proveedores de WhatsApp (Twilio, 360dialog, etc.) de forma transparente.

## Estructura de Archivos

```
Whatsapp/
├── Contracts/
│   └── WhatsappProviderInterface.php    # Interfaz que todos los proveedores implementan
├── DTO/
│   ├── NormalizedMessage.php            # Mensaje entrante normalizado
│   ├── NormalizedStatusUpdate.php       # Actualización de estado normalizada
│   ├── NormalizedTemplate.php           # Template normalizado
│   ├── SendMessageRequest.php           # Request para enviar mensaje
│   └── SendTemplateRequest.php          # Request para enviar template
├── Providers/
│   ├── AbstractWhatsappProvider.php     # Clase base con funcionalidad común
│   ├── TwilioProvider.php               # Implementación para Twilio
│   └── Dialog360Provider.php            # Implementación para 360dialog
├── Legacy/
│   └── WhatsappTwilioManager.php        # Wrapper de compatibilidad (deprecated)
├── WhatsappProviderFactory.php          # Factory para crear proveedores
├── WhatsappManager.php                  # Manager principal agnóstico
├── WhatsappWebhookController.php        # Controller de webhooks WordPress
└── WhatsappButtonHandler.php            # Handler de respuestas de botones
```

## Uso Básico

### Enviar un mensaje de texto

```php
use Alexr\Whatsapp\WhatsappManager;

$manager = WhatsappManager::forRestaurant($restaurantId);

// Enviar mensaje simple
$result = $manager->sendMessage(
    '+34612345678',
    'Hola, tu reserva está confirmada',
    $bookingId,  // opcional
    $customerId  // opcional
);

if ($result['success']) {
    echo "Mensaje enviado: " . $result['data']['message_id'];
}
```

### Enviar un template

```php
use Alexr\Whatsapp\WhatsappManager;

$manager = WhatsappManager::forRestaurant($restaurantId);

// Para Twilio, usar Content SID
// Para 360dialog, usar el nombre del template
$result = $manager->sendTemplate(
    '+34612345678',
    'HX1234567890abcdef',  // Template ID
    ['1' => 'Juan', '2' => '20/01/2025', '3' => '20:00'],
    $bookingId,
    $customerId,
    'booking_confirmation'
);
```

### Enviar template de reserva (con formato automático)

```php
$result = $manager->sendBookingTemplate(
    '+34612345678',
    'HX1234567890abcdef',
    [
        'customer_name' => 'Juan García',
        'date' => '2025-01-20',
        'time' => '20:00',
        'party' => 4,
    ],
    $bookingId,
    $customerId
);
```

### Obtener templates disponibles

```php
$result = $manager->getTemplates(50);

if ($result['success']) {
    foreach ($result['data']['templates'] as $template) {
        echo $template['name'] . ' - ' . $template['body'];
    }
}
```

## Configuración

### En la base de datos (WhatsappConfig)

La configuración se almacena en el campo `config` como JSON:

#### Para Twilio:
```json
{
    "enabled": true,
    "provider": "twilio",
    "twilio_sid": "ACxxxxxxxxxxxxxxxxx",
    "twilio_token": "your_auth_token",
    "twilio_phone": "+14155238886",
    "restaurant_name": "Mi Restaurante",
    "phone": "+34912345678",
    "date_format": "dmy",
    "time_format": "24h"
}
```

#### Para 360dialog:
```json
{
    "enabled": true,
    "provider": "360dialog",
    "dialog360_api_key": "your_api_key",
    "dialog360_phone_number": "+34612345678",
    "dialog360_phone_number_id": "123456789",
    "dialog360_webhook_verify_token": "your_verify_token",
    "dialog360_app_secret": "your_app_secret",
    "restaurant_name": "Mi Restaurante",
    "phone": "+34912345678"
}
```

**Nota**: Si no se especifica `provider`, el sistema lo detecta automáticamente según las credenciales configuradas.

## Webhooks

### URLs de Webhook

```php
$manager = WhatsappManager::forRestaurant($restaurantId);
$urls = $manager->getWebhookUrls();

// $urls['incoming'] => URL para mensajes entrantes
// $urls['status']   => URL para callbacks de estado
```

Las URLs tienen el formato:
```
https://tudominio.com/wp-admin/admin-ajax.php?action=alexr_whatsapp_webhook&restaurant_id=1
```

### Configurar en Twilio

1. Ve a tu número de WhatsApp en Twilio Console
2. Configura "When a message comes in" con la URL de incoming
3. Configura "Status Callback URL" con la URL de status

### Configurar en 360dialog

1. En tu Dashboard de 360dialog, configura el Webhook URL
2. Usa el mismo endpoint para mensajes y estados
3. Configura el `Verify Token` que coincida con `dialog360_webhook_verify_token`

## Manejar Respuestas de Botones

```php
use Alexr\Whatsapp\WhatsappButtonHandler;

// Registrar un handler personalizado
WhatsappButtonHandler::registerHandler('my_action', function($parsed, $restaurantId, $message, $conversation) {
    // $parsed contiene los datos normalizados del mensaje
    // $message es el modelo WhatsappMessage
    // $conversation es el modelo WhatsappConversation
    
    // Tu lógica aquí
    
    // Enviar respuesta si es necesario
    WhatsappButtonHandler::sendResponse(
        $restaurantId,
        $parsed['from_phone'],
        'Acción procesada correctamente',
        $message->booking_id
    );
}, 10);
```

Los handlers predefinidos:
- `alexr_whatsapp_button_confirm_booking`
- `alexr_whatsapp_button_cancel_booking`

## Añadir un Nuevo Proveedor

### 1. Crear la clase del proveedor

```php
namespace Alexr\Whatsapp\Providers;

use Alexr\Whatsapp\DTO\NormalizedMessage;
use Alexr\Whatsapp\DTO\NormalizedStatusUpdate;
use Alexr\Whatsapp\DTO\SendMessageRequest;
use Alexr\Whatsapp\DTO\SendTemplateRequest;

class MyNewProvider extends AbstractWhatsappProvider
{
    public const PROVIDER_NAME = 'mynewprovider';

    public function getProviderName(): string
    {
        return self::PROVIDER_NAME;
    }

    protected function loadProviderConfig(): void
    {
        // Cargar configuración específica del proveedor
        $this->apiKey = $this->config['mynewprovider_api_key'] ?? '';
    }

    protected function initClient(): void
    {
        // Inicializar cliente HTTP
    }

    public function isConfigured(): bool
    {
        return !empty($this->apiKey);
    }

    // Implementar todos los métodos de WhatsappProviderInterface...
}
```

### 2. Registrar el proveedor

```php
use Alexr\Whatsapp\WhatsappProviderFactory;

WhatsappProviderFactory::register('mynewprovider', MyNewProvider::class);
```

### 3. Actualizar la detección automática (opcional)

En `WhatsappProviderFactory::getProviderType()`, añadir la detección:

```php
if (!empty($configData['mynewprovider_api_key'])) {
    return 'mynewprovider';
}
```

## Migración desde WhatsappTwilioManager

Para una migración gradual, puedes seguir usando `WhatsappTwilioManager` que ahora es un wrapper:

```php
// Código antiguo (sigue funcionando)
use Alexr\Whatsapp\WhatsappTwilioManager;
$manager = WhatsappTwilioManager::forRestaurant($restaurantId);
$manager->sendMessage('+34612345678', 'Hola');

// Código nuevo (recomendado)
use Alexr\Whatsapp\WhatsappManager;
$manager = WhatsappManager::forRestaurant($restaurantId);
$manager->sendMessage('+34612345678', 'Hola');
```

La API es idéntica, pero `WhatsappTwilioManager` mostrará un aviso de deprecación en modo debug.

## Hooks de WordPress

### Mensajes enviados
```php
add_action('alexr_whatsapp_message_sent', function($data) {
    // $data['restaurant_id']
    // $data['phone']
    // $data['message_id']
    // $data['provider_message_id']
    // $data['type'] (text, template)
    // $data['provider']
}, 10, 1);
```

### Mensajes entrantes
```php
add_action('alexr_whatsapp_incoming_message', function($parsed, $restaurantId, $message, $conversation) {
    // $parsed es array con datos normalizados
    // $message es WhatsappMessage
    // $conversation es WhatsappConversation
}, 10, 4);
```

### Respuestas de botones
```php
add_action('alexr_whatsapp_button_response', function($parsed, $restaurantId, $message, $conversation) {
    // Procesar cualquier respuesta de botón
}, 10, 4);

// O para un botón específico
add_action('alexr_whatsapp_button_confirm_booking', function($parsed, $restaurantId, $message, $conversation) {
    // Solo respuestas de confirm_booking
}, 10, 4);
```

### Callbacks de estado
```php
add_action('alexr_whatsapp_status_callback', function($parsed, $restaurantId, $webhook, $message) {
    // Cualquier cambio de estado
}, 10, 4);

add_action('alexr_whatsapp_status_delivered', function($parsed, $restaurantId, $webhook, $message) {
    // Solo cuando el mensaje fue entregado
}, 10, 4);
```

## Constantes de Configuración

```php
// Desactivar validación de firma (solo desarrollo)
define('ALEXR_WHATSAPP_SKIP_SIGNATURE', true);

// Activar debug logging
define('ALEXR_WHATSAPP_DEBUG', true);

// Log file personalizado
define('ALEXR_WHATSAPP_LOG_FILE', '/path/to/whatsapp.log');

// URL base para webhooks en desarrollo local
define('ALEXR_WHATSAPP_WEBHOOK_BASE_URL', 'https://your-tunnel.ngrok.io');
```

## Testing

### Verificar configuración
```php
$manager = WhatsappManager::forRestaurant($restaurantId);

echo "Provider: " . $manager->getProviderName();
echo "Configured: " . ($manager->isConfigured() ? 'Yes' : 'No');

$test = $manager->testConnection();
echo "Connection: " . ($test['success'] ? 'OK' : $test['message']);
```

### Simular webhook entrante
```php
$manager = WhatsappManager::forRestaurant($restaurantId);

// Payload de Twilio
$twilioPayload = [
    'MessageSid' => 'SMxxxxxxxx',
    'From' => 'whatsapp:+34612345678',
    'To' => 'whatsapp:+14155238886',
    'Body' => 'Hola',
    'ProfileName' => 'Juan',
];

// Payload de 360dialog
$dialog360Payload = [
    'entry' => [[
        'changes' => [[
            'value' => [
                'messages' => [[
                    'id' => 'wamid.xxxxx',
                    'from' => '34612345678',
                    'type' => 'text',
                    'text' => ['body' => 'Hola'],
                ]],
                'contacts' => [[
                    'profile' => ['name' => 'Juan'],
                    'wa_id' => '34612345678',
                ]],
            ],
        ]],
    ]],
];

$result = $manager->processWebhook($twilioPayload);
```
