<?php
/**
 * Multi-Source RSS to Database - Automated Cronjob
 * Fetches posts from multiple RSS.app feeds and inserts into database
 * Run: php x_feeds.php or via cronjob
 * 
 * Features:
 * - Supports multiple sources from cat_sources table
 * - Downloads all photos in gallery (post_id_1.jpg, post_id_2.jpg, ...)
 * - Smart source processing (processes unprocessed sources first)
 * - Detailed error logging
 */

// إعداد البيئة
set_time_limit(0);
ini_set('max_execution_time', 600);
ini_set('memory_limit', '512M');
error_reporting(E_ALL);
ini_set('display_errors', 0);
date_default_timezone_set('Europe/Istanbul');

$logFile = __DIR__ . '/x_feeds_debug.log';
file_put_contents($logFile, date('Y-m-d H:i:s') . " - Script started (PID: " . getmypid() . ")\n", FILE_APPEND);


//include "../inc/con.php";
include dirname(__DIR__) . "/inc/con.php";

// التحقق من AJAX request
$isAjax = isset($_GET['ajax']) && $_GET['ajax'] == 1;



// ============================================
// إعدادات المجلدات
// ============================================
$project_root = dirname(__DIR__, 1); // project/
$uploads_dir = $project_root . '/upload/';        // للصور
$media_dir = $project_root . '/upload_media/';    // للفيديوهات
$error_log_file = $project_root . '/rss_errors.log';

// إنشاء المجلدات إذا لم تكن موجودة
if (!is_dir($uploads_dir))
    mkdir($uploads_dir, 0755, true);
if (!is_dir($media_dir))
    mkdir($media_dir, 0755, true);

// ============================================
// إعدادات المعالجة
// ============================================
$MAX_SOURCES_PER_RUN = 10;  // عدد المصادر في كل تشغيل

// ============================================
// بدء التنفيذ
// ============================================
$startTime = microtime(true);
$logMessages = [];

// إنشاء سجل جديد في قاعدة البيانات
$logId = null;
try {
    $stmt = $db->prepare("INSERT INTO rss_logs (run_date, status) VALUES (NOW(), 'running')");
    $stmt->execute();
    $logId = $db->lastInsertId();
} catch (PDOException $e) {
    // تجاهل الخطأ إذا كان الجدول غير موجود
}

/**
 * تسجيل رسالة
 */
function logMessage($message, $type = 'INFO')
{
    global $logMessages, $isAjax;
    $timestamp = date('Y-m-d H:i:s');
    $logMessages[] = "[$timestamp][$type] $message";

    // لا تطبع الرسائل في وضع AJAX
    if (!$isAjax) {
        echo "[$timestamp][$type] $message\n";
    }
}

/**
 * تسجيل خطأ مفصل
 */
function logError($source_name, $error_type, $details, $post_id = null)
{
    global $error_log_file;
    $timestamp = date('Y-m-d H:i:s');
    $post_info = $post_id ? " | Post ID: $post_id" : "";
    $error_message = "[$timestamp] Source: $source_name | Type: $error_type$post_info | Details: $details\n";

    file_put_contents($error_log_file, $error_message, FILE_APPEND);
    logMessage("ERROR logged for $source_name: $error_type", "ERROR");
}

logMessage("Starting Multi-Source RSS Cronjob<BR>");

// التحقق من الاتصال بقاعدة البيانات
if (!isset($db)) {
    logMessage("<BR>Database connection not available<BR>", "ERROR");
    exit(1);
}
logMessage("<BR>Database connected successfully<BR>");

/**
 * جلب المصادر النشطة للمعالجة
 * يرتب حسب: NULL أولاً (لم تُعالج أبداً)، ثم الأقدم
 */
