getMessage() . "\n"); } echo "Starting Auto Marketing Pusher Engine...\n"; // 1. استخراج الركاب الخاملين في آخر ساعتين (الذين لم يقموا بأي طلب اليوم) // نبحث في جدول locations أو tokens للركاب الذين لديهم نشاط قريب دون رحلات $sqlIdle = " SELECT p.id as passenger_id, t.token, p.country_code FROM passengers p JOIN tokens t ON p.id = t.passengerID WHERE p.id NOT IN ( SELECT passenger_id FROM rides WHERE DATE(created_at) = CURDATE() ) LIMIT 1000 "; // ملاحظة: في بيئة الإنتاج، استخدم جدول فتح التطبيق (App Opens) للحصول على دقة أعلى للركاب الذين فتحوا التطبيق مؤخراً. $stmtIdle = $con->query($sqlIdle); $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"; ?>