getMessage() . "\n"); } // getRedisConnection() لا ترمي استثناءً — تُعيد null عند تعذّر الاتصال. // مفتاح مكافحة التكرار (TTL يوم كامل) يعيش في Redis؛ بدونه يُعاد إرسال // نفس الحملة التسويقية كل ساعة. if (!$redis) { error_log('[AutoMarketingPusher] ABORT: Redis unavailable — anti-spam guard would fail open.'); die("Redis unavailable — aborting to avoid duplicate campaign pushes.\n"); } echo "Starting Auto Marketing Pusher Engine...\n"; // 1. استخراج الركاب الخاملين في آخر ساعتين (الذين لم يقموا بأي طلب اليوم) // First, fetch active passenger IDs from the ride database $stmtRide = $conRide->query("SELECT DISTINCT passenger_id FROM ride WHERE DATE(created_at) = CURDATE()"); $activePassengerIds = $stmtRide->fetchAll(PDO::FETCH_COLUMN); if (!empty($activePassengerIds)) { $placeholders = implode(',', array_fill(0, count($activePassengerIds), '?')); $notInSql = "WHERE p.id NOT IN ($placeholders) AND p.status = 'notDeleted'"; } else { $notInSql = "WHERE p.status = 'notDeleted'"; } // Then, fetch idle passengers from the main database $sqlIdle = " SELECT p.id as passenger_id, t.token, IFNULL(MAX(pol.country_code), 'JO') as country_code FROM passengers p JOIN tokens t ON p.id = t.passengerID LEFT JOIN passenger_opening_locations pol ON pol.passenger_id = p.id $notInSql GROUP BY p.id, t.token LIMIT 1000 "; $stmtIdle = $con->prepare($sqlIdle); $stmtIdle->execute($activePassengerIds); $idlePassengers = $stmtIdle->fetchAll(PDO::FETCH_ASSOC); if (empty($idlePassengers)) { echo "No idle passengers found at this moment.\n"; exit; } // تجميع الركاب حسب الدولة لتقليل استدعاءات Gemini $passengersByCountry = []; foreach ($idlePassengers as $p) { $country = strtoupper($p['country_code'] ?? 'SY'); $passengersByCountry[$country][] = $p; } $geminiService = new SiroGeminiService(); $encryptionHelper = new EncryptionHelper(); $totalPushes = 0; foreach ($passengersByCountry as $countryCode => $passengers) { echo "Processing country: $countryCode (" . count($passengers) . " idle passengers)\n"; // 2. سحب أحدث أسعار المنافسين كمرجع لجيميناي $sqlPrices = "SELECT competitor_name, base_fare, price_per_km, price_per_min FROM competitor_secret_formulas WHERE country_code = :country ORDER BY last_updated DESC LIMIT 3"; $stmtPrices = $con->prepare($sqlPrices); $stmtPrices->execute([':country' => $countryCode]); $competitorFormulas = $stmtPrices->fetchAll(PDO::FETCH_ASSOC); if (empty($competitorFormulas)) { // Fallback $competitorFormulas = [['competitor_name' => 'Market Average', 'base_fare' => 1]]; } // 3. طلب رسالة تسويقية من Gemini $siroBasePrice = 1.0; // يمكن استخراج السعر الافتراضي لسيرو من جدول kazan $regionName = ($countryCode === 'JO') ? 'Amman' : 'Damascus'; $aiCampaign = $geminiService->analyzeMarketAndDraftCampaign( $competitorFormulas, $siroBasePrice, $regionName, $countryCode ); if (!$aiCampaign || $aiCampaign['opportunity_detected'] !== true) { echo " -> Gemini found no compelling marketing opportunity for $countryCode right now. Skipping push.\n"; continue; } $title = $aiCampaign['push_title'] ?? 'خصم حصري من سيرو!'; $body = $aiCampaign['push_body'] ?? 'سيارتك جاهزة وبأرخص سعر في السوق. اطلب الآن.'; $promoCode = $aiCampaign['promo_code'] ?? ''; echo " -> Gemini generated campaign: [$title] $body\n"; // 4. إرسال الـ Push Notification لكل راكب foreach ($passengers as $p) { $passengerId = $p['passenger_id']; $encryptedToken = $p['token']; $decryptedToken = $encryptionHelper->decryptData($encryptedToken); if (!$decryptedToken) continue; // ── Anti-spam: لا يُرسَل لنفس الراكب أكثر من مرة/24 ساعة ── $redisKey = "marketing_push:sent:{$passengerId}"; if ($redis && $redis->exists($redisKey)) { continue; } $dataPayload = [ 'type' => 'marketing_promo', 'promo_code' => $promoCode, 'screen' => 'home', ]; // ── إرسال FCM الفعلي ────────────────────────────────────── sendFCM_Internal( $decryptedToken, $title, $body, $dataPayload, 'Marketing', false, 'ding' ); // ── تسجيل anti-spam في Redis (TTL 24 ساعة) ─────────────── if ($redis) { $redis->setex($redisKey, 86400, '1'); } // ── حفظ في جدول notifications الداخلي ──────────────────── try { $ins = $con->prepare( "INSERT INTO notifications (title, body, passenger_id) VALUES (:t, :b, :pid)" ); $ins->execute([':t' => $title, ':b' => $body, ':pid' => $passengerId]); } catch (Exception $ignored) {} $totalPushes++; } } echo "Done. Sent $totalPushes automated marketing pushes via Gemini AI.\n"; ?>