function getActiveSources($db, $limit = 10)
{
    try {
        $sql = "SELECT id, name, json_feed, last_fetch_time 
                FROM cat_sources 
                WHERE status = 1 AND json_feed IS NOT NULL AND json_feed != ''
                ORDER BY last_fetch_time IS NULL DESC, last_fetch_time ASC 
                LIMIT :limit";
        $stmt = $db->prepare($sql);
        $stmt->bindValue(':limit', $limit, PDO::PARAM_INT);
        $stmt->execute();
        return $stmt->fetchAll(PDO::FETCH_ASSOC);
    } catch (PDOException $e) {
        logError('SYSTEM', 'DATABASE_ERROR', 'Failed to fetch sources: ' . $e->getMessage());
        return [];
    }
}

/**
 * تحديث وقت آخر جلب للمصدر
 */
function updateSourceFetchTime($db, $source_id)
{
    try {
        $sql = "UPDATE cat_sources SET last_fetch_time = NOW() WHERE id = ?";
        $stmt = $db->prepare($sql);
        $stmt->execute([$source_id]);
        return true;
    } catch (PDOException $e) {
        logError('SYSTEM', 'DATABASE_ERROR', "Failed to update fetch time for source $source_id: " . $e->getMessage());
        return false;
    }
}

/**
 * تحويل التاريخ إلى توقيت القاهرة
 */
function convertToEgyptTime($dateString)
{
    try {
        $date = new DateTime($dateString, new DateTimeZone('UTC'));
        $date->setTimezone(new DateTimeZone('Africa/Cairo'));
        return $date->format('Y-m-d H:i:s');
    } catch (Exception $e) {
        return date('Y-m-d H:i:s');
    }
}

/**
 * تنظيف روابط تويتر من النص
 */
function cleanTwitterLinks($text)
{
    if (empty($text))
        return $text;
    $cleaned = preg_replace('/twitter\.com\/.*$/us', '', $text);
    $cleaned = rtrim($cleaned);
    $cleaned = preg_replace('/\s+$/u', '', $cleaned);
    return $cleaned;
}

/**
 * تنزيل ملف من رابط
 * @return array|false ['data' => binary data, 'size' => file size in bytes] or false on failure
 */
function downloadFile($url)
{
    $ch = curl_init();
    curl_setopt_array($ch, [
        CURLOPT_URL => $url,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_FOLLOWLOCATION => true,
        CURLOPT_TIMEOUT => 60,
        CURLOPT_SSL_VERIFYPEER => false,
        CURLOPT_SSL_VERIFYHOST => false,
        CURLOPT_USERAGENT => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
    ]);

    $data = curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);

    if ($data !== false && $httpCode === 200) {
        return [
            'data' => $data,
            'size' => strlen($data)
        ];
    }

    return false;
}

/**
 * حفظ ملف على السيرفر
 * @param string|array $data File data (string) or array from downloadFile
 * @return string|false Filename on success, false on failure
 */
function saveFile($data, $directory, $filename)
{
    if (!is_dir($directory)) {
        mkdir($directory, 0755, true);
    }

    // Handle both old format (string) and new format (array)
    $fileData = is_array($data) ? $data['data'] : $data;

    $filepath = $directory . $filename;
    return file_put_contents($filepath, $fileData) !== false ? $filename : false;
}

/**
 * استخراج Post ID من الرابط (Twitter أو YouTube)
 */
function getPostId($url)
{
    // Twitter: https://x.com/username/status/1234567890
    if (preg_match('/status\/(\d+)/', $url, $matches)) {
        return $matches[1];
    }

    // YouTube: https://www.youtube.com/watch?v=l53-6njVroM
    if (preg_match('/[\?&]v=([a-zA-Z0-9_-]+)/', $url, $matches)) {
        return $matches[1];
    }

    // YouTube Short: https://youtu.be/l53-6njVroM
    if (preg_match('/youtu\.be\/([a-zA-Z0-9_-]+)/', $url, $matches)) {
        return $matches[1];
    }

    // Fallback: استخدام hash من الرابط
    return substr(md5($url), 0, 13);
}

/**
 * إزالة كلمة pic من النص
 */
function removePicWord($text)
{
    $text = preg_replace('/\bpic\.?\s*/i', '', $text);
    $text = preg_replace('/\bpic\b/i', '', $text);
    return trim($text);
}

