<?php
 namespace App\Services; use App\Models\Setting; use App\Models\Ticket; use App\Models\TicketDepartment; use App\Models\TicketReply; use Illuminate\Support\Facades\Http; use Illuminate\Support\Facades\Log; use Illuminate\Support\Str; class TicketWhatsAppService { public function isEnabled(TicketDepartment $department): bool { return $department->whatsapp_enabled && !empty($department->whatsapp_phone) && !empty(Setting::get('whatsapp_api_token')) && !empty(Setting::get('whatsapp_phone_number_id')); } public function sendTicketOpened(Ticket $ticket): void { $department = $ticket->department; if (!$this->isEnabled($department)) { return; } $client = $ticket->client; $clientName = $client ? trim($client->first_name . ' ' . $client->last_name) : 'Guest'; $firstMessage = $ticket->replies()->oldest()->first()?->message ?? ''; $text = "🎫 *New Ticket #{$ticket->id}*\n\n" . "*Subject:* " . Str::limit($ticket->title ?? '-', 100) . "\n" . "*Priority:* " . ucfirst($ticket->priority ?? 'normal') . "\n" . "*Client:* {$clientName} ({$ticket->mail})\n" . "*Department:* " . ($department->name ?? '-') . "\n\n" . Str::limit($firstMessage, 500) . "\n\n" . $this->ticketUrl($ticket); $this->sendText($department->whatsapp_phone, $text); } public function sendReply(Ticket $ticket, TicketReply $reply): void { $department = $ticket->department; if (!$this->isEnabled($department) || $reply->is_internal) { return; } $authorName = $reply->isFromAdmin() ? ($reply->admin?->name ?? 'Admin') : trim(($reply->client?->first_name ?? '') . ' ' . ($reply->client?->last_name ?? '')); $label = $reply->isFromAdmin() ? '👤 Staff Reply' : '💬 Client Reply'; $text = "{$label} on *Ticket #{$ticket->id}*\n" . "*By:* {$authorName}\n\n" . Str::limit($reply->message ?? '', 500) . "\n\n" . $this->ticketUrl($ticket); $this->sendText($department->whatsapp_phone, $text); } public function sendTicketClosed(Ticket $ticket): void { $department = $ticket->department; if (!$this->isEnabled($department)) { return; } $text = "✅ *Ticket #{$ticket->id} Closed*\n" . "*Subject:* " . Str::limit($ticket->title ?? '-', 100); $this->sendText($department->whatsapp_phone, $text); } public function sendEscalationNotice(Ticket $ticket, string $ruleName, array $changes): void { $department = $ticket->department; if (!$this->isEnabled($department)) { return; } $parts = ["🚨 *Ticket #{$ticket->id} Escalated*\n*Rule:* {$ruleName}"]; if (isset($changes['department_id'])) $parts[] = '• Department changed'; if (isset($changes['priority'])) $parts[] = "• Priority: {$changes['priority']['from']} → {$changes['priority']['to']}"; if (isset($changes['flagged'])) $parts[] = '• Flagged'; $this->sendText($department->whatsapp_phone, implode("\n", $parts)); } private function sendText(string $to, string $text): void { $token = Setting::get('whatsapp_api_token'); $phoneNumberId = Setting::get('whatsapp_phone_number_id'); try { $response = Http::withToken($token) ->timeout(10) ->post("https://graph.facebook.com/v18.0/{$phoneNumberId}/messages", [ 'messaging_product' => 'whatsapp', 'to' => $to, 'type' => 'text', 'text' => ['body' => $text, 'preview_url' => false], ]); if ($response->failed()) { $error = $response->json('error'); Log::warning('WhatsApp ticket notification failed', [ 'to' => $to, 'error_code' => $error['code'] ?? null, 'error_message' => $error['message'] ?? null, 'hint' => ($error['code'] ?? 0) === 131047 ? '24-hour customer service window expired — approved template required' : null, ]); } } catch (\Exception $e) { Log::error('WhatsApp send exception', ['error' => $e->getMessage()]); } } private function ticketUrl(Ticket $ticket): string { return url("/admin/tickets/{$ticket->id}"); } } 