'failure', 'message' => 'Unauthorized access. Admin role required.']); exit; } // 2. Filter inputs $regionName = filterRequest('region_name') ?? 'Damascus'; $countryCode = filterRequest('country_code') ?? 'SY'; $siroBasePrice = filterRequest('siro_base_price', 'float') ?? 10000.0; try { // 3. Fetch recent competitor prices for this region to supply context to Gemini $sqlPrices = "SELECT competitor_name, price_amount AS total_price, (price_amount / price_per_km) AS distance_km FROM scraped_competitor_prices WHERE country_code = :country AND price_per_km > 0 ORDER BY created_at DESC LIMIT 10"; $stmtPrices = $con->prepare($sqlPrices); $stmtPrices->execute([':country' => strtoupper($countryCode)]); $competitorPrices = $stmtPrices->fetchAll(PDO::FETCH_ASSOC); if (empty($competitorPrices)) { // Fallback mock context if no competitor pricing has been scraped yet $competitorPrices = [ ['competitor_name' => 'yallago', 'total_price' => 12000, 'distance_km' => 5], ['competitor_name' => 'zaken', 'total_price' => 11500, 'distance_km' => 5] ]; } // 4. Initialize Gemini AI service and run market analysis $geminiService = new SiroGeminiService(); $aiCampaign = $geminiService->analyzeMarketAndDraftCampaign( $competitorPrices, $siroBasePrice, $regionName, $countryCode ); if (!$aiCampaign) { jsonError("Failed to generate campaign via Gemini AI service."); } // Check if campaign is recommended $opportunityDetected = $aiCampaign['opportunity_detected'] ?? false; if (!$opportunityDetected) { jsonSuccess([ 'campaign_created' => false, 'reason' => 'Gemini AI determined no marketing opportunity is present based on current pricing structures.', 'ai_analysis' => $aiCampaign ]); } $promoCode = $aiCampaign['promo_code'] ?? 'SIROGO10'; $discountVal = $aiCampaign['discount_percentage'] ?? 10; $pushTitle = $aiCampaign['push_title'] ?? 'خصومات مميزة من سيرو!'; $pushBody = $aiCampaign['push_body'] ?? 'وفر أكثر على رحلتك القادمة معنا.'; $smsBody = $aiCampaign['sms_body'] ?? 'اشتقنا لك! عد إلينا ووفر أكثر مع الرمز الترويجي الخاص بك.'; // 5. Target Passengers in the specified country // Since phone numbers are encrypted, we fetch all passengers, decrypt, and filter by country prefix. $sqlTarget = "SELECT id AS passenger_id, phone FROM passengers"; $stmtTarget = $con->prepare($sqlTarget); $stmtTarget->execute(); $allPassengers = $stmtTarget->fetchAll(PDO::FETCH_ASSOC); $targets = []; $debugCounts = ['JO' => 0, 'SY' => 0, 'EG' => 0, 'IQ' => 0, 'UNKNOWN' => 0, 'DECRYPT_FAIL' => 0]; foreach ($allPassengers as $p) { $decryptedPhone = $encryptionHelper->decryptData($p['phone']); if (!$decryptedPhone) { $debugCounts['DECRYPT_FAIL']++; continue; } $cleanPhone = preg_replace('/[^0-9]/', '', $decryptedPhone); $pCountry = 'UNKNOWN'; if (strpos($cleanPhone, '962') === 0 || strpos($cleanPhone, '07') === 0) $pCountry = 'JO'; elseif (strpos($cleanPhone, '963') === 0 || (strpos($cleanPhone, '09') === 0 && strlen($cleanPhone) == 10)) $pCountry = 'SY'; elseif (strpos($cleanPhone, '20') === 0 || (strpos($cleanPhone, '01') === 0 && strlen($cleanPhone) == 11)) $pCountry = 'EG'; elseif (strpos($cleanPhone, '964') === 0) $pCountry = 'IQ'; $debugCounts[$pCountry]++; if ($pCountry === strtoupper($countryCode)) { $targets[] = ['passenger_id' => $p['passenger_id'], 'decrypted_phone' => $decryptedPhone]; } } $sentFcm = 0; $sentSms = 0; $sentWhatsApp = 0; $dispatchedPassengers = []; // 6. Save broadcast promo for this campaign (Option 1 - promos table adjustment) $sqlPromo = "INSERT INTO promos (promo_code, amount, description, passengerID, source, validity_start_date, validity_end_date) VALUES (:code, :amount, :desc, 'all', 'ai_generated', CURDATE(), DATE_ADD(CURDATE(), INTERVAL 7 DAY))"; $stmtPromo = $con->prepare($sqlPromo); $stmtPromo->execute([ ':code' => $promoCode, ':amount' => (string)$discountVal, ':desc' => "AI Dynamic Promo: $promoCode ($discountVal%)" ]); foreach ($targets as $target) { $passengerId = $target['passenger_id']; // Enforce anti-spam: check if passenger received any SMS/WhatsApp campaign in the last 24 hours $sqlSpamCheck = "SELECT COUNT(*) FROM marketing_campaigns_log WHERE passenger_id = :pid AND message_type IN ('sms', 'whatsapp') AND sent_at > DATE_SUB(NOW(), INTERVAL 24 HOUR)"; $stmtSpam = $con->prepare($sqlSpamCheck); $stmtSpam->execute([':pid' => $passengerId]); $spamCount = intval($stmtSpam->fetchColumn()); // Check if passenger has active FCM token $sqlToken = "SELECT token FROM tokens WHERE passengerID = :pid LIMIT 1"; $stmtToken = $con->prepare($sqlToken); $stmtToken->execute([':pid' => $passengerId]); $fcmToken = $stmtToken->fetchColumn(); $pushSent = false; if ($fcmToken) { $decryptedToken = $encryptionHelper->decryptData($fcmToken); if ($decryptedToken) { // Send FCM Push Notification (Free channel - no anti-spam restriction needed) $fcmData = [ 'type' => 'marketing_campaign', 'promo_code' => $promoCode, 'discount' => (string)$discountVal ]; $fcmResult = sendFcmNotification( $decryptedToken, $pushTitle, $pushBody, $fcmData, 'Marketing', 'notification' ); if ($fcmResult['status'] === 'success') { $sentFcm++; // Log campaign dispatch $logStmt = $con->prepare("INSERT INTO marketing_campaigns_log (passenger_id, message_type, country_code, region_name, triggered_by) VALUES (?, 'push', ?, ?, 'autopilot')"); $logStmt->execute([$passengerId, $countryCode, $regionName]); $dispatchedPassengers[] = $passengerId; $pushSent = true; } } } if (!$pushSent) { // Fallback: Churned user (No token) OR Push failed -> Send WhatsApp or SMS // Check anti-spam first to prevent unnecessary marketing cost if ($spamCount === 0) { // Fetch and decrypt passenger phone number $sqlUser = "SELECT phone FROM passengers WHERE id = :pid LIMIT 1"; $stmtUser = $con->prepare($sqlUser); $stmtUser->execute([':pid' => $passengerId]); $encPhone = $stmtUser->fetchColumn(); if ($encPhone) { $decryptedPhone = $encryptionHelper->decryptData($encPhone); if ($decryptedPhone) { // Send WhatsApp (or fallback to SMS simulation) $waResult = sendWhatsAppFromServer($decryptedPhone, $smsBody); if ($waResult && ($waResult['status'] ?? '') === 'success') { $sentWhatsApp++; $logStmt = $con->prepare("INSERT INTO marketing_campaigns_log (passenger_id, message_type, country_code, region_name, triggered_by) VALUES (?, 'whatsapp', ?, ?, 'autopilot')"); $logStmt->execute([$passengerId, $countryCode, $regionName]); $dispatchedPassengers[] = $passengerId; } else { // Fallback to SMS simulation $sentSms++; $logStmt = $con->prepare("INSERT INTO marketing_campaigns_log (passenger_id, message_type, country_code, region_name, triggered_by) VALUES (?, 'sms', ?, ?, 'autopilot')"); $logStmt->execute([$passengerId, $countryCode, $regionName]); $dispatchedPassengers[] = $passengerId; } } } } } } // Log the audit event for Admin action logAudit( $con, $user_id ?? 'admin_system', 'trigger_marketing_campaign', 'promos', $promoCode, ['promo_code' => $promoCode, 'targets_count' => count($dispatchedPassengers)] ); jsonSuccess([ 'campaign_created' => true, 'promo_code' => $promoCode, 'discount_percentage' => $discountVal, 'push_notification' => [ 'title' => $pushTitle, 'body' => $pushBody, 'sent_count' => $sentFcm ], 'whatsapp_sms' => [ 'body' => $smsBody, 'whatsapp_sent_count' => $sentWhatsApp, 'sms_sent_count' => $sentSms ], 'total_dispatched' => count($dispatchedPassengers), 'debug_info' => [ 'requested_country' => $countryCode, 'total_passengers_in_db' => count($allPassengers), 'matched_targets' => count($targets), 'distribution' => $debugCounts ] ]); } catch (Exception $e) { error_log("[trigger_campaign.php] Error: " . $e->getMessage()); jsonError("Failed to trigger marketing campaign: " . $e->getMessage()); }