/**
 * استخراج رابط الفيديو من تويتر
 */
function getTwitterVideoUrl($itemUrl)
{
    $twitSaveUrl = 'https://twitsave.com/info?url=' . urlencode($itemUrl);

    $ch = curl_init();
    curl_setopt_array($ch, [
        CURLOPT_URL => $twitSaveUrl,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_FOLLOWLOCATION => true,
        CURLOPT_TIMEOUT => 30,
        CURLOPT_SSL_VERIFYPEER => false,
        CURLOPT_USERAGENT => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
    ]);

    $html = curl_exec($ch);
    curl_close($ch);

    if ($html === false) {
        return false;
    }

    // استخراج رابط الفيديو من <video src="...">
    if (preg_match('/<video[^>]+src="(https:\/\/video\.twimg\.com\/[^"]+\.mp4[^"]*)"/', $html, $matches)) {
        return html_entity_decode($matches[1]);
    }

    // البحث عن رابط التحميل في الأزرار
    if (preg_match('/<a href="(https:\/\/[^"]+\.mp4[^"]*)"[^>]*download[^>]*>/i', $html, $matches)) {
        return html_entity_decode($matches[1]);
    }

    if (preg_match('/<a[^>]+download[^>]+href="(https:\/\/[^"]+\.mp4[^"]*)"/i', $html, $matches)) {
        return html_entity_decode($matches[1]);
    }

    return false;
}

/**
 * فحص إذا كانت التغريدة تحتوي على فيديو
 */
function hasVideo($contentHtml, $attachments = [])
{
    if (stripos($contentHtml, 'video') !== false) {
        return true;
    }

    if (strpos($contentHtml, 'pic.twitter.com') !== false || strpos($contentHtml, 't.co') !== false) {
        return true;
    }

    return false;
}

/**
 * التحقق من وجود المنشور (بشكل سريع)
 */
function postExists($db, $postId)
{
    try {
        $stmt = $db->prepare("SELECT COUNT(*) FROM social_media_content WHERE post_id = ?");
        $stmt->execute([$postId]);
        return $stmt->fetchColumn() > 0;
    } catch (PDOException $e) {
        return false;
    }
}

/**
 * تحميل جميع صور الـ Gallery
 * @return array ['first_photo' => 'post_id_1.jpg', 'count' => 6]
 */
function downloadAllPhotos($attachments, $uploads_dir, $postId, $source_name)
{
    $result = [
        'first_photo' => null,
        'count' => 0
    ];

    if (empty($attachments)) {
        return $result;
    }

    logMessage("<BR><BR>Found " . count($attachments) . " photo(s) in gallery");

    $photoNumber = 1;
    foreach ($attachments as $attachment) {
        $url = $attachment['url'] ?? '';

        if (empty($url)) {
            continue;
        }

        $parsedUrl = parse_url($url);
        $pathInfo = pathinfo($parsedUrl['path']);
        $extension = $pathInfo['extension'] ?? 'jpg';

        // اسم الملف: post_id_1.jpg, post_id_2.jpg, ...
        $filename = $postId . '_' . $photoNumber . '.' . $extension;

        logMessage("<BR>Downloading photo $photoNumber: $filename");

        $fileData = downloadFile($url);
        if ($fileData !== false) {
            $saved = saveFile($fileData, $uploads_dir, $filename);
            if ($saved) {
                // حفظ اسم أول صورة
                if ($photoNumber === 1) {
                    $result['first_photo'] = $filename;
                }
                $result['count']++;
                logMessage("<BR>Photo $photoNumber saved: $filename", "SUCCESS");
                $photoNumber++;
            } else {
                logError($source_name, 'FILE_SAVE_ERROR', "Failed to save photo $photoNumber", $postId);
            }
        } else {
            logError($source_name, 'DOWNLOAD_ERROR', "Failed to download photo $photoNumber from $url", $postId);
        }
    }

    logMessage("<BR>Total photos downloaded: {$result['count']}", "SUCCESS");
    return $result;
}

/**
 * معالجة المرفقات وتحميل الفيديو وصورة الغلاف
 */
