<?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 TicketPushoverService { private const API_URL = 'https://api.pushover.net/1/messages.json'; public function isEnabled(TicketDepartment $department): bool { return $department->pushover_enabled && !empty($department->pushover_user_key) && !empty(Setting::get('pushover_app_token')); } 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 ?? ''; $title = "🎫 New Ticket #{$ticket->id}"; $message = "Subject: " . Str::limit($ticket->title ?? '-', 100) . "\n" . "Priority: " . ucfirst($ticket->priority ?? 'normal') . "\n" . "Client: {$clientName}\n" . "Dept: " . ($department->name ?? '-') . "\n\n" . Str::limit($firstMessage, 300); $this->send( $department->pushover_user_key, $title, $message, priority: $this->mapPriority($ticket->priority), url: $this->ticketUrl($ticket), ); } 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'; $title = "{$label} on #{$ticket->id}"; $message = "By: {$authorName}\n\n" . Str::limit($reply->message ?? '', 400); $this->send( $department->pushover_user_key, $title, $message, url: $this->ticketUrl($ticket), ); } public function sendTicketClosed(Ticket $ticket): void { $department = $ticket->department; if (!$this->isEnabled($department)) { return; } $this->send( $department->pushover_user_key, "✅ Ticket #{$ticket->id} Closed", Str::limit($ticket->title ?? '-', 200), url: $this->ticketUrl($ticket), ); } public function sendEscalationNotice(Ticket $ticket, string $ruleName, array $changes): void { $department = $ticket->department; if (!$this->isEnabled($department)) { return; } $parts = ["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->send( $department->pushover_user_key, "🚨 Ticket #{$ticket->id} Escalated", implode("\n", $parts), priority: 1, url: $this->ticketUrl($ticket), ); } private function send(string $recipient, string $title, string $message, int $priority = 0, ?string $url = null): void { $appToken = Setting::get('pushover_app_token'); $payload = [ 'token' => $appToken, 'user' => $recipient, 'title' => $title, 'message' => $message, 'priority' => $priority, ]; if ($url) { $payload['url'] = $url; $payload['url_title'] = 'Open in Admin'; } try { $response = Http::asForm()->post(self::API_URL, $payload); $data = $response->json(); if (($data['status'] ?? 0) !== 1) { Log::warning('Pushover ticket notification failed', [ 'errors' => $data['errors'] ?? [], 'status' => $response->status(), ]); } } catch (\Exception $e) { Log::error('Pushover send exception', ['error' => $e->getMessage()]); } } private function mapPriority(?string $ticketPriority): int { return match (strtolower($ticketPriority ?? 'normal')) { 'high', 'urgent', 'critical' => 1, 'low' => -1, default => 0, }; } private function ticketUrl(Ticket $ticket): string { return url("/admin/tickets/{$ticket->id}"); } } 