value('value'), '/'); $token = Setting::where('key', 'voip_api_token')->value('value'); $callPath = Setting::where('key', 'voip_api_call_path')->value('value') ?: '/calls'; if (! $baseUrl) { return [ 'success' => false, 'provider_call_id' => null, 'message' => 'نشانی ای‌پی‌آی تماس تنظیم نشده است', 'status' => 'configuration_error', ]; } $request = Http::acceptJson()->timeout(10); if ($token) { $request = $request->withToken($token); } $response = $request->post($baseUrl.'/'.ltrim($callPath, '/'), [ 'phone' => $phone, 'caller_id' => $callerId, ]); $body = $response->json() ?: []; return [ 'success' => $response->successful(), 'provider_call_id' => $body['provider_call_id'] ?? $body['call_id'] ?? null, 'message' => $body['message'] ?? ($response->successful() ? 'تماس از راه ای‌پی‌آی ارسال شد' : 'خطا در ارسال تماس از راه ای‌پی‌آی'), 'status' => $body['status'] ?? ($response->successful() ? 'initiated' : 'failed'), 'raw' => $body, ]; } public function getCallStatus(string $providerCallId): array { $baseUrl = rtrim((string) Setting::where('key', 'voip_api_base_url')->value('value'), '/'); $token = Setting::where('key', 'voip_api_token')->value('value'); $statusPath = Setting::where('key', 'voip_api_status_path')->value('value') ?: '/calls/{id}'; if (! $baseUrl) { return ['status' => 'configuration_error']; } $request = Http::acceptJson()->timeout(10); if ($token) { $request = $request->withToken($token); } $url = $baseUrl.'/'.ltrim(str_replace('{id}', $providerCallId, $statusPath), '/'); $response = $request->get($url); return $response->json() ?: [ 'status' => $response->successful() ? 'unknown' : 'failed', ]; } public function getRecordingUrl(string $providerCallId): ?string { $template = Setting::where('key', 'voip_api_recording_url')->value('value'); return $template ? str_replace('{id}', $providerCallId, $template) : null; } public function testConnection(): array { $missing = []; foreach (['voip_api_base_url', 'voip_api_token'] as $key) { if (! Setting::where('key', $key)->value('value')) { $missing[] = $key; } } if ($missing !== []) { return ['ok' => false, 'message' => 'تنظیمات اتصال API کامل نیست.', 'missing' => $missing]; } $baseUrl = rtrim((string) Setting::where('key', 'voip_api_base_url')->value('value'), '/'); $token = Setting::where('key', 'voip_api_token')->value('value'); $healthPath = Setting::where('key', 'voip_api_health_path')->value('value') ?: '/health'; $started = microtime(true); try { $response = Http::acceptJson()->withToken($token)->timeout(10)->get($baseUrl.'/'.ltrim($healthPath, '/')); $latency = (int) round((microtime(true) - $started) * 1000); return [ 'ok' => $response->successful(), 'message' => $response->successful() ? "اتصال واقعی API موفق بود ({$latency} میلی‌ثانیه)." : "سرویس API پاسخ {$response->status()} داد.", 'missing' => [], 'latency_ms' => $latency, 'http_status' => $response->status(), ]; } catch (Throwable $error) { return ['ok' => false, 'message' => 'اتصال واقعی API برقرار نشد: '.$error->getMessage(), 'missing' => []]; } } }