function processMedia($attachments, $uploads_dir, $media_dir, $itemUrl, $contentHtml, $postId, $source_name)
{
    $photoFile = null;
    $videoFile = null;
    $photosCount = 0;
    $videoSize = null;

    // التحقق من نوع المصدر
    $isTwitter = (strpos($itemUrl, 'twitter.com') !== false || strpos($itemUrl, 'x.com') !== false);
    $isYouTube = (strpos($itemUrl, 'youtube.com') !== false || strpos($itemUrl, 'youtu.be') !== false);

    // تحميل جميع الصور (بما فيها صورة الغلاف للفيديو)
    $photosResult = downloadAllPhotos($attachments, $uploads_dir, $postId, $source_name);
    $photoFile = $photosResult['first_photo'];
    $photosCount = $photosResult['count'];

    // معالجة فيديو تويتر
    if ($isTwitter && hasVideo($contentHtml, $attachments)) {
        logMessage("<BR><BR>Detecting video in tweet...");

        $videoUrl = getTwitterVideoUrl($itemUrl);

        if ($videoUrl) {
            logMessage("<BR><BR>Video URL found: $videoUrl");
            logMessage("<BR>Downloading video...");

            $filename = $postId . '.mp4';

            // Debug: Check URL headers before download
            $headers = get_headers($videoUrl, 1);
            if ($headers) {
                logMessage("<BR>DEBUG: Video Headers: " . json_encode($headers));
            }

            $videoData = downloadFile($videoUrl);

            if ($videoData !== false) {
                logMessage("<BR>DEBUG: Download successful. Size in bytes: " . $videoData['size']);

                $saved = saveFile($videoData, $media_dir, $filename);
                if ($saved) {
                    $videoFile = $filename;
                    $videoSize = $videoData['size']; // Capture file size
                    logMessage("<BR>Video saved successfully: $filename (Size: " . formatFileSize($videoSize) . ")", "SUCCESS");

                    // التأكد من وجود صورة غلاف للفيديو
                    if (empty($photoFile) && !empty($attachments)) {
                        logMessage("<BR>No cover photo found, attempting to download from attachments...");
                        $photosResult = downloadAllPhotos($attachments, $uploads_dir, $postId, $source_name);
                        $photoFile = $photosResult['first_photo'];
                        $photosCount = $photosResult['count'];
                    }
                } else {
                    logError($source_name, 'VIDEO_SAVE_ERROR', "Failed to save video file", $postId);
                }
            } else {
                logError($source_name, 'VIDEO_DOWNLOAD_ERROR', "Failed to download video from URL: $videoUrl", $postId);
            }
        } else {
            logMessage("<BR>Could not extract video URL from TwitSave", "WARNING");
        }
    }

    // معالجة فيديو يوتيوب - استخراج صورة الغلاف
    if ($isYouTube) {
        logMessage("<BR><BR>YouTube video detected");

        // استخراج YouTube Video ID
        $videoId = null;
        if (preg_match('/[\\?&]v=([a-zA-Z0-9_-]+)/', $itemUrl, $matches)) {
            $videoId = $matches[1];
        } elseif (preg_match('/youtu\\.be\\/([a-zA-Z0-9_-]+)/', $itemUrl, $matches)) {
            $videoId = $matches[1];
        }

        if ($videoId) {
            logMessage("<BR>YouTube Video ID: $videoId");

            // إذا لم تكن هناك صورة غلاف، حاول تحميلها من يوتيوب
            if (empty($photoFile)) {
                logMessage("<BR>Attempting to download YouTube thumbnail...");

                // محاولة تحميل صورة بجودة عالية من يوتيوب
                $thumbnailUrls = [
                    "https://img.youtube.com/vi/$videoId/maxresdefault.jpg", // أعلى جودة
                    "https://img.youtube.com/vi/$videoId/hqdefault.jpg",     // جودة عالية
                    "https://img.youtube.com/vi/$videoId/mqdefault.jpg",     // جودة متوسطة
                    "https://img.youtube.com/vi/$videoId/default.jpg"        // جودة عادية
                ];

                foreach ($thumbnailUrls as $thumbnailUrl) {
                    $thumbnailData = downloadFile($thumbnailUrl);
                    if ($thumbnailData !== false && $thumbnailData['size'] > 1000) { // تأكد أنها ليست صورة خطأ صغيرة
                        $filename = $postId . '_1.jpg';
                        $saved = saveFile($thumbnailData, $uploads_dir, $filename);
                        if ($saved) {
                            $photoFile = $filename;
                            $photosCount = 1;
                            logMessage("<BR>YouTube thumbnail downloaded successfully: $filename", "SUCCESS");
                            break;
                        }
                    }
                }

                if (empty($photoFile)) {
                    logMessage("<BR>Failed to download YouTube thumbnail", "WARNING");
                }
            } else {
                logMessage("<BR>Cover photo already exists from attachments");
            }

            // حفظ رابط الفيديو (لا نحمل الفيديو نفسه من يوتيوب)
            $videoFile = $itemUrl; // نحفظ الرابط فقط
            logMessage("<BR>YouTube video URL saved: $videoFile");
        }
    }

    return [
        'photo' => $photoFile,
        'video' => $videoFile,
        'photos_count' => $photosCount,
        'video_size' => $videoSize
    ];
}

/**
 * Helper function to format file size
 */
function formatFileSize($bytes)
{
    if ($bytes >= 1073741824) {
        return number_format($bytes / 1073741824, 2) . ' GB';
    } elseif ($bytes >= 1048576) {
        return number_format($bytes / 1048576, 2) . ' MB';
    } elseif ($bytes >= 1024) {
        return number_format($bytes / 1024, 2) . ' KB';
    } else {
        return $bytes . ' bytes';
    }
}

/**
 * تحديد نوع المحتوى
 * @param bool $hasPhoto هل يوجد صورة
 * @param bool $hasVideo هل يوجد فيديو
 * @param string $url رابط المنشور لتحديد المصدر
 * @param string $contentText نص المحتوى للبحث عن الكلمات المفتاحية
 * @param int $photosCount عدد الصور
 * @return int نوع المحتوى (1=صورة, 2=يوتيوب, 3=عاجل/خاص, 6=صور متعددة, 10=فيديو عام, 15=نص فقط, 21=فيديو تويتر)
 */
function getContentType($hasPhoto, $hasVideo, $url = '', $contentText = '', $photosCount = 0)
{
    // التحقق من الكلمات المفتاحية (#عاجل أو #خاص)
    $isUrgent = (stripos($contentText, '#عاجل') !== false || stripos($contentText, '#خاص') !== false);

    if ($isUrgent) {
        return 3; // عاجل أو خاص
    }

    // التحقق من الصور المتعددة (Gallery)
    if ($photosCount > 1) {
        return 6; // صور متعددة (gallery)
    }

    // التحقق من المصدر
    $isYouTube = (strpos($url, 'youtube.com') !== false || strpos($url, 'youtu.be') !== false);
    $isTwitter = (strpos($url, 'twitter.com') !== false || strpos($url, 'x.com') !== false);

    if ($hasVideo) {
        if ($isYouTube) {
            return 2; // يوتيوب
        } elseif ($isTwitter) {
            return 21; // فيديو تويتر
        }
        return 10; // فيديو عام (احتياطي)
    } elseif ($hasPhoto) {
        return 1; // صورة واحدة
    }

    // نص فقط - لا صور ولا فيديو
    return 15;
}

/**
 * إدخال منشور في قاعدة البيانات
 */
function insertPost($db, $postData)
{
    try {
        $sql = "INSERT INTO social_media_content (
            post_id, url, title, content_text, content_html, 
            photo, photos_count, video_url, file_size, attachments, content_type, 
            cat_sources, publish_date, create_date
        ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NOW())";

        $stmt = $db->prepare($sql);
        $success = $stmt->execute([
            $postData['post_id'],
            $postData['url'],
            $postData['title'],
            $postData['content_text'],
            $postData['content_html'],
            $postData['photo'],
            $postData['photos_count'],
            $postData['video_url'],
            $postData['file_size'],
            $postData['attachments'],
            $postData['content_type'],
            $postData['cat_sources'],
            $postData['publish_date']
        ]);

        if ($success) {
            return $db->lastInsertId();
        }
        return false;
    } catch (PDOException $e) {
        logError($postData['source_name'] ?? 'UNKNOWN', 'DATABASE_INSERT_ERROR', $e->getMessage(), $postData['post_id']);
        return false;
    }
}

/**
 * معالجة مصدر واحد
 */
function processSource($db, $source, $uploads_dir, $media_dir, $logId = null)
{
    $sourceStartTime = microtime(true);
    $source_id = $source['id'];
    $source_name = $source['name'];
    $json_feed_url = $source['json_feed'];

    logMessage("<BR><BR>========================================");
    logMessage("<BR>Processing Source: $source_name (ID: $source_id)");
    logMessage("<BR>Feed URL: $json_feed_url");
    logMessage("<BR>========================================<BR>");

    // جلب البيانات من JSON feed
    $jsonData = false;
    $downloadResult = downloadFile($json_feed_url); // Use downloadFile to mimic browser
    if ($downloadResult !== false) {
        $jsonData = $downloadResult['data'];
    }

    if ($jsonData === false) {
        logError($source_name, 'FEED_FETCH_ERROR', "Failed to fetch JSON feed from: $json_feed_url");
        return ['processed' => 0, 'errors' => 1];
    }

    $data = json_decode($jsonData, true);

    if (json_last_error() !== JSON_ERROR_NONE) {
        logError($source_name, 'JSON_PARSE_ERROR', "Failed to parse JSON: " . json_last_error_msg());
        return ['processed' => 0, 'errors' => 1];
    }

    if (!isset($data['items']) || !is_array($data['items'])) {
        logError($source_name, 'INVALID_JSON_STRUCTURE', "JSON does not contain 'items' array");
        return ['processed' => 0, 'errors' => 1];
    }

    $items = $data['items'];
    $totalItems = count($items);
    $processedCount = 0;
    $skippedCount = 0;
    $errorCount = 0;
    $photosDownloaded = 0;
    $videosDownloaded = 0;

    logMessage("<BR>Found $totalItems items in feed<BR>");

    foreach ($items as $index => $item) {
        try {
            $itemUrl = $item['url'] ?? '';

            if (empty($itemUrl)) {
                logError($source_name, 'MISSING_URL', "Item " . ($index + 1) . " has no URL");
                $errorCount++;
                continue;
            }

            // استخراج Post ID (Twitter أو YouTube)
            $postId = getPostId($itemUrl);

            // التحقق من وجود المنشور مباشرة
            if (postExists($db, $postId)) {
                $skippedCount++;
                continue;
            }

            logMessage("<BR><BR>Processing item " . ($index + 1) . "/$totalItems");
            logMessage("<BR>Post ID: $postId");
            logMessage("<BR>URL: $itemUrl");

            // استخراج البيانات
            $title = $item['title'] ?? '';
            $contentHtml = $item['content_html'] ?? '';
            $contentText = strip_tags($contentHtml);
            $contentText = cleanTwitterLinks($contentText);
            $contentText = removePicWord($contentText);
            $publishDate = isset($item['date_published']) ? convertToEgyptTime($item['date_published']) : date('Y-m-d H:i:s');

            // استخراج الصور من مصادر متعددة
            $attachments = $item['attachments'] ?? [];

            // إذا لم توجد attachments، حاول استخراج من image field
            if (empty($attachments) && isset($item['image'])) {
                $attachments[] = ['url' => $item['image']];
            }

            // استخراج صور إضافية من content_html (حتى لو كان هناك attachments)
            // لأن RSS قد لا يحتوي على جميع الصور في attachments
            if (!empty($contentHtml)) {
                // استخراج الصور من img tags
                preg_match_all('/<img[^>]+src="([^"]+)"/', $contentHtml, $imgMatches);
                if (!empty($imgMatches[1])) {
                    foreach ($imgMatches[1] as $imgUrl) {
                        // تجنب التكرار
                        $exists = false;
                        foreach ($attachments as $att) {
                            if (isset($att['url']) && $att['url'] === $imgUrl) {
                                $exists = true;
                                break;
                            }
                        }
                        if (!$exists) {
                            $attachments[] = ['url' => $imgUrl];
                        }
                    }
                }

                // استخراج من poster attribute في video
                preg_match('/poster="([^"]+)"/', $contentHtml, $posterMatch);
                if (!empty($posterMatch[1])) {
                    $exists = false;
                    foreach ($attachments as $att) {
                        if (isset($att['url']) && $att['url'] === $posterMatch[1]) {
                            $exists = true;
                            break;
                        }
                    }
                    if (!$exists) {
                        $attachments[] = ['url' => $posterMatch[1]];
                    }
                }

                // استخراج روابط Twitter media (pbs.twimg.com)
                preg_match_all('/https:\/\/pbs\.twimg\.com\/media\/[^\s"\'<>]+/', $contentHtml, $twitterMediaMatches);
                if (!empty($twitterMediaMatches[0])) {
                    foreach ($twitterMediaMatches[0] as $mediaUrl) {
                        // تجنب التكرار
                        $exists = false;
                        foreach ($attachments as $att) {
                            if (isset($att['url']) && $att['url'] === $mediaUrl) {
                                $exists = true;
                                break;
                            }
                        }
                        if (!$exists) {
                            $attachments[] = ['url' => $mediaUrl];
                        }
                    }
                }
            }

            logMessage("<BR>Attachments found: " . count($attachments));
            if (!empty($attachments)) {
                logMessage("<BR>Attachments details: " . json_encode($attachments));
            }

            $attachmentsJson = !empty($attachments) ? json_encode($attachments) : null;

            // معالجة الميديا (صور وفيديو)
            $media = processMedia($attachments, $uploads_dir, $media_dir, $itemUrl, $contentHtml, $postId, $source_name);

            // إحصائيات
            if ($media['photos_count'] > 0)
                $photosDownloaded += $media['photos_count'];
            if ($media['video'] !== null)
                $videosDownloaded++;

            // تحديد نوع المحتوى
            $contentType = getContentType(
                $media['photo'] !== null,
                $media['video'] !== null,
                $itemUrl,
                $contentText,
                $media['photos_count']
            );

            // تحضير البيانات للإدخال
            $postData = [
                'post_id' => $postId,
                'url' => $itemUrl,
                'title' => $title,
                'content_text' => $contentText,
                'content_html' => $contentHtml,
                'photo' => $media['photo'],
                'photos_count' => $media['photos_count'],
                'video_url' => $media['video'],
                'file_size' => $media['video_size'],
                'attachments' => $attachmentsJson,
                'content_type' => $contentType,
                'cat_sources' => $source_id,
                'publish_date' => $publishDate,
                'source_name' => $source_name
            ];

            // إدخال في قاعدة البيانات
            $recordId = insertPost($db, $postData);

            if ($recordId) {
                logMessage("<BR>Post inserted successfully with ID: $recordId", "SUCCESS");
                $processedCount++;
            } else {
                logError($source_name, 'INSERT_FAILED', "Failed to insert post", $postId);
                $errorCount++;
            }

        } catch (Exception $e) {
            logError($source_name, 'PROCESSING_ERROR', "Exception: " . $e->getMessage(), $postId ?? 'UNKNOWN');
            $errorCount++;
        }
    }

    // تحديث وقت آخر جلب
    updateSourceFetchTime($db, $source_id);

    // حساب وقت التنفيذ
    $sourceEndTime = microtime(true);
    $sourceExecutionTime = round($sourceEndTime - $sourceStartTime, 2);

    // تسجيل تفاصيل المصدر في قاعدة البيانات
    if ($logId) {
        try {
            $status = 'success';
            if ($errorCount > 0 && $processedCount > 0)
                $status = 'partial';
            elseif ($errorCount > 0 && $processedCount == 0)
                $status = 'failed';

            $stmt = $db->prepare("
                INSERT INTO rss_source_logs 
                (log_id, source_id, source_name, items_found, items_processed, items_skipped, items_errors, 
                 photos_downloaded, videos_downloaded, execution_time, status)
                VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
            ");
            $stmt->execute([
                $logId,
                $source_id,
                $source_name,
                $totalItems,
                $processedCount,
                $skippedCount,
                $errorCount,
                $photosDownloaded,
                $videosDownloaded,
                $sourceExecutionTime,
                $status
            ]);
        } catch (PDOException $e) {
            // تجاهل
        }
    }

    logMessage("<BR><BR>Source '$source_name' Summary:");
    logMessage("<BR>- Total items: $totalItems");
    logMessage("<BR>- Processed: $processedCount");
    logMessage("<BR>- Skipped (already exists): $skippedCount");
    logMessage("<BR>- Errors: $errorCount");
    logMessage("<BR>- Photos downloaded: $photosDownloaded");
    logMessage("<BR>- Videos downloaded: $videosDownloaded");

    return [
        'processed' => $processedCount,
        'skipped' => $skippedCount,
        'errors' => $errorCount
    ];
}

// ============================================
// الحلقة الرئيسية
// ============================================

// جلب المصادر النشطة
$sources = getActiveSources($db, $MAX_SOURCES_PER_RUN);
$totalSources = count($sources);

logMessage("<BR>Found $totalSources active source(s) to process<BR>");

if ($totalSources === 0) {
    logMessage("<BR>No sources to process. Exiting.<BR>");
    exit(0);
}

$totalProcessed = 0;
$totalSkipped = 0;
$totalErrors = 0;

foreach ($sources as $source) {
    $result = processSource($db, $source, $uploads_dir, $media_dir, $logId);
    $totalProcessed += $result['processed'];
    $totalSkipped += $result['skipped'] ?? 0;
    $totalErrors += $result['errors'];
}

// ============================================
// ملخص التنفيذ
// ============================================
$endTime = microtime(true);
$executionTime = round($endTime - $startTime, 2);

// تحديث سجل قاعدة البيانات
if ($logId) {
    try {
        $stmt = $db->prepare("
            UPDATE rss_logs 
            SET total_sources = ?, 
                total_processed = ?, 
                total_skipped = ?, 
                total_errors = ?, 
                execution_time = ?, 
                status = 'completed'
            WHERE id = ?
        ");
        $stmt->execute([
            $totalSources,
            $totalProcessed,
            $totalSkipped,
            $totalErrors,
            $executionTime,
            $logId
        ]);
    } catch (PDOException $e) {
        // تجاهل
    }
}

logMessage("<BR><BR>========================================");
logMessage("<BR>FINAL SUMMARY");
logMessage("<BR>========================================");
logMessage("<BR>Sources processed: $totalSources");
logMessage("<BR>Posts inserted: $totalProcessed");
logMessage("<BR>Posts skipped: $totalSkipped");
logMessage("<BR>Errors: $totalErrors");
logMessage("<BR>Execution time: {$executionTime}s");
logMessage("<BR>========================================<BR>");

// حفظ السجلات
$logFile = __DIR__ . '/rss_log_' . date('Y-m-d') . '.txt';
file_put_contents($logFile, implode("\n", $logMessages), FILE_APPEND);

logMessage("<BR>Log saved to: $logFile<BR>");
logMessage("<BR>Cronjob completed successfully!<BR>");

// إذا كان AJAX request، أرجع JSON response
if ($isAjax) {
    header('Content-Type: application/json');
    echo json_encode([
        'success' => true,
        'processed' => $totalProcessed,
        'skipped' => $totalSkipped,
        'errors' => $totalErrors,
        'sources' => $totalSources,
        'execution_time' => $executionTime
    ]);
}

file_put_contents($logFile, date('Y-m-d H:i:s') . " - Script finished successfully\n\n", FILE_APPEND);
