Files
Siro/backend/intaleq_v1_secure_latest.md
2026-06-11 13:47:40 +03:00

1.2 MiB
Raw Blame History

Siro V1 - Secure Latest Version

File: functions.php

<?php
//functions.php

use Firebase\JWT\JWT;
use Firebase\JWT\Key;
use Firebase\JWT\ExpiredException;
use Firebase\JWT\SignatureInvalidException;
use Firebase\JWT\BeforeValidException;


$INTERNAL_KEY = trim(file_get_contents('/home/siro-api/.internal_socket_key'));


/**
 * دالة البحث الهجين (Redis + MySQL)
 * @param $redis Client  : اتصال الريدز
 * @param $con   PDO     : اتصال قاعدة البيانات الرئيسية (Main DB)
 * @param $lat   float   : إحداثيات الراكب
 * @param $lng   float   : إحداثيات الراكب
 * @param $carType string: نوع الطلب (comfort, speed, Lady...)
 */

function sendToLocationServer($action, $data) {
    // رابط سيرفر اللوكيشن الداخلي أو العام
    $url = "http://location.intaleq.xyz:2021"; 
    $INTERNAL_KEY = trim(@file_get_contents('/home/siro-api/.internal_socket_key'));

    $postData = [
        'action' => $action,
        ...$data
    ];

    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_POST, 1);
    curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData));
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_TIMEOUT_MS, 500); // سريع جداً
    curl_setopt($ch, CURLOPT_HTTPHEADER, ["x-internal-key: $INTERNAL_KEY"]);
    curl_exec($ch);
    curl_close($ch);
}

function findBestDrivers($con, $lat, $lng, $carType) {
    // 1. الاتصال بـ Redis لجلب الأقرب
    $locationServerUrl = "https://location.intaleq.xyz/api_get_nearby.php";
    $INTERNAL_KEY = trim(@file_get_contents('/home/siro-api/.internal_socket_key'));

    $postData = ['lat' => $lat, 'lng' => $lng, 'radius' => 5, 'limit' => 100];

    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $locationServerUrl);
    curl_setopt($ch, CURLOPT_POST, 1);
    curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData));
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_TIMEOUT, 3);
    curl_setopt($ch, CURLOPT_HTTPHEADER, ["x-internal-key: $INTERNAL_KEY"]);
    
    $response = curl_exec($ch);
    $info = curl_getinfo($ch);
    curl_close($ch);

    if ($info['http_code'] !== 200) return [];

    $json = json_decode($response, true);
    $nearbyDrivers = ($json['status'] ?? false) ? $json['data'] : [];

    if (empty($nearbyDrivers)) return [];

    // 2. تجهيز البيانات للفلترة
    $driverIds = [];
    $redisMap = [];
    foreach ($nearbyDrivers as $d) {
        $driverIds[] = $d['id'];
        $redisMap[$d['id']] = $d; 
    }

    $placeholders = implode(',', array_fill(0, count($driverIds), '?'));
    
    // تعريف الثوابت
    $CAT_CAR = 1; $CAT_BIKE = 2; $CAT_VAN = 3; $FUEL_ELECTRIC = 3;

    // 3. الاستعلام (بدون platform)
    $sql = "SELECT 
                d.id AS driver_id,
                dt.token,
                cr.year,
                cr.vehicle_category_id,
                d.gender
            FROM driver d
            JOIN CarRegistration cr ON cr.driverID = d.id
            JOIN driverToken dt ON dt.captain_id = d.id
            WHERE d.id IN ($placeholders) ";

    $carType = trim($carType);
    switch ($carType) {
        case 'Comfort': 
            $sql .= " AND cr.vehicle_category_id = $CAT_CAR AND CAST(TRIM(cr.year) AS UNSIGNED) > 2017 "; 
            break;
        case 'Mishwar Vip': 
            $sql .= " AND cr.vehicle_category_id = $CAT_CAR AND CAST(TRIM(cr.year) AS UNSIGNED) > 2020 "; 
            break;
        case 'Scooter': 
        case 'Pink Bike': 
            $sql .= " AND cr.vehicle_category_id = $CAT_BIKE "; 
            break;
        case 'Electric': 
            $sql .= " AND cr.vehicle_category_id = $CAT_CAR AND cr.fuel_type_id = $FUEL_ELECTRIC "; 
            break;
        case 'Lady': 
             $femaleHash = 'bQ6yWJ2EVXKZooHdGclvmFiDlZCM8UYeO+ILFjDUvpQ='; 
             $sql .= " AND cr.vehicle_category_id = $CAT_CAR AND d.gender = '$femaleHash' "; 
             break;
        case 'Van': 
            $sql .= " AND cr.vehicle_category_id = $CAT_VAN "; 
            break;
        case 'Awfar Car': 
             $sql .= " AND cr.vehicle_category_id = $CAT_CAR AND CAST(TRIM(cr.year) AS UNSIGNED) > 1995 "; 
             break;
        case 'Fixed Price':
        case 'Speed':
        case 'Rayeh Gai': 
        default: 
            $sql .= " AND cr.vehicle_category_id = $CAT_CAR AND CAST(TRIM(cr.year) AS UNSIGNED) > 2000 "; 
            break;
    }

    try {
        $stmt = $con->prepare($sql);
        $stmt->execute($driverIds);
        $finalDrivers = $stmt->fetchAll(PDO::FETCH_ASSOC);

        // دمج البيانات
        foreach ($finalDrivers as &$driver) {
            $did = $driver['driver_id'];
            if (isset($redisMap[$did])) {
                $driver['distance_km'] = $redisMap[$did]['distance'];
                $driver['lat'] = $redisMap[$did]['lat'];
                $driver['lng'] = $redisMap[$did]['lng'];
            } else {
                $driver['distance_km'] = 999;
            }
        }

        // الترتيب
        usort($finalDrivers, function($a, $b) {
            return $a['distance_km'] <=> $b['distance_km'];
        });

        return array_slice($finalDrivers, 0, 30);
    } catch (Exception $e) {
        error_log("FindBestDrivers Error: " . $e->getMessage());
        return [];
    }
}
// --- دالة مساعدة لمخاطبة سيرفر السائقين (Location Socket) ---
function notifyDriversRideTaken($rideId, $winnerDriverId) {
    // رابط سيرفر السائقين الداخلي (نفس البورت المستخدم في driver_socket.php)
    $url = getenv('LOCATION_SOCKET_URL');
    if (!$url) throw new RuntimeException('LOCATION_SOCKET_URL not configured');
    $INTERNAL_KEY = trim(@file_get_contents('/home/siro-api/.internal_socket_key'));

    $postData = [
        'action' => 'ride_taken_event', // هذا الأكشن الجديد في السوكيت
        'ride_id' => $rideId,
        'taken_by_driver_id' => $winnerDriverId
    ];

    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_POST, 1);
    curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData));
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_TIMEOUT_MS, 500); // نصف ثانية فقط، لا نريد تعطيل الـ API
    curl_setopt($ch, CURLOPT_HTTPHEADER, ["x-internal-key: $INTERNAL_KEY"]);
    
    $response = curl_exec($ch);
    curl_close($ch);
}
function notifyDriversOnLocationServer($drivers_ids_array, $payload, $rideId = null) {
    // رابط سيرفر اللوكيشن الخارجي
    $url = getenv('LOCATION_SOCKET_URL');
    if (!$url) throw new RuntimeException('LOCATION_SOCKET_URL not configured');
    $INTERNAL_KEY = trim(@file_get_contents('/home/siro-api/.internal_socket_key'));

    $postData = [
        'action'      => 'dispatch_order', // اسم الحدث المتفق عليه في socket_server.php هناك
        'drivers_ids' => json_encode($drivers_ids_array), // نحول المصفوفة لنص JSON
        'ride_id'     => $rideId ?? '', // ✅ تصحيح اسم المتغير
        'payload'     => $payload
    ];

    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_POST, 1);
    curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData));
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_TIMEOUT_MS, 1000); // لا تنتظر أكثر من ثانية
    curl_setopt($ch, CURLOPT_HTTPHEADER, [
        "x-internal-key: $INTERNAL_KEY"
    ]);

    $response = curl_exec($ch);

    if (curl_errno($ch)) {
        error_log("Curl Error (Location Socket): " . curl_error($ch));
    }

    curl_close($ch);
    return $response;
}

/**
 * 🚀 دالة إشعار الراكب (تعمل على سيرفر الرحلات)
 * تخاطب السوكيت الموجود محلياً على نفس السيرفر
 */
function notifyPassengerOnRideServer($passenger_id, $payload) {
    // الرابط المحلي لسيرفر سوكيت الركاب
    $url = getenv('PASSENGER_SOCKET_URL');
    if (!$url) {
        error_log("[FATAL] PASSENGER_SOCKET_URL not configured");
        throw new RuntimeException('PASSENGER_SOCKET_URL not configured');
    }
    $INTERNAL_KEY = trim(@file_get_contents('/home/siro-api/.internal_socket_key'));

    $postData = [
        'action'       => 'update_ride_status',
        'passenger_id' => $passenger_id,
        'payload'      => $payload
    ];

    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_POST, 1);
    curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData));
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_TIMEOUT_MS, 1000); 
    curl_setopt($ch, CURLOPT_HTTPHEADER, [
        "x-internal-key: $INTERNAL_KEY"
    ]);

    $response = curl_exec($ch);
    
    if (curl_errno($ch)) {
        error_log("Curl Error (Passenger Socket): " . curl_error($ch));
    }
    
    curl_close($ch);
    return $response;
}

// ============================================================================
// دالة توزيع الطلب (محدثة لاستخدام sendFCM_Internal)
// ============================================================================
// ============================================================================
// دالة توزيع الطلب (Dispatch Function) - النسخة المصححة
// ============================================================================
function dispatchRideToDrivers($driversData, $rideId, $payloadTemplate, $startNameLoc, $encryptionHelper) {
    $countDrivers = count($driversData);
    error_log("🚀 [DISPATCH_START] RideID: $rideId | Drivers Count: $countDrivers");

    $socketUrl = getenv('LOCATION_SOCKET_URL');
    if (!$socketUrl) throw new RuntimeException('LOCATION_SOCKET_URL not configured');
    
    $internalKeyPath = '/home/siro-api/.internal_socket_key';
    $internalKey = file_exists($internalKeyPath) ? trim(file_get_contents($internalKeyPath)) : '';

    foreach ($driversData as $driver) {
        $driverId = $driver['driver_id'];
        $rawToken = $driver['token'] ?? ''; 
        
        error_log("--------------------------------------------------");
        error_log("👤 [DRIVER_PROCESS] Processing Driver ID: $driverId");

        // 1. معالجة التوكن
        $driverToken = processDriverToken($rawToken, $encryptionHelper);

        // تجهيز البيانات الخاصة بالسائق
        $payloadForDriver = $payloadTemplate;
        $payloadForDriver[6]  = (string)$driverId;
        $payloadForDriver[18] = (string)$driverId; 

        // 2. إرسال السوكيت
        sendSocketNotification($driverId, $rideId, $payloadForDriver, $socketUrl, $internalKey);

        // 3. إرسال FCM
        if (!empty($driverToken)) {
            $fcmData = [
                'DriverList' => $payloadForDriver,
                'order_id'   => (string)$rideId
            ];
            $fcmResult = sendFcmNotification(
                $driverToken, 
                "طلب جديد 🔔", 
                "هناك رحلة جديدة من " . $startNameLoc, 
                $fcmData, 
                "Order", 
                "ding"
            );
            error_log("📲 [FCM_RESULT] " . json_encode($fcmResult));
        } else {
            error_log("⚠️ [FCM_SKIP] No valid token for Driver $driverId");
        }
    }
    error_log("🏁 [DISPATCH_END] RideID: $rideId");
}

/**
 * معالجة توكن السائق وفك تشفيره
 */
function processDriverToken($rawToken, $encryptionHelper) {
    if (empty($rawToken)) {
        error_log("🚫 [TOKEN_MISSING] No token found.");
        return '';
    }
    try {
        $decrypted = $encryptionHelper->decryptData($rawToken);
        if ($decrypted !== false && !empty($decrypted)) {
            error_log("✅ [TOKEN_DECRYPT] Success.");
            return trim($decrypted);
        }
        error_log("⚠️ [TOKEN_DECRYPT] Failed. Using Raw.");
        return $rawToken;
    } catch (Exception $e) {
        error_log("❌ [TOKEN_EXCEPTION] Error. Using Raw.");
        return $rawToken;
    }
}

/**
 * إرسال إشعار السوكيت لسيرفر اللوكيشن
 */
function sendSocketNotification($driverId, $rideId, $payload, $url, $internalKey) {
    $postData = [
        'action' => 'dispatch_order',
        'drivers_ids' => json_encode([$driverId]),
        'ride_id' => $rideId,
        'payload' => $payload
    ];

    $ch = curl_init($url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData));
    if (!empty($internalKey)) curl_setopt($ch, CURLOPT_HTTPHEADER, ["x-internal-key: $internalKey"]);
    curl_setopt($ch, CURLOPT_TIMEOUT, 1);
    curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 1);
    
    $res = curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);

    error_log("📡 [SOCKET_SEND] Driver $driverId | HTTP: $httpCode");
}

/**
 * إرسال إشعار FCM الموحد
 */
function sendFcmNotification($token, $title, $body, $data, $category, $tone) {
    if (class_exists('FcmService')) {
        global $redis;
        $fcmService = new FcmService($redis ?? null);
        return $fcmService->send($token, $title, $body, $data, $category, $tone);
    } elseif (function_exists('sendFCM_Internal')) {
        return sendFCM_Internal($token, $title, $body, $data, $category, false, $tone);
    }
    return ['status' => 'error', 'message' => 'FCM service not loaded'];
}



// ═══════════════════════════════════════════════════════════════
// authenticateJWT() — النسخة النهائية الكاملة
// ───────────────────────────────────────────────────────────────
// قائمة allowedFiles مبنية على هيكل الملفات الفعلي:
//   siro_v1/          ← الجذر
//   siro_v1/auth/     ← مشترك راكب/سائق
//   siro_v1/auth/syria/   ← تسجيل سوريا
//   siro_v1/auth/captin/  ← تسجيل السائق
// ═══════════════════════════════════════════════════════════════

function authenticateJWT(): object
{
    $secretKey  = trim(file_get_contents('/home/siro-api/.secret_key'));
    $hmacSecret = getenv('SECRET_KEY_HMAC');
    $fpPepper   = getenv('FP_PEPPER');

    if (!$secretKey || !$hmacSecret) {
        http_response_code(500);
        echo json_encode(['error' => 'Internal server configuration error.']);
        exit;
    }

    // ── 1. استخراج الـ JWT من Authorization header ─────────────
    $authHeader = $_SERVER['HTTP_AUTHORIZATION'] ?? '';
    $token      = null;

    if (preg_match('/Bearer\s(\S+)/', $authHeader, $matches)) {
        $token = $matches[1];
    }

    if (!$token) {
        http_response_code(401);
        echo json_encode(['error' => 'Authorization token required']);
        exit;
    }

    // ── 2. فك التشفير والتحقق من التوقيع والصلاحية ─────────────
    try {
        $decoded = JWT::decode($token, new Key($secretKey, 'HS256'));

    } catch (ExpiredException $e) {
        http_response_code(401);
        echo json_encode(['error' => 'Token expired']);
        exit;

    } catch (SignatureInvalidException $e) {
        http_response_code(401);
        echo json_encode(['error' => 'Invalid token signature']);
        exit;

    } catch (BeforeValidException $e) {
        http_response_code(401);
        echo json_encode(['error' => 'Token not yet valid']);
        exit;

    } catch (Exception $e) {
        http_response_code(401);
        echo json_encode(['error' => 'Invalid token']);
        exit;
    }

    // ── 3. التحقق من الـ Issuer ─────────────────────────────────
    $expectedIssuer = getenv('APP_ISSUER') ;
    if (($decoded->iss ?? '') !== $expectedIssuer) {
        http_response_code(401);
        echo json_encode(['error' => 'Invalid token issuer']);
        exit;
    }

    // استخراج user_id من الـ payload
    $userId = $decoded->user_id ?? $decoded->sub ?? null;
    if (!$userId) {
        http_response_code(401);
        echo json_encode(['error' => 'Invalid JWT payload']);
        exit;
    }

    // ── 4. فحص token_type ───────────────────────────────────────
    // توكن التسجيل (loginFirstTime) نوعه 'registration'
    // مدته 150 ثانية فقط ومقيّد بـ endpoints التسجيل
    // ───────────────────────────────────────────────────────────
    // ── 4. فحص token_type ───────────────────────────────────────
    $tokenType = $decoded->token_type ?? 'access';

    // حل مؤقت: دمج صلاحيات 'registration' و 'new' على نفس القائمة البيضاء
    if ($tokenType === 'registration' || $tokenType === 'new') {

        $allowedFiles = [
            'loginFirstTime',
            'loginFirstTimeDriver',
            'checkPhoneNumberISVerfiedDriver',
            'checkPhoneNumberISVerfiedPassenger',
            'loginFromGooglePassenger',
            'otpmessage',
            'signup',
            'verifyEmail',
            'verifyOtpMessage',
            'sendVerifyEmail',
            'sendWhatsAppDriver',
            'register_passenger',
            'sendWhatsOpt',
            'verifyOtp',
            'auth_proxy',
            'addToken',
            'loginFromGoogle',
            'loginUsingCredentialsWithoutGoogle',
            'register',
            'sendOtpMessageDriver',
            'getTokensPassenger',
            'send_otp',
            'verify_otp',
        ];

        $currentFile = basename($_SERVER['PHP_SELF'], '.php');
        $isAllowed   = false;

        foreach ($allowedFiles as $allowed) {
            if (strcasecmp($currentFile, $allowed) === 0) {
                $isAllowed = true;
                break;
            }
        }

        if (!$isAllowed) {
            error_log(sprintf(
                '⚠️ [SECURITY] Auth token blocked | type=%s | file=%s | user=%s | IP=%s',
                $tokenType,
                $currentFile,
                $userId,
                $_SERVER['REMOTE_ADDR'] ?? 'unknown'
            ));
            http_response_code(403);
            echo json_encode(['error' => 'Token not authorized for this action']);
            exit;
        }
    }

    // ── 5. التحقق من بصمة الجهاز ───────────────────────────────
    // Flutter يرسل fp_encrypted في X-Device-FP header
    // السيرفر يحسب: sha256(fp_encrypted + FP_PEPPER)
    // يقارنه مع JWT.fingerPrint المخزن عند تسجيل الدخول
    // ───────────────────────────────────────────────────────────
    // backward compatibility:
    //   توكنات قبل الأبديت ليس فيها fingerPrint → نسمح مؤقتاً
    //   بعد انتهاء كل التوكنات القديمة (15 دقيقة من النشر)
    //   احذف الشرط الداخلي واجعل الفحص إلزامياً دائماً
    // ───────────────────────────────────────────────────────────
    if ($fpPepper) {
        $fpInToken = $decoded->fingerPrint ?? null;
        $fpHeader  = $_SERVER['HTTP_X_DEVICE_FP'] ?? null;

        if ($fpInToken === null || $fpHeader === null) {
            error_log(sprintf('⚠️ [SECURITY] Fingerprint missing | user=%s', $userId));
            http_response_code(403);
            echo json_encode(['error' => 'Device verification required']);
            exit;
        }

        $expectedFp = hash('sha256', $fpHeader . $fpPepper);

        if (!hash_equals($expectedFp, $fpInToken)) {
            error_log(sprintf(
                '⚠️ [SECURITY] Device mismatch | user=%s | IP=%s',
                $userId,
                $_SERVER['REMOTE_ADDR'] ?? 'unknown'
            ));
            http_response_code(403);
            echo json_encode(['error' => 'Device mismatch']);
            exit;
        }
    }

    // ── 6. التحقق من الـ HMAC — للـ wallet فقط ─────────────────
    // X-HMAC-Auth موجود فقط في طلبات المحفظة
    // لو موجود → نتحقق منه إلزامياً
    // ───────────────────────────────────────────────────────────
    $hmacHeader = $_SERVER['HTTP_X_HMAC_AUTH'] ?? null;

    if ($hmacHeader !== null) {
        $expectedHmac = hash_hmac('sha256', $userId, $hmacSecret);

        if (!hash_equals($expectedHmac, $hmacHeader)) {
            error_log(sprintf(
                '⚠️ [SECURITY] HMAC mismatch | user=%s | IP=%s',
                $userId,
                $_SERVER['REMOTE_ADDR'] ?? 'unknown'
            ));
            http_response_code(403);
            echo json_encode(['error' => 'Invalid HMAC']);
            exit;
        }
    }

    // ✅ كل التحققات نجحت — نرجع الـ payload
    return $decoded;
}
define("MB", 1048576);

/**
 * Send WhatsApp message using your server's API
 *
 * @param string $to        The recipient phone number (e.g., 96279xxxxxxx)
 * @param string $message   The message to send
 * @return mixed            API response object or false on failure
 */

function sendWhatsAppFromServer($to, $message)
{
    // 1) قائمة السيرفرات المتاحة
    $servers = [
        //"https://botmasa.intaleq.xyz/send",//mayar
      //	"https://botmasa2.intaleq.xyz/send",//shad 
        "https://bot5.intaleq.xyz/send",//ramat bus
      "https://bot3.intaleq.xyz/send",//shahd
      //"https://whatsapp.tripz-egypt.com/send"//tripz
    ];

    // 2) محاولة الإرسال (Primary -> Fallback)
    $response = null;
    $success  = false;

    foreach ($servers as $url) {
        $curl = curl_init();
        curl_setopt_array($curl, [
            CURLOPT_URL => $url,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_TIMEOUT => 3, // مهلة قصيرة للمحاولة
            CURLOPT_CUSTOMREQUEST => "POST",
            CURLOPT_POSTFIELDS => json_encode([
                "to" => $to,
                "message" => $message
            ], JSON_UNESCAPED_UNICODE),
            CURLOPT_HTTPHEADER => ["Content-Type: application/json"],
        ]);

        $response = curl_exec($curl);
        $err = curl_error($curl);
        curl_close($curl);

        if (!$err) {
            $success = true;
            break;
        } else {
            error_log("[sendWhatsAppFromServer] Server $url failed, trying next... Error: $err");
        }
    }

    if (!$success) return false;
    return json_decode($response, true);
}

/*
<?php
function sendWhatsAppFromServer($to, $message)
{
    // بيانات تسجيل الدخول لخدمة CIEDCO SMS
    $username = 'sefertraveling@gmail.com';
    $password = '4c175';
    $senderId = 'ciedco-sms';

    // تحويل النص إلى ترميز URL
    $encodedMessage = urlencode($message);

    // بناء رابط API مع المعاملات المطلوبة
    $url = "http://www.ciedco-sms.net/api/sendsms.php?username={$username}&password={$password}&mno={$to}&msg={$encodedMessage}&sid={$senderId}&fl=0&mt=0";

    // تهيئة cURL
    $curl = curl_init();
    curl_setopt_array($curl, [
        CURLOPT_URL => $url,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_ENCODING => '',
        CURLOPT_MAXREDIRS => 10,
        CURLOPT_TIMEOUT => 0,
        CURLOPT_FOLLOWLOCATION => true,
        CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
        CURLOPT_CUSTOMREQUEST => 'GET',
        CURLOPT_HTTPHEADER => [
            'Content-Type: application/x-www-form-urlencoded'
        ],
    ]);

    // تنفيذ الطلب
    $response = curl_exec($curl);
    $err = curl_error($curl);
    curl_close($curl);

    // التحقق من الأخطاء
    if ($err) {
        error_log("[sendWhatsAppFromServer] cURL Error: $err");
        return false;
    }

    return $response;
}

*/


function debugLog($message) {
    error_log($message);
}

// [DELETED] filterRequest and imageUpload moved to core/helpers.php






function sendFCM_Internal(
    $target,
    $title,
    $body,
    $customData = [],
    $category = 'Order',
    $isTopic = false,
    $tone = 'order'
) {
    // مسار ملف الصلاحيات
    $serviceAccountFile = __DIR__ . '/service-account.json';
    $tokenCacheFile     = sys_get_temp_dir() . '/fcm_access_token.json';

    // 1. الحصول على Access Token من الكاش أو من جوجل
    $accessToken = getCachedAccessToken($serviceAccountFile, $tokenCacheFile);
    if (!$accessToken) {
        error_log("❌ [FCM] Failed to get Access Token.");
        return ['status' => 'error', 'message' => 'Auth Failed'];
    }

    // 2. جلب project_id وبناء رابط FCM
    $creds    = json_decode(file_get_contents($serviceAccountFile), true);
    $projectId = $creds['project_id'];
    $fcmUrl   = "https://fcm.googleapis.com/v1/projects/$projectId/messages:send";

    // ============================================================
    // 3. تجهيز الـ Data Payload الموحد (المهم لـ Flutter)
    // ============================================================
    // نبدأ بالـ customData (مثلاً ride_id, driver_id, ... إلخ)
    $finalData = is_array($customData) ? $customData : [];

    // نضيف الحقول القياسية التي سيقرأها Flutter دائماً
    $finalData['title']    = $title;
    $finalData['body']     = $body;
    $finalData['tone']     = $tone;
    $finalData['category'] = $category; // ✅ الحقل الرسمي الذي يتحقق منه Flutter
    $finalData['type']     = $category; // (اختياري) للتماشي مع أي كود قديم

    // تحويل كل القيم إلى نصوص (شرط FCM: data values must be strings)
    $processedData = [];
    foreach ($finalData as $key => $val) {
        if (is_array($val) || is_object($val)) {
            $processedData[$key] = json_encode($val, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
        } else {
            $processedData[$key] = (string)$val;
        }
    }

    // ============================================================
    // 4. بناء الرسالة: Data-Only (بدون Notification Block)
    // ============================================================
    $messagePayload = [
        'message' => [
            'data' => $processedData, // ✅ كل شيء داخل data فقط

            'android' => [
                'priority' => 'HIGH',
            ],
            'apns' => [
                'headers' => [
                    'apns-priority'  => '10',
                    'apns-push-type' => 'background',
                ],
                'payload' => [
                    'aps' => [
                        'content-available' => 1,
                        // لا نضع alert هنا حتى لا يظهر إشعار نظام تلقائي
                    ],
                ],
            ],
        ],
    ];

    // تحديد المستلم (Token أو Topic)
    if ($isTopic) {
        $messagePayload['message']['topic'] = $target;
    } else {
        $messagePayload['message']['token'] = $target;
    }

    // ============================================================
    // 5. الإرسال عبر CURL
    // ============================================================
    $ch = curl_init($fcmUrl);
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_HTTPHEADER, [
        'Authorization: Bearer ' . $accessToken,
        'Content-Type: application/json; charset=UTF-8',
    ]);
    curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($messagePayload, JSON_UNESCAPED_UNICODE));
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_TIMEOUT, 10);

    $result   = curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);

    if (curl_errno($ch)) {
        $error_msg = curl_error($ch);
        curl_close($ch);
        return ['status' => 'error', 'message' => 'CURL Error: ' . $error_msg];
    }

    curl_close($ch);

    if ($httpCode == 200) {
        return ['status' => 'success', 'response' => json_decode($result, true)];
    } else {
        error_log("❌ [FCM Error] Code: $httpCode | Response: $result");
        return ['status' => 'error', 'code' => $httpCode, 'response' => $result];
    }
}
// --------------------------------------------------------------------------
// دوال مساعدة (Helper Functions)
// --------------------------------------------------------------------------

function getCachedAccessToken($credentialsPath, $cacheFile) {
    global $redis;
    
    // 1. محاولة القراءة من Redis (أسرع وأكثر أماناً)
    if ($redis) {
        $token = $redis->get('fcm:access_token');
        if ($token) return $token;
    }

    // 2. إذا لم يوجد، نطلب واحد جديد
    $newToken = getGoogleAccessToken($credentialsPath);
    
    if ($newToken && $redis) {
        // حفظ في Redis لمدة ساعة (3500 ثانية)
        $redis->setex('fcm:access_token', 3500, $newToken);
    }
    
    return $newToken;
}

function getGoogleAccessToken($credentialsPath) {
    if (!file_exists($credentialsPath)) return null;
    
    $credentials = json_decode(file_get_contents($credentialsPath), true);
    $clientEmail = $credentials['client_email'];
    $privateKey  = $credentials['private_key'];
    
    $now = time();
    $header = rtrim(strtr(base64_encode(json_encode(['alg' => 'RS256', 'typ' => 'JWT'])), '+/', '-_'), '=');
    $claim = rtrim(strtr(base64_encode(json_encode([
        'iss' => $clientEmail,
        'scope' => 'https://www.googleapis.com/auth/firebase.messaging',
        'aud' => 'https://oauth2.googleapis.com/token',
        'exp' => $now + 3600,
        'iat' => $now
    ])), '+/', '-_'), '=');
    
    $signature = '';
    openssl_sign("$header.$claim", $signature, $privateKey, 'SHA256');
    $jwt = "$header.$claim." . rtrim(strtr(base64_encode($signature), '+/', '-_'), '=');
    
    $ch = curl_init("https://oauth2.googleapis.com/token");
    curl_setopt($ch, CURLOPT_POST, 1);
    curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query([
        'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer',
        'assertion' => $jwt
    ]));
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    $res = curl_exec($ch);
    curl_close($ch);
    
    return json_decode($res, true)['access_token'] ?? null;
}





//////////

function   jsonError($message = "none")
{
    echo     json_encode(array("status" => "failure", "message" => $message));
}
function   jsonSuccess($message = "none")
{
    echo     json_encode(array("status" => "success", "message" => $message));
}

function result($count)
{
    if ($count > 0) {
        jsonSuccess();
    } else {
        jsonError();
    }
}

function sendEmail($from,$to, $title, $body)
{
    $header = "From: $from" . "\n" . "CC: $from";
    mail($to, $title, $body, $header);
}

File: uploadImagePortrate.php

<?php
// ============================================================
// uploadImagePortrate.php
// رفع صورة الكابتن بأمان
// ============================================================

require_once __DIR__ . '/connect.php'; // يفترض أنه يستدعي core/bootstrap.php

appLog("🚀 [upload_profile_image.php] بدأ تنفيذ سكربت رفع الصورة");

try {
    // 1. Rate Limiting للرفع
    $limiter = new RateLimiter($redis);
    $limiter->enforce(RateLimiter::identifier($user_id ?? null), 'upload');

    $driverID = filterRequest("driverID");
    appLog("📥 Received driverID: $driverID");

    if (empty($driverID)) {
        jsonError('Driver ID is required.', 400);
    }

    // 2. استخدام دالة الرفع الآمنة (MIME check, random name, 5MB limit)
    $target_dir = __DIR__ . "/portrate_captain_image/";
    $uploadResult = uploadImageSecure('image', $target_dir, $driverID);

    if (!$uploadResult['success']) {
        securityLog("❌ Image upload failed", ['driverID' => $driverID, 'error' => $uploadResult['error']]);
        jsonError($uploadResult['error'], 400);
    }

    $new_filename = $uploadResult['filename'];
    appLog("✅ File moved successfully to: " . $uploadResult['path']);

    // 3. تحديث قاعدة البيانات
    $linkImage = 'https://intaleq.xyz/portrate_captain_image/' . $new_filename;
    $uploadDate = date("Y-m-d H:i:s");
    
    // تأكد من أن الاتصال قادم من connect.php أو اجلبه
    $con = Database::get('main');

    // التحقق من وجود السائق
    $stmt = $con->prepare("SELECT COUNT(*) FROM card_images WHERE driverID = ?");
    $stmt->execute([$driverID]);
    $count = $stmt->fetchColumn();

    if ($count > 0) {
        // تحديث
        $updateSQL = "UPDATE card_images SET upload_date = ?, image_name = ?, link = ? WHERE driverID = ?";
        $updateStmt = $con->prepare($updateSQL);
        $success = $updateStmt->execute([$uploadDate, $new_filename, $linkImage, $driverID]);
    } else {
        // إدخال جديد
        $insertSQL = "INSERT INTO imageProfileCaptain (driverID, image_name, link) VALUES (?, ?, ?)";
        $insertStmt = $con->prepare($insertSQL);
        $success = $insertStmt->execute([$driverID, $new_filename, $linkImage]);
    }

    if ($success) {
        appLog("✅ Record updated for driverID: $driverID");
        jsonSuccess(['file_link' => $linkImage], 'Record updated successfully.');
    } else {
        appLog("❌ Failed to update DB record for driverID: $driverID");
        jsonError('Failed to update record.', 500);
    }

} catch (PDOException $e) {
    securityLog("💥 PDO ERROR in uploadImage", ['error' => $e->getMessage()]);
    jsonError('Database error.', 500);
} catch (Exception $e) {
    securityLog("💥 GENERAL ERROR in uploadImage", ['error' => $e->getMessage()]);
    jsonError('Server error.', 500);
}

File: loginAdmin.php

<?php
// ============================================================
// loginAdmin.php — تسجيل دخول الإدارة
// ============================================================

require_once __DIR__ . '/core/bootstrap.php';

header('Content-Type: application/json');
header("Access-Control-Allow-Origin: " . (getenv('ALLOWED_ORIGIN') ?: '*'));
header("Access-Control-Allow-Methods: POST, OPTIONS");
header("Access-Control-Allow-Headers: Content-Type, Authorization");

if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
    http_response_code(200);
    exit;
}

// ── Rate Limiting ───────────────────────────────────────────
$limiter = new RateLimiter($redis);
$limiter->enforce(RateLimiter::identifier(), 'login');

try {
    $id       = filterRequest('id') ?? '';
    $password = filterRequest('password') ?? '';
    $audience = filterRequest('aud') ?? '';

    $allowed1 = getenv('allowedDriver1');
    $allowed2 = getenv('allowedDriver2');
    $allowedAudiences = array_values(array_filter([$allowed1, $allowed2]));

    if (empty($id) || empty($password) || empty($audience)) {
        jsonError('ID and password are required.', 400);
    }

    if (!in_array($audience, $allowedAudiences, true)) {
        jsonError('Invalid audience.', 400);
    }

    $con = Database::get('main');

    // ── جلب بيانات المشرف ────────────────────────────────────
    // ملاحظة: جدول admin_users سيتم إنشاؤه في Phase 4 (db_improvements.sql)
    $stmt = $con->prepare("SELECT id, password, email, role FROM admin_users WHERE username = :id OR email = :id LIMIT 1");
    $stmt->execute([':id' => $id]);
    $admin = $stmt->fetch();

    $startTime = microtime(true);

    if ($admin && password_verify($password, $admin['password'])) {
        
        $limiter->reset(RateLimiter::identifier(), 'login');
        
        $jwtService = new JwtService($redis);
        
        // استخدام Role المخصص أو 'admin'
        $role = $admin['role'] ?? 'admin';
        
        $jwt = $jwtService->generateAccessToken($admin['id'], $role, $audience);
        $refresh = $jwtService->generateRefreshToken($admin['id']);

        jsonSuccess([
            'jwt' => $jwt,
            'refresh_token' => $refresh['token'],
            'expires_in' => 900
        ]);

    } else {
        // حماية من Timing Attack
        $elapsed = microtime(true) - $startTime;
        if ($elapsed < 0.1) usleep((int)((0.1 - $elapsed) * 1000000));
        
        jsonError('Invalid ID or password.', 401);
    }

} catch (PDOException $e) {
    securityLog("Admin Login PDO Error", ['msg' => $e->getMessage()]);
    jsonError('Login failed: Database error', 500);
} catch (Exception $e) {
    securityLog("Admin Login Error", ['msg' => $e->getMessage()]);
    jsonError('Login failed: Server error', 500);
}

File: schema_primary.sql

-- MySQL dump 10.13  Distrib 8.0.43, for Linux (x86_64)
--
-- Host: localhost    Database: intaleqDB1
-- ------------------------------------------------------
-- Server version	8.0.43-0ubuntu0.22.04.2

/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!50503 SET NAMES utf8mb4 */;
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
/*!40103 SET TIME_ZONE='+00:00' */;
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;

--
-- Table structure for table `CarRegistration`
--

DROP TABLE IF EXISTS `CarRegistration`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `CarRegistration` (
  `id` int NOT NULL AUTO_INCREMENT,
  `driverID` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL,
  `vin` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL,
  `car_plate` varchar(150) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL,
  `make` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL,
  `model` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL,
  `year` int NOT NULL,
  `expiration_date` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `color` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL,
  `owner` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL,
  `color_hex` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `fuel` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL,
  `isDefault` tinyint(1) NOT NULL DEFAULT '0',
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `status` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'yet',
  `vehicle_category_id` tinyint(1) DEFAULT '1',
  `fuel_type_id` tinyint DEFAULT '1',
  PRIMARY KEY (`id`),
  KEY `idx_driverID` (`driverID`)
) ENGINE=InnoDB AUTO_INCREMENT=1796 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `adminUser`
--

DROP TABLE IF EXISTS `adminUser`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `adminUser` (
  `id` int NOT NULL AUTO_INCREMENT,
  `device_number` varchar(300) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `name` varchar(150) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `api_keys`
--

DROP TABLE IF EXISTS `api_keys`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `api_keys` (
  `id` int NOT NULL AUTO_INCREMENT,
  `name` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `hashed_key` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `blacklist_driver`
--

DROP TABLE IF EXISTS `blacklist_driver`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `blacklist_driver` (
  `id` int NOT NULL AUTO_INCREMENT,
  `driver_id` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `phone` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `reason` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT 'Violation',
  `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `canecl`
--

DROP TABLE IF EXISTS `canecl`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `canecl` (
  `id` int NOT NULL AUTO_INCREMENT,
  `driverID` varchar(111) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `passengerID` varchar(111) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `rideID` varchar(111) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `note` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT 'nothing',
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `captains_car`
--

DROP TABLE IF EXISTS `captains_car`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `captains_car` (
  `id` int NOT NULL AUTO_INCREMENT,
  `driverID` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `vin` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `car_plate` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `make` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `model` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `year` varchar(6) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `expiration_date` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `color` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `owner` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `color_hex` char(15) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `address` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `displacement` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `fuel` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `registration_date` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `isDefault` tinyint(1) NOT NULL DEFAULT '0',
  `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `car_plate` (`car_plate`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `carPlateEdit`
--

DROP TABLE IF EXISTS `carPlateEdit`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `carPlateEdit` (
  `id` int NOT NULL AUTO_INCREMENT,
  `driverId` varchar(50) NOT NULL,
  `carPlate` varchar(155) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
  `color` varchar(20) NOT NULL,
  `make` varchar(50) NOT NULL,
  `model` varchar(20) NOT NULL,
  `expiration_date` varchar(50) NOT NULL,
  `owner` varchar(155) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
  `year` int NOT NULL,
  `isEdit` tinyint(1) NOT NULL DEFAULT '0',
  `employee` varchar(30) NOT NULL DEFAULT 'any',
  `createdAt` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `driverId` (`driverId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `car_locations`
--

DROP TABLE IF EXISTS `car_locations`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `car_locations` (
  `driver_id` varchar(100) NOT NULL,
  `latitude` decimal(10,7) NOT NULL,
  `longitude` decimal(10,7) NOT NULL,
  `heading` decimal(10,2) NOT NULL,
  `speed` double(10,3) NOT NULL,
  `distance` decimal(10,2) NOT NULL,
  `status` varchar(6) NOT NULL DEFAULT 'off',
  `carType` varchar(100) NOT NULL DEFAULT 'Awfar',
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `location_point` point NOT NULL /*!80003 SRID 4326 */,
  PRIMARY KEY (`driver_id`),
  KEY `idx_loc_status_time` (`status`,`updated_at`,`latitude`,`longitude`),
  SPATIAL KEY `idx_location_point` (`location_point`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;
/*!40101 SET character_set_client = @saved_cs_client */;
/*!50003 SET @saved_cs_client      = @@character_set_client */ ;
/*!50003 SET @saved_cs_results     = @@character_set_results */ ;
/*!50003 SET @saved_col_connection = @@collation_connection */ ;
/*!50003 SET character_set_client  = utf8mb4 */ ;
/*!50003 SET character_set_results = utf8mb4 */ ;
/*!50003 SET collation_connection  = utf8mb4_0900_ai_ci */ ;
/*!50003 SET @saved_sql_mode       = @@sql_mode */ ;
/*!50003 SET sql_mode              = 'NO_AUTO_VALUE_ON_ZERO' */ ;
DELIMITER ;;
/*!50003 CREATE*/ /*!50017 DEFINER=`siroUserDB1`@`%`*/ /*!50003 TRIGGER `trg_before_insert_car_locations` BEFORE INSERT ON `car_locations` FOR EACH ROW BEGIN
SET NEW.location_point = ST_PointFromText(CONCAT('POINT(', NEW.longitude, ' ', NEW.latitude, ')'), 4326);
END */;;
DELIMITER ;
/*!50003 SET sql_mode              = @saved_sql_mode */ ;
/*!50003 SET character_set_client  = @saved_cs_client */ ;
/*!50003 SET character_set_results = @saved_cs_results */ ;
/*!50003 SET collation_connection  = @saved_col_connection */ ;
/*!50003 SET @saved_cs_client      = @@character_set_client */ ;
/*!50003 SET @saved_cs_results     = @@character_set_results */ ;
/*!50003 SET @saved_col_connection = @@collation_connection */ ;
/*!50003 SET character_set_client  = utf8mb4 */ ;
/*!50003 SET character_set_results = utf8mb4 */ ;
/*!50003 SET collation_connection  = utf8mb4_0900_ai_ci */ ;
/*!50003 SET @saved_sql_mode       = @@sql_mode */ ;
/*!50003 SET sql_mode              = 'NO_AUTO_VALUE_ON_ZERO' */ ;
DELIMITER ;;
/*!50003 CREATE*/ /*!50017 DEFINER=`siroUserDB1`@`%`*/ /*!50003 TRIGGER `trg_before_update_car_locations` BEFORE UPDATE ON `car_locations` FOR EACH ROW BEGIN
IF NEW.latitude <> OLD.latitude OR NEW.longitude <> OLD.longitude THEN
SET NEW.location_point = ST_PointFromText(CONCAT('POINT(', NEW.longitude, ' ', NEW.latitude, ')'), 4326);
END IF;
END */;;
DELIMITER ;
/*!50003 SET sql_mode              = @saved_sql_mode */ ;
/*!50003 SET character_set_client  = @saved_cs_client */ ;
/*!50003 SET character_set_results = @saved_cs_results */ ;
/*!50003 SET collation_connection  = @saved_col_connection */ ;

--
-- Table structure for table `car_tracks`
--

DROP TABLE IF EXISTS `car_tracks`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `car_tracks` (
  `id` int NOT NULL AUTO_INCREMENT,
  `driver_id` varchar(100) NOT NULL,
  `latitude` decimal(10,7) NOT NULL,
  `longitude` decimal(10,7) NOT NULL,
  `heading` float DEFAULT NULL,
  `speed` float DEFAULT NULL,
  `distance` float DEFAULT NULL,
  `status` enum('on','off') DEFAULT 'off',
  `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=10484 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `card_images`
--

DROP TABLE IF EXISTS `card_images`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `card_images` (
  `id` int NOT NULL AUTO_INCREMENT,
  `driverID` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `image_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `upload_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `link` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `carsToWork`
--

DROP TABLE IF EXISTS `carsToWork`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `carsToWork` (
  `id` int NOT NULL AUTO_INCREMENT,
  `owner_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `phone` varchar(70) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `car_number` varchar(77) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `manufacture_year` year DEFAULT NULL,
  `car_model` varchar(77) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `car_type` varchar(77) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `site` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `registration_date` date NOT NULL,
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `complaint`
--

DROP TABLE IF EXISTS `complaint`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `complaint` (
  `id` int NOT NULL AUTO_INCREMENT,
  `ride_id` varchar(255) NOT NULL,
  `passenger_id` varchar(255) DEFAULT NULL,
  `driver_id` varchar(255) DEFAULT NULL,
  `complaint_type` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
  `description` text,
  `date_filed` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  `statusComplaint` enum('Open','In Progress','Resolved') NOT NULL DEFAULT 'Open',
  `resolution` text,
  `passenger_report` text,
  `driver_report` text,
  `cs_solutions` text,
  `fault_determination` varchar(255) DEFAULT NULL,
  `complaint_nature` varchar(255) DEFAULT NULL,
  `date_resolved` timestamp NULL DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `contactEgypt`
--

DROP TABLE IF EXISTS `contactEgypt`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `contactEgypt` (
  `id` int NOT NULL AUTO_INCREMENT,
  `phones` varchar(20) NOT NULL,
  `name` varchar(100) NOT NULL,
  `phones2` varchar(60) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
  `createdAt` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `contactSyria`
--

DROP TABLE IF EXISTS `contactSyria`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `contactSyria` (
  `id` int NOT NULL AUTO_INCREMENT,
  `driverId` varchar(255) NOT NULL COMMENT 'معرّف السائق الذي قام بمزامنة جهة الاتصال',
  `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT 'اسم جهة الاتصال',
  `phone` varchar(50) NOT NULL COMMENT 'رقم هاتف جهة الاتصال',
  `sync_timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'وقت المزامنة',
  PRIMARY KEY (`id`),
  UNIQUE KEY `driver_contact_unique` (`driverId`,`phone`)
) ENGINE=InnoDB AUTO_INCREMENT=83699 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `criminalDocuments`
--

DROP TABLE IF EXISTS `criminalDocuments`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `criminalDocuments` (
  `id` int NOT NULL AUTO_INCREMENT,
  `driverId` varchar(50) NOT NULL,
  `IssueDate` varchar(20) NOT NULL,
  `createdAt` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `InspectionResult` varchar(100) NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `driverId` (`driverId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `driver`
--

DROP TABLE IF EXISTS `driver`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `driver` (
  `idn` int NOT NULL AUTO_INCREMENT,
  `id` varchar(100) NOT NULL,
  `phone` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL,
  `email` varchar(255) NOT NULL,
  `password` varchar(255) NOT NULL,
  `gender` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL DEFAULT 'Male',
  `license_type` varchar(255) DEFAULT NULL,
  `national_number` varchar(255) DEFAULT NULL,
  `name_arabic` varchar(255) DEFAULT NULL,
  `issue_date` date DEFAULT NULL,
  `expiry_date` date DEFAULT NULL,
  `license_categories` varchar(255) DEFAULT NULL,
  `address` text,
  `licenseIssueDate` varchar(50) DEFAULT NULL,
  `status` varchar(20) NOT NULL DEFAULT 'notDeleted',
  `birthdate` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL,
  `site` varchar(255) NOT NULL,
  `first_name` varchar(255) NOT NULL,
  `last_name` varchar(255) NOT NULL,
  `accountBank` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL DEFAULT 'yet',
  `bankCode` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL DEFAULT 'CIB',
  `employmentType` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL,
  `maritalStatus` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL,
  `fullNameMaritial` varchar(255) DEFAULT NULL,
  `expirationDate` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL,
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`idn`),
  UNIQUE KEY `national_number` (`national_number`)
) ENGINE=InnoDB AUTO_INCREMENT=2085 DEFAULT CHARSET=utf8mb3;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `driverToken`
--

DROP TABLE IF EXISTS `driverToken`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `driverToken` (
  `id` int NOT NULL AUTO_INCREMENT,
  `token` varchar(300) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `captain_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `fingerPrint` varchar(155) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  KEY `idx_captain_id` (`captain_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1460 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `driverWallet`
--

DROP TABLE IF EXISTS `driverWallet`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `driverWallet` (
  `id` int NOT NULL AUTO_INCREMENT,
  `driverID` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `paymentID` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `dateCreated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `amount` varchar(5) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `paymentMethod` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `dateUpdated` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `driver_behavior`
--

DROP TABLE IF EXISTS `driver_behavior`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `driver_behavior` (
  `id` int NOT NULL,
  `driver_id` varchar(255) NOT NULL,
  `trip_id` varchar(255) NOT NULL,
  `max_speed` double DEFAULT '0',
  `avg_speed` double DEFAULT '0',
  `hard_brakes` int DEFAULT '0',
  `total_distance` double DEFAULT '0',
  `behavior_score` double DEFAULT '0',
  `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `driver_documents`
--

DROP TABLE IF EXISTS `driver_documents`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `driver_documents` (
  `id` int NOT NULL AUTO_INCREMENT,
  `driverID` varchar(64) NOT NULL,
  `doc_type` varchar(64) NOT NULL,
  `image_name` varchar(255) NOT NULL,
  `link` varchar(512) NOT NULL,
  `upload_date` datetime NOT NULL,
  PRIMARY KEY (`id`),
  KEY `driverID` (`driverID`)
) ENGINE=InnoDB AUTO_INCREMENT=5089 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `driver_gifts`
--

DROP TABLE IF EXISTS `driver_gifts`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `driver_gifts` (
  `id` int NOT NULL AUTO_INCREMENT,
  `driver_id` varchar(70) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `gift_description` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `gift_date` datetime DEFAULT CURRENT_TIMESTAMP,
  `is_claimed` tinyint(1) DEFAULT '0',
  PRIMARY KEY (`id`),
  UNIQUE KEY `driver_id` (`driver_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1377 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `driver_health_assurance`
--

DROP TABLE IF EXISTS `driver_health_assurance`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `driver_health_assurance` (
  `id` int NOT NULL AUTO_INCREMENT,
  `driver_id` varchar(155) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `assured` tinyint(1) DEFAULT '0',
  `date_created` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  `health_insurance_provider` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `driver_id` (`driver_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `driver_orders`
--

DROP TABLE IF EXISTS `driver_orders`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `driver_orders` (
  `id` int NOT NULL AUTO_INCREMENT,
  `driver_id` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `order_id` varchar(99) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL,
  `notes` varchar(200) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL DEFAULT 'nothing',
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `status` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT 'applied',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=286 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `driver_ride_scam`
--

DROP TABLE IF EXISTS `driver_ride_scam`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `driver_ride_scam` (
  `id` int NOT NULL AUTO_INCREMENT,
  `driverID` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `passengerID` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `rideID` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `isDriverCallPassenger` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `dateCreated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=38 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `driversWantWork`
--

DROP TABLE IF EXISTS `driversWantWork`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `driversWantWork` (
  `id` int NOT NULL AUTO_INCREMENT,
  `driver_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `phone` varchar(77) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `national_id` varchar(77) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `birth_date` varchar(77) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `license_type` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `site` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `national_id` (`national_id`),
  UNIQUE KEY `phone` (`phone`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `email_verifications`
--

DROP TABLE IF EXISTS `email_verifications`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `email_verifications` (
  `id` int NOT NULL AUTO_INCREMENT,
  `email` varchar(255) NOT NULL,
  `token` varchar(255) NOT NULL,
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `verified` tinyint(1) NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`),
  UNIQUE KEY `email` (`email`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `employee`
--

DROP TABLE IF EXISTS `employee`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `employee` (
  `id` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `education` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `site` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `phone` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `status` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `phone` (`phone`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `error`
--

DROP TABLE IF EXISTS `error`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `error` (
  `id` int NOT NULL AUTO_INCREMENT,
  `error` varchar(400) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `userId` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `userType` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `phone` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `device` varchar(300) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `details` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci,
  `status` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'new',
  PRIMARY KEY (`id`),
  KEY `idx_error_created_at` (`created_at`),
  KEY `idx_error_phone` (`phone`)
) ENGINE=InnoDB AUTO_INCREMENT=115339 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `feedBack`
--

DROP TABLE IF EXISTS `feedBack`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `feedBack` (
  `id` int NOT NULL AUTO_INCREMENT,
  `passengerId` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `feedBack` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
  `datecreated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `helpCenter`
--

DROP TABLE IF EXISTS `helpCenter`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `helpCenter` (
  `id` int NOT NULL AUTO_INCREMENT,
  `driverID` varchar(89) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `helpQuestion` varchar(300) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL,
  `replay` varchar(400) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'not yet',
  `datecreated` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=72 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `hotels`
--

DROP TABLE IF EXISTS `hotels`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `hotels` (
  `id` int NOT NULL,
  `nameEnglish` varchar(255) DEFAULT NULL,
  `nameArabic` varchar(255) DEFAULT NULL,
  `phone` varchar(20) DEFAULT NULL,
  `countReview` int DEFAULT NULL,
  `rate` float DEFAULT NULL,
  `stars` varchar(50) DEFAULT NULL,
  `address` text,
  `website` varchar(255) DEFAULT NULL,
  `email` varchar(255) DEFAULT NULL,
  `PlusCode` varchar(50) DEFAULT NULL,
  `closeTime` varchar(50) DEFAULT NULL,
  `latitude` decimal(10,6) DEFAULT NULL,
  `longitude` decimal(10,6) DEFAULT NULL,
  `instagram` varchar(255) DEFAULT NULL,
  `facebook` varchar(255) DEFAULT NULL,
  `linkedin` varchar(255) DEFAULT NULL,
  `twitter` varchar(255) DEFAULT NULL,
  `photo` varchar(255) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `imageProfileCaptain`
--

DROP TABLE IF EXISTS `imageProfileCaptain`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `imageProfileCaptain` (
  `id` int NOT NULL AUTO_INCREMENT,
  `driverID` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `image_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `upload_date` datetime DEFAULT CURRENT_TIMESTAMP,
  `link` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=552 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `invites`
--

DROP TABLE IF EXISTS `invites`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `invites` (
  `id` int NOT NULL AUTO_INCREMENT,
  `driverId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `inviterDriverPhone` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `createdAt` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `inviteCode` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `isInstall` tinyint(1) NOT NULL DEFAULT '0',
  `isGiftToken` tinyint(1) NOT NULL DEFAULT '0',
  `expirationTime` datetime NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `inviterDriverId` (`inviterDriverPhone`),
  UNIQUE KEY `inviteCode` (`inviteCode`)
) ENGINE=InnoDB AUTO_INCREMENT=129 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `invitesToPassengers`
--

DROP TABLE IF EXISTS `invitesToPassengers`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `invitesToPassengers` (
  `id` int NOT NULL AUTO_INCREMENT,
  `driverId` varchar(70) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `passengerID` varchar(80) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'yet',
  `inviterPassengerPhone` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `inviteCode` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `expirationTime` datetime NOT NULL,
  `createdAt` datetime DEFAULT CURRENT_TIMESTAMP,
  `isInstall` tinyint(1) DEFAULT '0',
  `isGiftToken` tinyint(1) NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`),
  UNIQUE KEY `inviteCode` (`inviteCode`)
) ENGINE=InnoDB AUTO_INCREMENT=143 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `invoice_records`
--

DROP TABLE IF EXISTS `invoice_records`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `invoice_records` (
  `id` int NOT NULL AUTO_INCREMENT,
  `driverID` int NOT NULL,
  `invoice_number` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `amount` decimal(10,2) DEFAULT NULL,
  `date` date DEFAULT NULL,
  `image_link` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci,
  `created_at` datetime DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=36 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `invoicesAdmin`
--

DROP TABLE IF EXISTS `invoicesAdmin`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `invoicesAdmin` (
  `id` int NOT NULL AUTO_INCREMENT,
  `item_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `amount` decimal(10,2) NOT NULL,
  `image_url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=22 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `kazan`
--

DROP TABLE IF EXISTS `kazan`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `kazan` (
  `id` int NOT NULL AUTO_INCREMENT,
  `country` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `kazan` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `comfortPrice` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `speedPrice` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `familyPrice` varchar(4) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `deliveryPrice` varchar(11) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `freePrice` varchar(11) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `latePrice` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `heavyPrice` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `adminId` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `createdAt` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `naturePrice` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `fuelPrice` varchar(6) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `lisenceDetails`
--

DROP TABLE IF EXISTS `lisenceDetails`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `lisenceDetails` (
  `id` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
  `driverID` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
  `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `licenseClass` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `documentNo` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `address` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `height` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `postalCode` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `sex` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `stateCode` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `expireDate` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `dateOfBirth` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `dateCreated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `documentNo` (`documentNo`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `login_attempts`
--

DROP TABLE IF EXISTS `login_attempts`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `login_attempts` (
  `id` int NOT NULL AUTO_INCREMENT,
  `ip_address` varchar(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `attempt_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=18 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `login_attempts_drivers`
--

DROP TABLE IF EXISTS `login_attempts_drivers`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `login_attempts_drivers` (
  `id` int NOT NULL AUTO_INCREMENT,
  `ip_address` varchar(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `attempt_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `mishwaritrips`
--

DROP TABLE IF EXISTS `mishwaritrips`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `mishwaritrips` (
  `id` int NOT NULL AUTO_INCREMENT,
  `driverId` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `phone` varchar(15) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `gender` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `name_english` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `address` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `religion` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `age` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `startNameAddress` varchar(150) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'none',
  `locationCoordinate` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'none',
  `education` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `license_type` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `national_number` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `car_plate` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `make` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `model` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `color` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `color_hex` char(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `token` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `rating` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `countRide` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `passengerId` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `timeSelected` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `createdAt` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  `status` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT 'pending',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `notesForDriverService`
--

DROP TABLE IF EXISTS `notesForDriverService`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `notesForDriverService` (
  `id` int NOT NULL AUTO_INCREMENT,
  `phone` varchar(70) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
  `note` varchar(250) NOT NULL,
  `editor` varchar(50) NOT NULL,
  `createdAt` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `phone` (`phone`)
) ENGINE=InnoDB AUTO_INCREMENT=1814 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `notesForPassengerService`
--

DROP TABLE IF EXISTS `notesForPassengerService`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `notesForPassengerService` (
  `id` int NOT NULL AUTO_INCREMENT,
  `phone` int NOT NULL,
  `note` varchar(250) NOT NULL,
  `editor` varchar(50) NOT NULL,
  `createdAt` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `notificationCaptain`
--

DROP TABLE IF EXISTS `notificationCaptain`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `notificationCaptain` (
  `id` int NOT NULL AUTO_INCREMENT,
  `driverID` varchar(80) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `title` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL,
  `body` varchar(200) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL,
  `isShown` varchar(6) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'false',
  `isPin` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'unPin',
  `dateCreated` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `notifications`
--

DROP TABLE IF EXISTS `notifications`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `notifications` (
  `id` int NOT NULL AUTO_INCREMENT,
  `title` varchar(111) NOT NULL,
  `body` varchar(265) NOT NULL,
  `passenger_id` varchar(111) NOT NULL,
  `isShown` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL DEFAULT 'false',
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8mb3;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `otp_verification_fingerPrint`
--

DROP TABLE IF EXISTS `otp_verification_fingerPrint`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `otp_verification_fingerPrint` (
  `id` int NOT NULL,
  `phone` varchar(20) NOT NULL,
  `otp` varchar(6) NOT NULL,
  `createdAt` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `packageInfo`
--

DROP TABLE IF EXISTS `packageInfo`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `packageInfo` (
  `id` int NOT NULL AUTO_INCREMENT,
  `platform` varchar(50) NOT NULL,
  `appName` varchar(20) NOT NULL,
  `createdAt` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `version` varchar(10) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `palces11`
--

DROP TABLE IF EXISTS `palces11`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `palces11` (
  `id` int NOT NULL AUTO_INCREMENT,
  `latitude` varchar(50) NOT NULL,
  `longitude` varchar(50) NOT NULL,
  `name` varchar(180) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,
  `name_ar` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,
  `name_en` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,
  `address` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,
  `category` varchar(55) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `location` point DEFAULT NULL,
  PRIMARY KEY (`id`),
  FULLTEXT KEY `idx_fulltext_search` (`name`,`name_ar`,`name_en`,`address`,`category`)
) ENGINE=InnoDB AUTO_INCREMENT=37946 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `passengerWallet`
--

DROP TABLE IF EXISTS `passengerWallet`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `passengerWallet` (
  `id` int NOT NULL AUTO_INCREMENT,
  `passenger_id` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `balance` decimal(10,2) NOT NULL,
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  KEY `passenger_id` (`passenger_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `passenger_blacklist`
--

DROP TABLE IF EXISTS `passenger_blacklist`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `passenger_blacklist` (
  `id` bigint unsigned NOT NULL AUTO_INCREMENT,
  `phone` varchar(150) NOT NULL,
  `phone_normalized` varchar(64) NOT NULL,
  `reason` varchar(255) DEFAULT NULL,
  `expires_at` datetime DEFAULT CURRENT_TIMESTAMP,
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `uq_phone_norm` (`phone_normalized`),
  KEY `idx_expires` (`expires_at`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb3;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `passengerlocation`
--

DROP TABLE IF EXISTS `passengerlocation`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `passengerlocation` (
  `id` int NOT NULL AUTO_INCREMENT,
  `passengerId` varchar(60) NOT NULL,
  `lat` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
  `lng` varchar(20) NOT NULL,
  `rideId` varchar(10) NOT NULL,
  `createdAt` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=725 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `passengers`
--

DROP TABLE IF EXISTS `passengers`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `passengers` (
  `id` varchar(100) NOT NULL,
  `phone` varchar(150) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL,
  `email` varchar(255) NOT NULL,
  `password` varchar(100) NOT NULL,
  `gender` varchar(150) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL,
  `status` varchar(150) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL DEFAULT 'notDeleted',
  `birthdate` varchar(150) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL,
  `site` varchar(255) NOT NULL,
  `first_name` varchar(255) NOT NULL,
  `last_name` varchar(255) NOT NULL,
  `sosPhone` varchar(150) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL DEFAULT 'sos',
  `education` varchar(150) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL DEFAULT 'none',
  `employmentType` varchar(150) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL DEFAULT 'none',
  `maritalStatus` varchar(150) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL DEFAULT 'none',
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `phone` (`phone`,`email`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `payment_tokens`
--

DROP TABLE IF EXISTS `payment_tokens`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `payment_tokens` (
  `id` int NOT NULL AUTO_INCREMENT,
  `token` varchar(255) NOT NULL,
  `driverID` varchar(255) NOT NULL,
  `dateCreated` datetime NOT NULL,
  `amount` decimal(10,2) NOT NULL,
  `isUsed` tinyint(1) DEFAULT '0',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `payment_tokens_passenger`
--

DROP TABLE IF EXISTS `payment_tokens_passenger`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `payment_tokens_passenger` (
  `id` int NOT NULL AUTO_INCREMENT,
  `token` varchar(255) NOT NULL,
  `passengerId` varchar(255) NOT NULL,
  `dateCreated` datetime NOT NULL,
  `amount` decimal(10,2) NOT NULL,
  `isUsed` tinyint(1) DEFAULT '0',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `payments`
--

DROP TABLE IF EXISTS `payments`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `payments` (
  `id` varchar(111) NOT NULL,
  `amount` decimal(10,2) NOT NULL,
  `payment_method` varchar(255) NOT NULL,
  `passengerID` varchar(100) NOT NULL,
  `rideId` varchar(100) NOT NULL,
  `driverID` varchar(100) NOT NULL,
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `isGiven` varchar(20) NOT NULL DEFAULT 'waiting',
  PRIMARY KEY (`id`),
  UNIQUE KEY `rideId` (`rideId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `paymentsDriverPoints`
--

DROP TABLE IF EXISTS `paymentsDriverPoints`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `paymentsDriverPoints` (
  `id` int NOT NULL AUTO_INCREMENT,
  `amount` decimal(10,2) NOT NULL,
  `payment_method` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `driverID` varchar(60) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `created_at` datetime DEFAULT CURRENT_TIMESTAMP,
  `updated_at` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `phone_verification`
--

DROP TABLE IF EXISTS `phone_verification`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `phone_verification` (
  `id` int NOT NULL AUTO_INCREMENT,
  `phone_number` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
  `driverId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT 'yet',
  `email` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT 'yet',
  `token_code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,
  `expiration_time` datetime DEFAULT NULL,
  `is_verified` tinyint(1) DEFAULT '0',
  `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=10531 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `phone_verification_passenger`
--

DROP TABLE IF EXISTS `phone_verification_passenger`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `phone_verification_passenger` (
  `id` int NOT NULL AUTO_INCREMENT,
  `phone_number` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,
  `token` varchar(255) DEFAULT NULL,
  `expiration_time` varchar(255) DEFAULT NULL,
  `verified` tinyint(1) DEFAULT '0',
  `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  `status` varchar(22) NOT NULL DEFAULT 'yet',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=7304 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `places`
--

DROP TABLE IF EXISTS `places`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `places` (
  `id` int NOT NULL AUTO_INCREMENT,
  `latitude` double NOT NULL,
  `longitude` double NOT NULL,
  `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `name_ar` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `name_en` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `address` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `category` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=70783 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `placesEgypt`
--

DROP TABLE IF EXISTS `placesEgypt`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `placesEgypt` (
  `id` int NOT NULL,
  `nameEnglish` varchar(255) DEFAULT NULL,
  `nameArabic` varchar(255) DEFAULT NULL,
  `phone` varchar(20) DEFAULT NULL,
  `countReview` int DEFAULT NULL,
  `rate` float DEFAULT NULL,
  `stars` varchar(50) DEFAULT NULL,
  `address` text,
  `website` varchar(255) DEFAULT NULL,
  `email` varchar(255) DEFAULT NULL,
  `PlusCode` varchar(50) DEFAULT NULL,
  `closeTime` varchar(50) DEFAULT NULL,
  `latitude` decimal(10,6) DEFAULT NULL,
  `longitude` decimal(10,6) DEFAULT NULL,
  `instagram` varchar(255) DEFAULT NULL,
  `facebook` varchar(255) DEFAULT NULL,
  `linkedin` varchar(255) DEFAULT NULL,
  `twitter` varchar(255) DEFAULT NULL,
  `photo` varchar(255) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `promos`
--

DROP TABLE IF EXISTS `promos`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `promos` (
  `id` int NOT NULL AUTO_INCREMENT,
  `promo_code` varchar(14) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `amount` varchar(4) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '0',
  `description` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL,
  `passengerID` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'none',
  `validity_start_date` date DEFAULT NULL,
  `validity_end_date` date DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `passengerID` (`passengerID`)
) ENGINE=InnoDB AUTO_INCREMENT=637 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `promptDriverIDEgypt`
--

DROP TABLE IF EXISTS `promptDriverIDEgypt`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `promptDriverIDEgypt` (
  `id` int NOT NULL AUTO_INCREMENT,
  `type` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `prompt` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `createdAt` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  `updatedAt` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `ratingApp`
--

DROP TABLE IF EXISTS `ratingApp`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `ratingApp` (
  `id` int NOT NULL AUTO_INCREMENT,
  `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `email` varchar(150) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `phone` varchar(80) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `userId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `userType` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `rating` varchar(2) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `comment` varchar(300) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=118 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `ratingDriver`
--

DROP TABLE IF EXISTS `ratingDriver`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `ratingDriver` (
  `id` int NOT NULL AUTO_INCREMENT,
  `passenger_id` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci,
  `driver_id` varchar(33) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `ride_id` int DEFAULT NULL,
  `rating` float DEFAULT NULL,
  `comment` text CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci,
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `ride_id` (`ride_id`),
  KEY `idx_driver_id` (`driver_id`)
) ENGINE=InnoDB AUTO_INCREMENT=46 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `ratingPassenger`
--

DROP TABLE IF EXISTS `ratingPassenger`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `ratingPassenger` (
  `id` int NOT NULL AUTO_INCREMENT,
  `passenger_id` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `driverID` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `rideId` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `rating` float NOT NULL,
  `comment` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci,
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `rideId` (`rideId`)
) ENGINE=InnoDB AUTO_INCREMENT=39 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `ride`
--

DROP TABLE IF EXISTS `ride`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `ride` (
  `id` int NOT NULL AUTO_INCREMENT,
  `start_location` varchar(255) NOT NULL,
  `end_location` varchar(255) NOT NULL,
  `date` date NOT NULL,
  `time` time NOT NULL,
  `endtime` time NOT NULL,
  `price` decimal(10,2) NOT NULL DEFAULT '0.00',
  `passenger_id` varchar(111) NOT NULL,
  `driver_id` varchar(111) NOT NULL,
  `status` varchar(200) NOT NULL DEFAULT 'nothing',
  `paymentMethod` varchar(20) NOT NULL DEFAULT 'Cash',
  `carType` varchar(20) NOT NULL DEFAULT 'Speed',
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `DriverIsGoingToPassenger` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `rideTimeStart` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `rideTimeFinish` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `price_for_driver` decimal(10,2) NOT NULL DEFAULT '0.00',
  `price_for_passenger` decimal(10,2) NOT NULL DEFAULT '0.00',
  `distance` float DEFAULT '0',
  PRIMARY KEY (`id`),
  KEY `passengerfk` (`passenger_id`),
  KEY `driverfk` (`driver_id`)
) ENGINE=InnoDB AUTO_INCREMENT=831 DEFAULT CHARSET=utf8mb3;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `seferWallet`
--

DROP TABLE IF EXISTS `seferWallet`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `seferWallet` (
  `id` int NOT NULL AUTO_INCREMENT,
  `driverId` varchar(100) NOT NULL,
  `passengerId` varchar(100) NOT NULL,
  `amount` varchar(10) NOT NULL,
  `paymentMethod` varchar(50) NOT NULL,
  `token` varchar(100) NOT NULL,
  `createdAt` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `server_locations`
--

DROP TABLE IF EXISTS `server_locations`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `server_locations` (
  `id` int NOT NULL AUTO_INCREMENT,
  `name` varchar(255) NOT NULL,
  `min_latitude` decimal(10,6) NOT NULL,
  `max_latitude` decimal(10,6) NOT NULL,
  `min_longitude` decimal(10,6) NOT NULL,
  `max_longitude` decimal(10,6) NOT NULL,
  `server_link` varchar(255) NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `name` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `smsSender`
--

DROP TABLE IF EXISTS `smsSender`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `smsSender` (
  `id` int NOT NULL AUTO_INCREMENT,
  `senderId` varchar(20) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `test`
--

DROP TABLE IF EXISTS `test`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `test` (
  `id` int NOT NULL AUTO_INCREMENT,
  `name` varchar(22) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `testApp`
--

DROP TABLE IF EXISTS `testApp`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `testApp` (
  `id` int NOT NULL AUTO_INCREMENT,
  `isTest` tinyint(1) NOT NULL,
  `createdAt` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `appPlatform` varchar(20) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `tips`
--

DROP TABLE IF EXISTS `tips`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `tips` (
  `id` int NOT NULL AUTO_INCREMENT,
  `driverID` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `passengerID` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `rideID` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `tipAmount` decimal(10,2) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `token_verification`
--

DROP TABLE IF EXISTS `token_verification`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `token_verification` (
  `id` int NOT NULL AUTO_INCREMENT,
  `phone_number` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `token` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `expiration_time` datetime NOT NULL,
  `verified` tinyint(1) DEFAULT '0',
  `created_at` datetime DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=88 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `token_verification_admin`
--

DROP TABLE IF EXISTS `token_verification_admin`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `token_verification_admin` (
  `id` int NOT NULL AUTO_INCREMENT,
  `phone_number` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `token` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `expiration_time` datetime NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `phone_number` (`phone_number`)
) ENGINE=InnoDB AUTO_INCREMENT=51 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `token_verification_driver`
--

DROP TABLE IF EXISTS `token_verification_driver`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `token_verification_driver` (
  `id` int NOT NULL AUTO_INCREMENT,
  `phone_number` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `token` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `expiration_time` datetime NOT NULL,
  `verified` tinyint(1) NOT NULL DEFAULT '0',
  `created_at` datetime DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2210 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `tokens`
--

DROP TABLE IF EXISTS `tokens`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `tokens` (
  `id` int NOT NULL AUTO_INCREMENT,
  `token` varchar(333) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `passengerID` varchar(80) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `fingerPrint` varchar(250) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `status` varchar(22) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'yet',
  PRIMARY KEY (`id`),
  UNIQUE KEY `passengerID` (`passengerID`)
) ENGINE=InnoDB AUTO_INCREMENT=2604 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `users`
--

DROP TABLE IF EXISTS `users`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `users` (
  `id` varchar(111) NOT NULL,
  `phone` varchar(15) NOT NULL,
  `email` varchar(255) NOT NULL,
  `gender` varchar(10) NOT NULL,
  `password` varchar(100) NOT NULL,
  `birthdate` date NOT NULL,
  `site` varchar(255) NOT NULL,
  `first_name` varchar(255) NOT NULL,
  `last_name` varchar(255) NOT NULL,
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `user_type` varchar(44) NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `email` (`email`),
  UNIQUE KEY `phone` (`phone`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `vehicles`
--

DROP TABLE IF EXISTS `vehicles`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `vehicles` (
  `id` int NOT NULL AUTO_INCREMENT,
  `driverID` varchar(100) NOT NULL,
  `make` varchar(255) NOT NULL,
  `model` varchar(255) NOT NULL,
  `license_plate` varchar(255) NOT NULL,
  `seats` int NOT NULL,
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `license_plate` (`license_plate`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `videos`
--

DROP TABLE IF EXISTS `videos`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `videos` (
  `id` int NOT NULL AUTO_INCREMENT,
  `title` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `description` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `url` varchar(150) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `waitingRides`
--

DROP TABLE IF EXISTS `waitingRides`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `waitingRides` (
  `id` varchar(100) NOT NULL,
  `start_location` varchar(255) NOT NULL,
  `start_lat` decimal(10,7) DEFAULT NULL,
  `start_lng` decimal(10,7) DEFAULT NULL,
  `end_location` varchar(255) NOT NULL,
  `end_lat` decimal(10,7) DEFAULT NULL,
  `end_lng` decimal(10,7) DEFAULT NULL,
  `date` date NOT NULL,
  `time` time NOT NULL,
  `price` decimal(10,2) NOT NULL DEFAULT '0.00',
  `passenger_id` varchar(111) NOT NULL,
  `status` varchar(200) NOT NULL DEFAULT 'nothing',
  `carType` varchar(19) NOT NULL,
  `passengerRate` decimal(10,2) NOT NULL,
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `price_for_passenger` decimal(10,2) NOT NULL DEFAULT '0.00',
  `distance` varchar(255) NOT NULL,
  `duration` varchar(10) NOT NULL DEFAULT '0',
  `payment_method` varchar(10) NOT NULL DEFAULT 'cash',
  `passenger_wallet` varchar(6) NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`),
  KEY `idx_location_status` (`start_lat`,`start_lng`,`status`,`created_at`),
  KEY `idx_status_created` (`status`,`created_at`),
  KEY `idx_passenger` (`passenger_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `welcomeDriverCall`
--

DROP TABLE IF EXISTS `welcomeDriverCall`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `welcomeDriverCall` (
  `id` int NOT NULL AUTO_INCREMENT,
  `driverId` varchar(50) NOT NULL,
  `isCall` tinyint(1) NOT NULL DEFAULT '0',
  `notes` varchar(255) NOT NULL,
  `createdAt` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1648 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `write_argument_after_applied_from_background`
--

DROP TABLE IF EXISTS `write_argument_after_applied_from_background`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `write_argument_after_applied_from_background` (
  `id` int unsigned NOT NULL AUTO_INCREMENT,
  `ride_id` varchar(50) NOT NULL,
  `driver_id` varchar(50) NOT NULL,
  `passenger_id` varchar(50) NOT NULL,
  `passenger_location` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
  `passenger_destination` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
  `duration` varchar(255) NOT NULL,
  `duration_to_passenger` varchar(255) NOT NULL,
  `duration_of_ride` varchar(255) NOT NULL,
  `distance` varchar(255) NOT NULL,
  `total_cost` varchar(255) NOT NULL,
  `payment_amount` varchar(255) NOT NULL,
  `payment_method` enum('visa','cash') NOT NULL,
  `wallet_checked` varchar(255) NOT NULL,
  `has_steps` varchar(255) NOT NULL,
  `step0` varchar(255) DEFAULT NULL,
  `step1` varchar(255) DEFAULT NULL,
  `step2` varchar(255) DEFAULT NULL,
  `step3` varchar(255) DEFAULT NULL,
  `step4` varchar(255) DEFAULT NULL,
  `passenger_wallet_burc` varchar(33) NOT NULL,
  `token_passenger` varchar(255) NOT NULL,
  `name` varchar(100) NOT NULL,
  `phone` varchar(20) NOT NULL,
  `email` varchar(150) NOT NULL,
  `start_name_location` varchar(255) NOT NULL,
  `end_name_location` varchar(255) NOT NULL,
  `car_type` varchar(50) NOT NULL,
  `kazan` varchar(255) NOT NULL,
  `direction_url` text NOT NULL,
  `time_of_order` datetime NOT NULL,
  `total_passenger` varchar(255) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Dumping events for database 'intaleqDB1'
--

--
-- Dumping routines for database 'intaleqDB1'
--
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;

/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;

-- Dump completed on 2026-04-22 19:40:54

File: login.php

<?php
// ============================================================
// login.php — تجديد توكن الراكب
// ============================================================

require_once __DIR__ . '/core/bootstrap.php';

header('Content-Type: application/json');
header('Access-Control-Allow-Origin: https://intaleqapp.com');
header('Access-Control-Allow-Methods: POST, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type, Authorization, X-Device-FP');

if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
    http_response_code(200);
    exit;
}

$startTime = microtime(true);

try {
    $limiter = new RateLimiter($redis);
    $limiter->enforce(RateLimiter::identifier(), 'login');

    $passengerId = filterRequest('id');
    $fingerprint = filterRequest('fingerPrint') ?? filterRequest('fingerprint'); 
    $audience    = filterRequest('aud');

    if (empty($passengerId) || empty($fingerprint) || empty($audience)) {
        jsonError('Missing required parameters', 400);
    }

    $con = Database::get('main');

    // التحقق من الجهاز من خلال البصمة
    $stmt = $con->prepare('
        SELECT passengerID, fingerprint
        FROM tokens
        WHERE passengerID = :pid
        LIMIT 1
    ');
    $stmt->execute([':pid' => $passengerId]);
    $row = $stmt->fetch();

    $fpVerified = false;
    if ($row) {
        $fpPepper = getenv('FP_PEPPER') ?: '';
        $storedFp = $row['fingerprint'];
        
        // دعم الطريقة الجديدة (hash) والقديمة (مباشر)
        if ($fpPepper) {
            $expectedHash = hash('sha256', $fingerprint . $fpPepper);
            $fpVerified = hash_equals($storedFp, $expectedHash);
            if (!$fpVerified) {
                $fpVerified = hash_equals($storedFp, $fingerprint);
            }
        } else {
            $fpVerified = hash_equals($storedFp, $fingerprint);
        }
    }

    // وقت رد ثابت لمنع Timing Attack
    $elapsed = microtime(true) - $startTime;
    if ($elapsed < 0.1) usleep((int)((0.1 - $elapsed) * 1000000));

    if (!$fpVerified) {
        securityLog("Invalid login fingerprint", ['passengerId' => $passengerId]);
        jsonError('Invalid credentials', 401);
    }

    $limiter->reset(RateLimiter::identifier(), 'login');

    $jwtService = new JwtService($redis);
    $jwt = $jwtService->generateAccessToken($passengerId, 'passenger', $audience, $fingerprint);
    $refresh = $jwtService->generateRefreshToken($passengerId);

    jsonSuccess([
        'jwt' => $jwt,
        'refresh_token' => $refresh['token'],
        'expires_in' => 900
    ]);

} catch (PDOException $e) {
    securityLog("Login PDO Error", ['msg' => $e->getMessage()]);
    jsonError('Database error', 500);
} catch (Exception $e) {
    securityLog("Login Error", ['msg' => $e->getMessage()]);
    jsonError('Server error', 500);
}

File: privacy_policy1.php

<!doctype html>
<html lang="ar" dir="rtl">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>سياسة الخصوصية وشروط الخدمة  Siro Driver</title>
<meta name="robots" content="index,follow">
<style>
  body{font-family:system-ui,-apple-system,Segoe UI,Roboto,Helvetica,Arial,sans-serif;line-height:1.9;margin:24px;max-width:1000px}
  h1,h2{color:#1f4e79;margin-top:1.2em}
  h3{margin-top:1em}
  .note{background:#eef6ff;border:1px solid #cfe2ff;padding:16px;border-radius:8px}
  .box{background:#fafafa;border:1px solid #eee;padding:16px;border-radius:8px}
  .muted{color:#555}
  .two{display:grid;grid-template-columns:1fr;gap:18px}
  @media(min-width:900px){.two{grid-template-columns:1fr 1fr}}
  a{color:#1f4e79}
  hr{border:none;border-top:1px solid #eee;margin:28px 0}
  .ltr{direction:ltr}
  ul{margin:0 0 0 1em}
</style>
</head>
<body>

<header>
  <h1>سياسة الخصوصية وشروط الخدمة  تطبيق Siro Driver</h1>
  <p class="muted">آخر تحديث: 14-08-2025</p>
  <p class="muted">المشغّل/المتحكم بالبيانات: <strong>سيرو لنقل الركاب</strong></p>
  <p class="muted">البريد للتواصل: <a href="mailto:support@intaleqapp.com">support@intaleqapp.com</a></p>
</header>

<section class="note">
  <h2>إفصاح بارز عن البيانات الحساسة  الموقع الجغرافي</h2>
  <p><strong>يجمع تطبيق Siro Driver بيانات الموقع <u>الدقيقة</u> من جهاز السائق أثناء فتح التطبيق وأيضًا أثناء عمله في الخلفية/وعند إغلاقه، لغايات إسناد الرحلات القريبة، وتتبع الرحلة حيًا، واحتساب المسافة والأجرة بدقة.</strong></p>
  <ul>
    <li><strong>في الواجهة (Foreground):</strong> عرض موقع السائق على الخريطة وإتاحة الطلبات المناسبة.</li>
    <li><strong>في الخلفية/عند الإغلاق:</strong> استقبال طلبات جديدة قريبة، وتمكين تتبع الراكب للمسار، وحساب المسافة/الوقت/الأجرة.</li>
  </ul>
  <p>يمكنك إدارة إذن الموقع من إعدادات النظام. تعطيل الإذن سيمنع الوظائف الأساسية للتطبيق.</p>
</section>

<section>
  <h2>1) الفئات الكاملة للبيانات التي نجمعها</h2>
  <div class="two">
    <div class="box">
      <h3>أ. بيانات يقدّمها السائق</h3>
      <ul>
        <li>هوية: الاسم الكامل، رقم الهاتف، صورة الملف.</li>
        <li>مركبة: النوع/الطراز، رقم اللوحة، صور المركبة.</li>
        <li>وثائق قانونية: رخصة القيادة، رخصة المركبة، وأي مستندات مطلوبة للامتثال.</li>
        <li>إعدادات الحساب والتفضيلات.</li>
      </ul>
    </div>
    <div class="box">
      <h3>ب. بيانات تُجمع تلقائيًا</h3>
      <ul>
        <li><strong>الموقع:</strong> دقيق/تقريبي، في الواجهة والخلفية كما ورد أعلاه.</li>
        <li>بيانات الرحلات والاستخدام: سجل الرحلات، نقاط الانطلاق/الوصول، المدد والمسافات، التقييمات.</li>
        <li>بيانات الجهاز والمعرّفات: طراز الجهاز، نظام التشغيل، معرّفات إشعارات (FCM token)، عنوان IP، سجلات الأداء والأعطال.</li>
        <li>بيانات الدفع والعوائد (إن وُجدت): المبالغ المستحقة، سجلات السحب/التسوية.</li>
      </ul>
    </div>
  </div>
</section>

<section>
  <h2>2) الأغراض القانونية لاستخدام البيانات</h2>
  <ul>
    <li>تشغيل الخدمة الأساسية وإسناد الرحلات والملاحة وتتبع الرحلة واحتساب الأجرة.</li>
    <li>السلامة ومنع الاحتيال والتحقق من الأهلية القانونية للسائق.</li>
    <li>الدعم الفني وتحسين الجودة والتحليلات المجمّعة.</li>
    <li>الالتزام بواجبات محاسبية/ضريبية وقانونية.</li>
  </ul>
  <p><strong>الأساس القانوني:</strong> تنفيذ العقد، المصلحة المشروعة (السلامة/منع الاحتيال/التحسين)، والموافقة للأذونات الحساسة مثل الموقع في الخلفية.</p>
</section>

<section>
  <h2>3) المشاركة والجهات المتلقّية</h2>
  <ul>
    <li>مزودو الخرائط/الملاحة (مثل Google Maps Platform) لمعالجة الخرائط والتوجيه.</li>
    <li>خدمات الإشعارات والأداء/الأعطال (مثل Firebase Cloud Messaging وCrashlytics/Analytics).</li>
    <li>مزودو الدفع والتحقق والامتثال حسب السوق (مثل MTN، Syriatel، eCash/الهرم) عند الحاجة.</li>
    <li>جهات رسمية/رقابية عند وجود التزام قانوني.</li>
  </ul>
  <p><strong>لا نبيع</strong> بياناتك الشخصية. وأي مشاركة مقيّدة باتفاقيات ومعايير أمان مناسبة.</p>
</section>

<section>
  <h2>4) الاحتفاظ بالبيانات</h2>
  <ul>
    <li>بيانات الحساب والهوية: طالما الحساب فعّال، ثم لمدة معقولة بعد الإنهاء للامتثال/حل النزاعات.</li>
    <li>بيانات الرحلات والفوترة: وفق المتطلبات القانونية المحلية (عادة بين 35 سنوات).</li>
    <li>سجلات الأداء والأعطال: لفترات أقصر (عادة حتى 12 شهرًا).</li>
  </ul>
</section>

<section>
  <h2>5) أمان المعلومات</h2>
  <ul>
    <li>تشفير أثناء النقل (TLS) وتدابير وصول مقيّدة وسجلات تدقيق.</li>
    <li>مراجعات دورية وإصلاح الثغرات عند اكتشافها.</li>
  </ul>
  <p>لا توجد وسيلة نقل/تخزين إلكترونية آمنة تمامًا، لكننا نطبّق أفضل الممارسات المناسبة للخدمة.</p>
</section>

<section>
  <h2>6) القاصرون</h2>
  <p>خدمتنا موجّهة للسائقين البالغين قانونيًا فقط. لا نستهدف القاصرين ولا نجمع عن علم بيانات لمن هم دون السن القانوني المناسب لسوقنا. إن علمنا بذلك سنحذف البيانات ونعطّل الحساب.</p>
</section>

<section>
  <h2>7) حقوقك</h2>
  <ul>
    <li>الاطلاع على بياناتك والحصول على نسخة منها.</li>
    <li>تصحيح البيانات غير الدقيقة.</li>
    <li>طلب الحذف (مع مراعاة الالتزامات القانونية للاحتفاظ).</li>
    <li>تقييد أو الاعتراض على المعالجة في حالات محددة.</li>
    <li>سحب الموافقة للأذونات الحساسة (مثل الموقع في الخلفية) من إعدادات الجهاز، دون أن يؤثر ذلك على قانونية المعالجة السابقة للسحب.</li>
  </ul>
  <p>لممارسة أي من هذه الحقوق أو لتقديم شكوى، تواصل معنا عبر: <a href="mailto:support@intaleqapp.com">support@intaleqapp.com</a>.</p>
</section>

<section>
  <h2>8) النقل الدولي للبيانات</h2>
  <p>قد تُعالَج البيانات على خوادم/مزودين خارج بلدك. نتخذ تدابير تعاقدية وفنية مع شركائنا لضمان مستوى حماية مناسب.</p>
</section>

<section>
  <h2>9) ملفات تعريف الارتباط (Cookies) والمواقع</h2>
  <p>قد يستخدم موقعنا الإلكتروني كوكيز ضرورية للتشغيل و/أو تحليلات أساسية. يمكنك التحكم بها عبر إعدادات المتصفح. تطبيق الهاتف لا يعتمد على كوكيز، لكنه قد يستخدم معرّفات أجهزة لأغراض إشعارات/تحليلات.</p>
</section>

<section>
  <h2>10) أذونات أخرى قد يطلبها التطبيق</h2>
  <ul>
    <li><strong>الإشعارات (Push):</strong> لإعلام السائق بالطلبات والرسائل.</li>
    <li><strong>الكاميرا/الصور:</strong> لالتقاط/رفع صور الوثائق أو المركبة (إن طُلبت).</li>
    <li><strong>التخزين:</strong> لحفظ/قراءة صور الوثائق (إن لزم).</li>
  </ul>
</section>

<section>
  <h2>11) إدارة الأذونات</h2>
  <p>على Android: الإعدادات &gt; التطبيقات &gt; Siro Driver &gt; الأذونات (الموقع/الكاميرا/الصور/الإشعارات…). تعطيل بعض الأذونات قد يوقف الميزات الأساسية كاستلام الطلبات.</p>
</section>

<section>
  <h2>12) التعديلات على هذه السياسة</h2>
  <p>قد نحدّث هذه السياسة من وقت لآخر. سنغيّر تاريخ "آخر تحديث" أعلاه، وقد نرسل إشعارًا داخل التطبيق عند التغييرات الجوهرية.</p>
</section>

<section>
  <h2>13) حذف الحساب والتواصل</h2>
  <p>يمكنك طلب حذف حسابك وبياناتك عبر البريد: <a href="mailto:support@intaleqapp.com">support@intaleqapp.com</a>. نعالج الطلب خلال <strong>30 يومًا</strong> ما لم تمنعنا متطلبات قانونية من ذلك.</p>
</section>

<hr>

<!-- English full mirror to satisfy reviewers who prefer EN -->
<section class="ltr" dir="ltr" lang="en">
  <h2>Privacy Policy (English)</h2>
  <p class="muted"><strong>Last Updated:</strong> 14 Aug 2025  Data Controller: <strong>Siro for Passenger Transport</strong>  Contact: <a href="mailto:support@intaleqapp.com">support@intaleqapp.com</a></p>

  <div class="note">
    <h3>Prominent Disclosure  Location</h3>
    <p><strong>The Siro Driver app collects <u>precise</u> location data while the app is in the foreground and also in the background/when closed, to dispatch nearby jobs, enable live trip tracking, and accurately compute distance and fares.</strong></p>
    <ul>
      <li><strong>Foreground:</strong> show driver location and enable dispatch.</li>
      <li><strong>Background/closed:</strong> receive new requests, rider trip-tracking, and route/fare computation.</li>
    </ul>
    <p>Permissions can be managed in system settings; disabling location prevents core functionality.</p>
  </div>

  <h3>Data We Collect</h3>
  <ul>
    <li>Driver-provided: name, phone, profile photo; vehicle details; legal documents; account settings.</li>
    <li>Automatically collected: precise/approximate location (foreground & background), trip history, start/finish points, durations/distances, ratings; device info and identifiers (e.g., FCM token), IP, performance/crash logs; payout/billing data where applicable.</li>
  </ul>

  <h3>Purposes & Legal Bases</h3>
  <ul>
    <li>Core service operation (dispatch, navigation, tracking, fare computation); safety & fraud prevention; support; analytics; legal compliance.</li>
    <li>Legal bases: contract performance; legitimate interests (safety, fraud prevention, improvement); consent for sensitive permissions such as background location.</li>
  </ul>

  <h3>Sharing</h3>
  <ul>
    <li>Map/navigation providers (e.g., Google Maps Platform), notifications/performance/crash services (e.g., Firebase), payment/verification partners (e.g., MTN, Syriatel, eCash/Al-Haram as applicable), and authorities when legally required. No sale of personal data.</li>
  </ul>

  <h3>Retention</h3>
  <ul>
    <li>Account/identity: while the account is active and for a reasonable period thereafter.</li>
    <li>Trips/billing: per legal requirements (typically 35 years).</li>
    <li>Performance/crash logs: typically up to 12 months.</li>
  </ul>

  <h3>Security</h3>
  <p>TLS in transit, restricted access, audit logs, and reasonable technical/organizational measures.</p>

  <h3>Minors</h3>
  <p>Service is intended for legally adult drivers only. We do not knowingly collect data from minors; if identified, we will delete data and disable the account.</p>

  <h3>Your Rights</h3>
  <ul>
    <li>Access, rectification, deletion (subject to legal retention), restriction/objection, data portability where applicable, and consent withdrawal for sensitive permissions.</li>
  </ul>

  <h3>International Transfers</h3>
  <p>Data may be processed on servers/providers outside your country; we use contractual and technical safeguards with partners.</p>

  <h3>Cookies & Websites</h3>
  <p>Our website may use essential/analytics cookies; you can control them in your browser. The mobile app uses device identifiers instead of cookies.</p>

  <h3>Other Permissions</h3>
  <p>Push notifications; camera/photos for document/vehicle images; storage for saving/reading such images.</p>

  <h3>Changes</h3>
  <p>We may update this policy and will adjust the “Last Updated” date; material changes may be notified in-app.</p>

  <h3>Account Deletion & Contact</h3>
  <p>Email us at <a href="mailto:support@intaleqapp.com">support@intaleqapp.com</a>. We aim to fulfill deletion requests within <strong>30 days</strong> unless legal obligations prevent immediate deletion.</p>
</section>

<hr>

<section>
  <h2>شروط الخدمة المختصرة</h2>
  <ul>
    <li>باستخدام التطبيق، تُقرّ بالتزامك بالقوانين المحلية وبسياسة الخصوصية.</li>
    <li>تقديم معلومات دقيقة والمحافظة على سلوك مهني وسلامة المركبة.</li>
  </ul>
</section>

<footer class="muted">
  <p>© 2025 سيرو لنقل الركاب  جميع الحقوق محفوظة.</p>
</footer>

</body>
</html>

File: migrate_driver_passwords.php

<?php
// migrate_driver_passwords.php
// سكربت لمرة واحدة لإعادة توليد كلمة السر لكل السائقين
// المعادلة: baseString = id | normalizedPhone | [national_number OR birthYear]
// السر: hmacHex = hash_hmac('sha256', baseString, SECRET_KEY_HMAC, false)
// المخزن في DB: password_hash(hmacHex)

set_time_limit(0); // منع انتهاء المهلة أثناء المايغريشن
ini_set('memory_limit', '512M');

require_once realpath(__DIR__ . '/../vendor/autoload.php');
require_once 'load_env.php';

$env_file = '/home/siro-api/env/.env';
loadEnvironment($env_file);

include "encrypt_decrypt.php"; // لاستخدام $encryptionHelper

$dbUser = getenv('USER');
$dbPass = getenv('PASS');
$dbname = getenv('dbname');
$pepper = getenv('SECRET_KEY_HMAC');

if ($dbUser === false || $dbPass === false || $dbname === false || $pepper === false) {
    error_log("[MIGRATE] Missing env vars (USER/PASS/dbname/SECRET_KEY_HMAC). Abort.");
    exit(1);
}

try {
    $dsn = "mysql:host=localhost;dbname={$dbname};charset=utf8mb4";
    $options = [
        PDO::ATTR_EMULATE_PREPARES   => false,
        PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION,
        PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
        PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES UTF8",
    ];
    $pdo = new PDO($dsn, $dbUser, $dbPass, $options);

    // نجلب الحقول التي نحتاجها لبناء السر
    $sql = "SELECT id, phone, birthdate, national_number FROM driver";
    $stmt = $pdo->query($sql);

    $update = $pdo->prepare("UPDATE driver SET password = :pwd WHERE id = :id");

    $count       = 0;
    $skipped     = 0;
    $startTime   = microtime(true);

    while ($row = $stmt->fetch()) {
        $id       = $row['id'];
        $encPhone = $row['phone'];
        $encBirth = $row['birthdate'] ?? null;
        $encNat   = $row['national_number'] ?? null;

        // نفك التشفير  قد يرجع null لو الحقل فاضي
        $phone = $encPhone ? $encryptionHelper->decryptData($encPhone) : null;
        $birth = $encBirth ? $encryptionHelper->decryptData($encBirth) : null;
        $nat   = $encNat   ? $encryptionHelper->decryptData($encNat)   : null;

        if (empty($id) || empty($phone)) {
            // لو ناقصين، نتجاوز السطر مع تسجيل في اللوج
            error_log("[MIGRATE] Skip driver id={$id}: missing phone or id.");
            $skipped++;
            continue;
        }

        // في الوضع المثالي عندك nat + birthdate لكل السائقين
        // لو حاب تجبرهم يكونوا موجودين:
        /*
        if (empty($nat) || empty($birth)) {
            error_log("[MIGRATE] Skip driver id={$id}: missing nat or birthdate.");
            $skipped++;
            continue;
        }
        */

        // phone مفروض يكون أصلاً مطبّع (9639...) من سكربت التسجيل
        $normalizedPhone = trim($phone);

        // نبني baseString: الأساس id + phone
        $parts = [$id, $normalizedPhone];

        // نضيف رقم وطني أو سنة الميلاد (حسب الموجود)
        if (!empty($nat)) {
            $parts[] = trim($nat);
        } elseif (!empty($birth)) {
            // birthdate متوقعة بصيغة YYYY-01-01 -> نأخذ السنة فقط
            $year = substr($birth, 0, 4);
            if (preg_match('/^\d{4}$/', $year)) {
                $parts[] = $year;
            }
        }

        $baseString = implode('|', $parts);

        // اشتقاق السر النهائي (HEX string، بدون باينري)
        $hmacHex = hash_hmac('sha256', $baseString, $pepper, false);

        // نخزن فقط الهاش باستخدام password_hash
        $pwdHash = password_hash($hmacHex, PASSWORD_DEFAULT);

        $update->execute([
            ':pwd' => $pwdHash,
            ':id'  => $id,
        ]);

        $count++;

        // لوج بسيط كل 100 سائق
        if ($count % 100 === 0) {
            $elapsed = round(microtime(true) - $startTime, 2);
            error_log("[MIGRATE] Progress: updated {$count} drivers, skipped {$skipped}, elapsed {$elapsed}s");
        }
    }

    $totalTime = round(microtime(true) - $startTime, 2);
    error_log("[MIGRATE] Done. Updated {$count} driver passwords, skipped {$skipped}. Total time: {$totalTime}s");
    echo "Migration finished. Updated {$count} drivers, skipped {$skipped}. Time: {$totalTime}s\n";

} catch (PDOException $e) {
    error_log("[MIGRATE][PDO] " . $e->getMessage());
    echo "Migration failed (DB error).\n";
    exit(1);
} catch (Exception $e) {
    error_log("[MIGRATE][GENERAL] " . $e->getMessage());
    echo "Migration failed (general error).\n";
    exit(1);
}

File: loginJwtWalletDriver.php

<?php
// ============================================================
// loginJwtWalletDriver.php — توكن محفظة السائق
// ============================================================

require_once __DIR__ . '/core/bootstrap.php';

header('Content-Type: application/json');
header('Access-Control-Allow-Origin: https://walletintaleq.intaleq.xyz');
header('Access-Control-Allow-Methods: POST, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type, Authorization, X-Device-FP');

if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
    http_response_code(200);
    exit;
}

try {
    $limiter = new RateLimiter($redis);
    $limiter->enforce(RateLimiter::identifier(), 'login');

    $id          = filterRequest('id');
    $password    = filterRequest('password');
    $audience    = filterRequest('aud');
    $fingerPrint = filterRequest('fingerPrint') ?? filterRequest('fingerprint');

    $allowed1 = getenv('allowedWallet1');
    $allowed2 = getenv('allowedWallet2');
    $allowedAudiences = array_values(array_filter([$allowed1, $allowed2]));
    $passwordnewpassenger = getenv('passwordnewpassenger');
    $fpPepper = getenv('FP_PEPPER') ?: '';

    if (empty($id) || empty($password) || empty($audience) || empty($fingerPrint)) {
        jsonError('Missing required parameters', 400);
    }

    if (!in_array($audience, $allowedAudiences, true)) {
        jsonError('Invalid audience', 400);
    }

    if (!password_verify($password, $passwordnewpassenger)) {
        securityLog("WalletDriver login failed (password)", ['id' => $id]);
        jsonError('Invalid credentials', 401);
    }

    $con = Database::get('main');

    $stmt = $con->prepare('
        SELECT captain_id, fingerPrint
        FROM driverToken
        WHERE captain_id = :captain_id
        LIMIT 1
    ');
    $stmt->execute([':captain_id' => $id]);
    $tokenData = $stmt->fetch();

    $storedFp = $tokenData['fingerPrint'] ?? '';

    if (empty($storedFp)) {
        jsonError('Device fingerprint not registered', 403);
    }

    $fpVerified = false;
    if (!empty($fpPepper)) {
        $expectedHash = hash('sha256', $fingerPrint . $fpPepper);
        $fpVerified   = hash_equals($storedFp, $expectedHash);
        if (!$fpVerified) {
            $fpVerified = hash_equals($storedFp, $fingerPrint);
        }
    } else {
        $fpVerified = hash_equals($storedFp, $fingerPrint);
    }

    if (!$fpVerified) {
        securityLog("WalletDriver FP mismatch", ['id' => $id]);
        jsonError('Device verification failed', 403);
    }

    $limiter->reset(RateLimiter::identifier(), 'login');

    $fpHash = hash('sha256', $fingerPrint . $fpPepper);

    $payload = [
        'user_id'     => $id,
        'fingerPrint' => $fpHash,
        'exp'         => time() + 300, // 5 دقائق تم إصلاحه (كان 60)
        'iat'         => time(),
        'iss'         => 'Tripz-Wallet',
        'aud'         => $audience,
        'jti'         => bin2hex(random_bytes(16)),
    ];

    $secretKey = trim(file_get_contents('/home/siro-api/.secret_key_pay'));
    $jwt = Firebase\JWT\JWT::encode($payload, $secretKey, 'HS256');

    $hmac = hash_hmac('sha256', $id, getenv('SECRET_KEY_HMAC'));

    jsonSuccess([
        'status'     => 'success',
        'jwt'        => $jwt,
        'hmac'       => $hmac,
        'expires_in' => 300, // تم التعديل
    ]);

} catch (PDOException $e) {
    securityLog("LoginWalletDriver PDO Error", ['msg' => $e->getMessage()]);
    jsonError('Database error', 500);
} catch (Exception $e) {
    securityLog("LoginWalletDriver Error", ['msg' => $e->getMessage()]);
    jsonError('Server error', 500);
}

File: loginFirstTimeDriver.php

<?php
// ============================================================
// loginFirstTimeDriver.php — توكن التسجيل الأول (السائق)
// ============================================================

require_once __DIR__ . '/core/bootstrap.php';

header('Content-Type: application/json');
header('Access-Control-Allow-Origin: https://intaleqapp.com');
header('Access-Control-Allow-Methods: POST, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type, Authorization');

if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
    http_response_code(200);
    exit;
}

try {
    $limiter = new RateLimiter($redis);
    $limiter->enforce(RateLimiter::identifier(), 'register');

    $id          = filterRequest('id');
    $password    = filterRequest('password');
    $audience    = filterRequest('aud');
    $fingerprint = filterRequest('fingerprint') ?? filterRequest('fingerPrint'); 

    $allowed1 = getenv('allowedDriver1');
    $allowed2 = getenv('allowedDriver2');
    $allowedAudiences = array_values(array_filter([$allowed1, $allowed2]));
    $passwordnewpassenger = getenv('passwordnewpassenger');

    if (empty($id) || empty($password) || empty($audience)) {
        jsonError('Missing input fields.', 400);
    }

    if (!in_array($audience, $allowedAudiences, true)) {
        jsonError('Invalid audience', 400);
    }

    if (!password_verify($password, $passwordnewpassenger)) {
        securityLog("FirstTimeDriver login failed (password)", ['id' => $id]);
        jsonError('Invalid credentials.', 401);
    }

    $fpPepper = getenv('FP_PEPPER') ?: '';
    $fpHash = (!empty($fingerprint) && !empty($fpPepper))
        ? hash('sha256', $fingerprint . $fpPepper)
        : null;

    $payload = [
        'user_id'    => 'new',
        'sub'        => $id,
        'token_type' => 'registration',
        'exp'        => time() + 450, 
        'iat'        => time(),
        'iss'        => 'Tripz',
        'aud'        => $audience,
        'jti'        => bin2hex(random_bytes(16)),
    ];

    if ($fpHash !== null) {
        $payload['fingerPrint'] = $fpHash;
    }

    $secretKey = trim(file_get_contents('/home/siro-api/.secret_key'));
    $jwt = Firebase\JWT\JWT::encode($payload, $secretKey, 'HS256');

    jsonSuccess([
        'jwt'        => $jwt,
        'expires_in' => 450,
    ]);

} catch (Exception $e) {
    securityLog("LoginFirstTimeDriver Error", ['msg' => $e->getMessage()]);
    jsonError('Server error', 500);
}

File: loginWallet.php

<?php
// ============================================================
// loginWallet.php — توكن محفظة الراكب
// ============================================================

require_once __DIR__ . '/core/bootstrap.php';

header('Content-Type: application/json');
header('Access-Control-Allow-Origin: https://intaleqapp.com');
header('Access-Control-Allow-Methods: POST, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type, Authorization, X-Device-FP');

if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
    http_response_code(200);
    exit;
}

try {
    $limiter = new RateLimiter($redis);
    // محفظة الراكب نستخدم 'login' limit، يمكن فصله لـ 'wallet' إذا أردت
    $limiter->enforce(RateLimiter::identifier(), 'login');

    $id          = filterRequest('id');
    $password    = filterRequest('password');
    $audience    = filterRequest('aud');
    $fingerPrint = filterRequest('fingerPrint') ?? filterRequest('fingerprint');

    $allowed1 = getenv('allowed1');
    $allowed2 = getenv('allowed2');
    $allowedAudiences = array_values(array_filter([$allowed1, $allowed2]));
    $passwordnewpassenger = getenv('passwordnewpassenger');

    if (empty($id) || empty($password) || empty($audience) || empty($fingerPrint)) {
        jsonError('Missing required parameters', 400);
    }

    if (!in_array($audience, $allowedAudiences, true)) {
        jsonError('Invalid audience', 400);
    }

    if (!password_verify($password, $passwordnewpassenger)) {
        securityLog("Wallet login failed (password)", ['id' => $id]);
        jsonError('Invalid credentials', 401);
    }

    $con = Database::get('main');

    $stmt = $con->prepare('
        SELECT passengerID, fingerPrint
        FROM tokens
        WHERE passengerID = :pid
        LIMIT 1
    ');
    $stmt->execute([':pid' => $id]);
    $tokenData = $stmt->fetch();

    if (!$tokenData || !hash_equals($tokenData['fingerPrint'], $fingerPrint)) {
        securityLog("Wallet FP mismatch", ['id' => $id]);
        jsonError('Device verification failed', 403);
    }

    $limiter->reset(RateLimiter::identifier(), 'login');

    $jwtService = new JwtService($redis);
    
    $fpPepper = getenv('FP_PEPPER') ?: '';
    $fpHash = hash('sha256', $fingerPrint . $fpPepper);

    $payload = [
        'user_id'     => $id,
        'sub'         => $id,
        'fingerPrint' => $fpHash,
        'exp'         => time() + 300, // 5 دقائق تم إصلاحه
        'iat'         => time(),
        'iss'         => 'Tripz-Wallet',
        'aud'         => $audience,
        'jti'         => bin2hex(random_bytes(16)),
    ];

    $secretKey = trim(file_get_contents('/home/siro-api/.secret_key'));
    $jwt = Firebase\JWT\JWT::encode($payload, $secretKey, 'HS256');

    $hmac = hash_hmac('sha256', $id, getenv('SECRET_KEY_HMAC'));

    jsonSuccess([
        'jwt'        => $jwt,
        'hmac'       => $hmac,
        'expires_in' => 300,
    ]);

} catch (PDOException $e) {
    securityLog("LoginWallet PDO Error", ['msg' => $e->getMessage()]);
    jsonError('Database error', 500);
} catch (Exception $e) {
    securityLog("LoginWallet Error", ['msg' => $e->getMessage()]);
    jsonError('Server error', 500);
}

File: logout.php

<?php
// logout.php — تسجيل الخروج الآمن وإلغاء التوكن

require_once __DIR__ . '/connect.php';

try {
    $jwtService = new JwtService($redis);
    $decoded = $jwtService->authenticate();

    $jti = $decoded->jti ?? null;
    $exp = $decoded->exp ?? 0;
    $remaining = $exp - time();

    if ($jti && $remaining > 0) {
        $jwtService->revokeToken($jti, $remaining);
        securityLog("User logged out and token revoked", ['user_id' => $decoded->user_id, 'jti' => $jti]);
    }

    jsonSuccess(null, "Logged out successfully");

} catch (Exception $e) {
    jsonError("Logout failed", 500);
}

File: load_env.php

<?php
function loadEnvironment($env_file) {
    if (!file_exists($env_file)) {
        error_log("❌ .env not found: $env_file");
        return false;
    }

    $lines = file($env_file, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
    foreach ($lines as $line) {
        $line = trim($line);
        if (empty($line) || strpos($line, '#') === 0) continue;
        $parts = explode('=', $line, 2);
        if (count($parts) === 2) {
            [$keyName, $value] = $parts;
            $value = trim($value, "\"'");
            putenv("$keyName=$value");
            $_ENV[$keyName] = $value;
            $_SERVER[$keyName] = $value;
        }
    }

    return true;
}

File: connect.php

<?php
// ============================================================
// connect.php (النسخة الحديثة)
// بوابة التطبيقات (تستلزم JWT)
// ============================================================

require_once __DIR__ . '/core/bootstrap.php';
require_once __DIR__ . '/functions.php';

// 1. Rate Limiting
$limiter = new RateLimiter($redis);
$limiter->enforce(RateLimiter::identifier(), 'api');

// 2. JWT Authentication
$jwtService = new JwtService($redis);
$decoded = $jwtService->authenticate();

// متغيرات مساعدة للمطور
$user_id = $decoded->user_id ?? null;
$role    = $decoded->role ?? 'passenger';

// 3. Database Connection
try {
    $con = Database::get('main');
} catch (Exception $e) {
    http_response_code(500);
    exit(json_encode(['error' => 'Database connection failed']));
}

File: loginFirstTime.php

<?php
// ============================================================
// loginFirstTime.php — توكن التسجيل الأول (الراكب)
// ============================================================

require_once __DIR__ . '/core/bootstrap.php';

header('Content-Type: application/json');
header('Access-Control-Allow-Origin: https://intaleqapp.com');
header('Access-Control-Allow-Methods: POST, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type, Authorization');

if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
    http_response_code(200);
    exit;
}

try {
    $limiter = new RateLimiter($redis);
    $limiter->enforce(RateLimiter::identifier(), 'register');

    $id          = filterRequest('id');
    $password    = filterRequest('password');
    $audience    = filterRequest('aud');
    $fingerprint = filterRequest('fingerprint') ?? filterRequest('fingerPrint'); 

    $allowed1 = getenv('allowed1');
    $allowed2 = getenv('allowed2');
    $allowedAudiences = array_values(array_filter([$allowed1, $allowed2]));
    $passwordnewpassenger = getenv('passwordnewpassenger');

    if (empty($id) || empty($password) || empty($audience)) {
        jsonError('Missing input fields.', 400);
    }

    if (!in_array($audience, $allowedAudiences, true)) {
        jsonError('Invalid audience', 400);
    }

    if (!password_verify($password, $passwordnewpassenger)) {
        securityLog("FirstTime login failed (password)", ['id' => $id]);
        jsonError('Invalid password.', 401);
    }

    $jwtService = new JwtService($redis);
    
    // استخدام override للـ TTL في الـ Access Token (نحتاج 150 ثانية فقط)
    // لتوليد التوكن بتفاصيل خاصة، نستخدم الدالة generateAccessToken لكن بتعديل إن لزم،
    // أو نولد التوكن يدوياً هنا للسرعة كما كان:
    $fpPepper = getenv('FP_PEPPER') ?: '';
    $fpHash = (!empty($fingerprint) && !empty($fpPepper))
        ? hash('sha256', $fingerprint . $fpPepper)
        : null;

    $payload = [
        'user_id'    => 'new',
        'sub'        => $id,
        'token_type' => 'registration',
        'exp'        => time() + 150, // 150 ثانية
        'iat'        => time(),
        'iss'        => 'Tripz',
        'aud'        => $audience,
        'jti'        => bin2hex(random_bytes(16)),
    ];

    if ($fpHash !== null) {
        $payload['fingerPrint'] = $fpHash;
    }

    $secretKey = trim(file_get_contents('/home/siro-api/.secret_key'));
    $jwt = Firebase\JWT\JWT::encode($payload, $secretKey, 'HS256');

    jsonSuccess([
        'jwt'        => $jwt,
        'expires_in' => 150,
    ]);

} catch (Exception $e) {
    securityLog("LoginFirstTime Error", ['msg' => $e->getMessage()]);
    jsonError('Server error', 500);
}

File: privacy_policy.php

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Siro - Privacy Policy & Terms</title>
    <style>
        @import url('https://fonts.googleapis.com/css2?family=Cairo:wght@400;500;700&display=swap');
        
        body {
            font-family: 'Cairo', sans-serif;
            line-height: 1.8;
            margin: 0;
            padding: 0;
            background-color: #f7fafc;
            color: #2d3748;
        }

        .container {
            max-width: 800px;
            margin: 20px auto;
            padding: 20px;
            background-color: #ffffff;
            border-radius: 8px;
            box-shadow: 0 2px 10px rgba(0,0,0,0.05);
        }

        .language-section {
            border-bottom: 2px solid #e2e8f0;
            padding-bottom: 30px;
            margin-bottom: 30px;
        }
        .language-section:last-child {
            border-bottom: none;
            margin-bottom: 0;
        }

        h1, h2, h3 {
            color: #2c5282;
        }
        
        h1 {
            text-align: center;
            font-size: 2rem;
        }

        h2 {
            font-size: 1.75rem;
            border-bottom: 1px solid #e2e8f0;
            padding-bottom: 10px;
            margin-top: 40px;
        }

        h3 {
            font-size: 1.25rem;
            margin-top: 25px;
        }

        ul {
            padding-right: 20px; /* For Arabic */
            padding-left: 20px; /* For English */
        }
        
        li {
            margin-bottom: 10px;
        }

        .policy-dates {
            text-align: center;
            font-size: 0.9em;
            color: #4a5568;
            background-color: #ebf8ff;
            padding: 10px;
            border-radius: 5px;
            border: 1px solid #bee3f8;
            margin-bottom: 30px;
        }
        
        a {
            color: #3182ce;
            font-weight: bold;
            text-decoration: none;
        }
        a:hover {
            text-decoration: underline;
        }

    </style>
</head>
<body>

    <div class="container">

        <div class="language-section" lang="ar" dir="rtl">
            <h1>الشروط والخصوصية</h1>
            <div class="policy-dates">
                <strong>تاريخ النفاذ:</strong> 09/08/2025 &nbsp;&nbsp;&nbsp; <strong>آخر تحديث:</strong> 14/08/2025
            </div>

            <section>
                <h2>1. شروط الاستخدام والتعريفات</h2>
                <h3>شروط الاستخدام</h3>
                <p>عند تحميل أو تصفح أو استخدام تطبيق إنطلق ("التطبيق")، فإنك توافق على الالتزام بهذه الشروط والأحكام. يحق لإنطلق تعديل هذه الشروط في أي وقت. إذا لم توافق على أي جزء من هذه الشروط، يجب عليك التوقف فورًا عن استخدام التطبيق. استمرارك في الاستخدام يعني موافقتك على الشروط وأي تعديلات لاحقة.</p>
                <h3>التعريفات</h3>
                <ul>
                    <li><strong>"إنطلق" أو "التطبيق":</strong> يشير إلى تطبيق الهاتف الذكي الذي يسهل خدمات النقل بين الركاب ("المستخدمين") والسائقين ("مقدمو الخدمة"). وهو منصة حجز رحلات تعمل كوسيط ولا توظف السائقين مباشرة.</li>
                    <li><strong>"مقدمو الخدمة" (السائقون):</strong> الأفراد أو الكيانات المسجلة لتقديم خدمات النقل عبر إنطلق. يدفعون رسوم عمولة عن كل رحلة مكتملة.</li>
                    <li><strong>"المستخدمون" (الركاب):</strong> الأفراد الذين يحجزون الرحلات عبر التطبيق.</li>
                    <li><strong>"الخدمات":</strong> جميع خدمات النقل المقدمة من قبل مقدمي الخدمة عبر التطبيق.</li>
                </ul>
            </section>

            <section>
                <h2>2. سياسة الخصوصية</h2>
                <p>نحن نؤمن بالشفافية الكاملة فيما يتعلق ببياناتك. نوضح أدناه ما نجمعه، ولماذا، وكيف نحميه. <strong>يُعد استخدامنا لبيانات الموقع أمراً بالغ الأهمية لخدمتنا، ولذلك يتم شرحه أولاً.</strong></p>
                <div style="border: 2px solid #bee3f8; background-color: #ebf8ff; padding: 15px; border-radius: 8px; margin: 20px 0;">
                    <h3 style="color: #2c5282; margin-top: 0;">إفصاح بارز: استخدام بيانات الموقع</h3>
                    <p><strong>لتوفير خدماتنا الأساسية لتوصيل الركاب، يقوم تطبيق إنطلق بجمع بيانات الموقع الدقيقة من جهازك المحمول. الوصول إلى موقعك ضروري لكي يعمل التطبيق.</strong></p>
                    <p>نقوم بجمع هذه البيانات في الأوقات التالية:</p>
                    <ul>
                        <li><strong>عندما يكون التطبيق مفتوحاً على الشاشة (يعمل في الواجهة):</strong> لتحديد موقع الانطلاق الخاص بك، وعرضه على الخريطة، وإظهار السائقين القريبين منك.</li>
                        <li><strong>عندما يعمل التطبيق في الخلفية (بعد منحك الإذن):</strong> هذا الأمر حاسم لإيجاد رحلة لك أثناء استخدامك لتطبيقات أخرى، ولتتبع مسار الرحلة لضمان السلامة ودقة حساب الأجرة، ولتمكين مزايا الأمان مثل مشاركة حالة رحلتك.</li>
                    </ul>
                    <p><strong>الغرض من الاستخدام:</strong> ببساطة، بدون بيانات موقعك، لا يمكننا إيجاد سائقين لك، أو توجيههم إلى نقطة انطلاقك، أو حساب أجرة رحلتك. يمكنك إدارة أو تعطيل خدمات الموقع من خلال إعدادات جهازك، ولكن يرجى العلم أن القيام بذلك سيمنع تطبيق إنطلق من تقديم خدماته.</p>
                </div>
                <h3>البيانات التي تقدمها بنفسك</h3>
                <ul>
                    <li><strong>بيانات الهوية (للسائقين):</strong> الاسم الكامل، رقم الهاتف، صورة شخصية، ومعلومات الثبوتيات الشخصية للتحقق من الأهلية.</li>
                    <li><strong>بيانات الدفع:</strong> نحن لا نجمع أو نحتفظ بأي بيانات دفع. بدلاً من ذلك، نربطك مع مزودي خدمات دفع محليين مرخصين.</li>
                </ul>
                <h3>بيانات أخرى يتم جمعها تلقائياً</h3>
                <ul>
                    <li><strong>بيانات الجهاز والاتصال:</strong> طراز جهازك، نظام التشغيل، معرفات الجهاز الفريدة، وعنوان IP لأمان الحساب والتحقق منه.</li>
                    <li><strong>بيانات الاستخدام:</strong> معلومات حول كيفية تفاعلك مع التطبيق، مثل الميزات التي تستخدمها، وسجل رحلاتك، وتقييماتك، وذلك لتحسين خدماتنا.</li>
                </ul>
            </section>

            <section>
                <h2>3. التزامات المستخدم والسلوكيات</h2>
                <h3>معلومات دقيقة</h3>
                <p>يجب على المستخدمين تقديم <strong>معلومات صحيحة وكاملة وحديثة</strong> أثناء التسجيل. سيؤدي استخدام حسابات مزيفة أو أنشطة احتيالية إلى <strong>تعليق الحساب</strong>.</p>
                <h3>السلوكيات المحظورة</h3>
                <p><strong>يمنع على المستخدمين</strong>:</p>
                <ul>
                    <li>استخدام التطبيق في <strong>أنشطة غير قانونية</strong>.</li>
                    <li>مضايقة السائقين أو الركاب الآخرين.</li>
                    <li>إلحاق الضرر بالمركبة.</li>
                </ul>
            </section>

            <section>
                <h2>4. حقوق وواجبات الشركة</h2>
                <h3>واجباتنا</h3>
                <ul>
                    <li>حماية بياناتك الشخصية.</li>
                    <li>إبلاغك بأي تغييرات جوهرية في هذه السياسة.</li>
                    <li>توفير آليات واضحة لك لممارسة حقوقك المتعلقة بالبيانات.</li>
                </ul>
                <h3>حقوقنا</h3>
                <ul>
                    <li>تحديث التطبيق وشروط الخدمة.</li>
                    <li>اتخاذ الإجراءات اللازمة في حال مخالفة المستخدم للسياسة.</li>
                    <li>رفض تقديم الخدمة لأي سبب مشروع.</li>
                </ul>
            </section>
            
            <section>
                <h2>5. سياسات الرحلات والسلامة</h2>
                <h3>سياسة منع التدخين</h3>
                <p>يُحظر <strong>التدخين</strong> منعاً باتاً في جميع المركبات.</p>
                <h3>إجراءات السلامة لكوفيد-19</h3>
                <p>نحث جميع المستخدمين والسائقين على اتباع <strong>الإرشادات الصحية المحلية</strong>.</p>
            </section>

            <section>
                <h2>6. إخلاء المسؤولية</h2>
                <p>يقدم التطبيق والخدمات <strong>"كما هي"</strong> دون أي ضمانات. إنطلق هي منصة وسيطة ولا تتحمل <strong>المسؤولية</strong> عن أفعال السائقين أو المستخدمين.</p>
            </section>
            
            <section>
                <h2>7. التعديل على السياسة</h2>
                <p>في حال قمنا بإجراء تعديلات جوهرية على هذه الشروط، سنتعهد بإبلاغك بشكل واضح داخل التطبيق. سيُطلب منك قبول الشروط الجديدة لمواصلة استخدام الخدمة.</p>
            </section>
            
            <section>
                <h2>8. حذف الحساب والتواصل معنا</h2>
                <p>لحذف حسابك أو بياناتك، يرجى مراسلتنا على البريد الإلكتروني. يتم الرد على الطلبات خلال <strong>30 يومًا</strong>.</p>
                <p>لأي استفسارات، يرجى التواصل عبر: <a href="mailto:support@intaleqapp.com">support@intaleqapp.com</a></p>
            </section>

        </div>

        <div class="language-section" lang="en" dir="ltr">
            <h1>Policy & Terms</h1>
            <div class="policy-dates">
                <strong>Effective Date:</strong> 09/08/2025 &nbsp;&nbsp;&nbsp; <strong>Last Updated:</strong> 14/08/2025
            </div>

            <section>
                <h2>1. Terms of Use & Definitions</h2>
                <h3>Terms of Use</h3>
                <p>By downloading, browsing, or using the Siro application ("the App"), you agree to be bound by these Terms and Conditions. Siro reserves the right to modify these terms at any time. Continued use constitutes acceptance of the terms.</p>
                <h3>Definitions</h3>
                <ul>
                    <li><strong>"Siro" or "the App":</strong> Refers to the smartphone application that facilitates ride-hailing services.</li>
                    <li><strong>"Service Providers" (Drivers):</strong> Individuals or entities registered to provide transportation services through Siro.</li>
                    <li><strong>"Users" (Passengers):</strong> Individuals who book rides through the App.</li>
                    <li><strong>"Services":</strong> All transportation services provided by Service Providers via the App.</li>
                </ul>
            </section>
            
            <section>
                <h2>2. Privacy Policy</h2>
                <p>We believe in full transparency regarding your data. <strong>Our use of location data is critical to our service and is explained first.</strong></p>
                <div style="border: 2px solid #bee3f8; background-color: #ebf8ff; padding: 15px; border-radius: 8px; margin: 20px 0;">
                    <h3 style="color: #2c5282; margin-top: 0;">Prominent Disclosure: Use of Location Data</h3>
                    <p><strong>To provide our core ride-hailing services, the Siro app collects precise location data from your mobile device. Access to your location is essential for the app to function.</strong></p>
                    <p>We collect this data:</p>
                    <ul>
                        <li><strong>When the app is open and visible (in the foreground):</strong> To determine your pickup location and show you nearby drivers.</li>
                        <li><strong>When the app is running in the background (after you grant permission):</strong> This is crucial to connect you with a ride, track the trip's progress for safety and fare calculation.</li>
                    </ul>
                    <p><strong>Purpose of Use:</strong> Without your location data, we cannot find drivers for you, guide them to your pickup point, or calculate your fare. Disabling location services will prevent the app from providing its services.</p>
                </div>
                <h3>Data You Provide Yourself</h3>
                <ul>
                    <li><strong>Identity Data (for Drivers):</strong> Full name, phone number, profile picture, and personal identification to verify eligibility.</li>
                    <li><strong>Payment Data:</strong> We do not collect or store any payment data like card numbers. We connect you with licensed local payment providers.</li>
                </ul>
                <h3>Other Automatically Collected Data</h3>
                <ul>
                    <li><strong>Device & Connection Data:</strong> Your device's model, OS, unique identifiers, and IP address for security.</li>
                    <li><strong>Usage Data:</strong> Information about how you interact with the app, such as trip history and ratings, to improve our services.</li>
                </ul>
            </section>

            <section>
                <h2>3. User Obligations & Conduct</h2>
                <h3>Accurate Information</h3>
                <p>Users must provide <strong>true, complete, and up-to-date</strong> information. Fake accounts will result in <strong>account suspension</strong>.</p>
                <h3>Prohibited Conduct</h3>
                <p>Users <strong>must not</strong>:</p>
                <ul>
                    <li>Use the App for <strong>illegal activities</strong>.</li>
                    <li>Harass drivers or other passengers.</li>
                    <li>Damage the vehicle.</li>
                </ul>
            </section>

            <section>
                <h2>4. Company Rights and Duties</h2>
                <h3>Our Duties</h3>
                <ul>
                    <li>To protect your personal data.</li>
                    <li>To inform you of material changes to this policy.</li>
                    <li>To provide clear mechanisms to exercise your data rights.</li>
                </ul>
                <h3>Our Rights</h3>
                <ul>
                    <li>To update the application and terms of service.</li>
                    <li>To take necessary actions in case of user violation.</li>
                    <li>To refuse service for any legitimate reason.</li>
                </ul>
            </section>

            <section>
                <h2>5. Ride & Safety Policies</h2>
                <h3>No-Smoking Policy</h3>
                <p>Smoking is <strong>strictly prohibited</strong> in all vehicles.</p>
                <h3>COVID-19 Safety</h3>
                <p>We urge all users and drivers to follow <strong>local health guidelines</strong>.</p>
            </section>
            
            <section>
                <h2>6. Disclaimer of Liability</h2>
                <p>The App and services are provided <strong>"as is"</strong>. Siro is an intermediary platform and is <strong>not liable</strong> for the acts of any user or driver.</p>
            </section>

            <section>
                <h2>7. Policy Modifications</h2>
                <p>If we make material changes, we will inform you clearly within the app. You will be required to accept the new terms to continue using the service.</p>
            </section>
            
            <section>
                <h2>8. Account Deletion & Contact Us</h2>
                <p>To <strong>delete your account or data</strong>, please email us. Requests are processed within <strong>30 days</strong>.</p>
                <p>For any questions, contact us at: <a href="mailto:support@intaleqapp.com">support@intaleqapp.com</a></p>
            </section>
        </div>

    </div>

</body>
</html>

File: schema_tracking.sql

-- MySQL dump 10.13  Distrib 8.0.36-28, for Linux (x86_64)
--
-- Host: 188.68.36.205    Database: locationDB
-- ------------------------------------------------------
-- Server version	8.0.36-28

/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!50503 SET NAMES utf8mb4 */;
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
/*!40103 SET TIME_ZONE='+00:00' */;
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
/*!50717 SELECT COUNT(*) INTO @rocksdb_has_p_s_session_variables FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'performance_schema' AND TABLE_NAME = 'session_variables' */;
/*!50717 SET @rocksdb_get_is_supported = IF (@rocksdb_has_p_s_session_variables, 'SELECT COUNT(*) INTO @rocksdb_is_supported FROM performance_schema.session_variables WHERE VARIABLE_NAME=\'rocksdb_bulk_load\'', 'SELECT 0') */;
/*!50717 PREPARE s FROM @rocksdb_get_is_supported */;
/*!50717 EXECUTE s */;
/*!50717 DEALLOCATE PREPARE s */;
/*!50717 SET @rocksdb_enable_bulk_load = IF (@rocksdb_is_supported, 'SET SESSION rocksdb_bulk_load = 1', 'SET @rocksdb_dummy_bulk_load = 0') */;
/*!50717 PREPARE s FROM @rocksdb_enable_bulk_load */;
/*!50717 EXECUTE s */;
/*!50717 DEALLOCATE PREPARE s */;

--
-- Table structure for table `CarRegistration`
--

DROP TABLE IF EXISTS `CarRegistration`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `CarRegistration` (
  `id` int NOT NULL AUTO_INCREMENT,
  `driverID` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL,
  `vin` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL,
  `car_plate` varchar(150) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL,
  `make` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL,
  `model` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL,
  `year` varchar(10) CHARACTER SET utf32 COLLATE utf32_general_ci NOT NULL,
  `expiration_date` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `color` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL,
  `owner` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL,
  `color_hex` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `fuel` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL,
  `isDefault` tinyint(1) NOT NULL DEFAULT '0',
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `status` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'yet',
  PRIMARY KEY (`id`),
  UNIQUE KEY `car_plate` (`car_plate`),
  KEY `idx_driverID` (`driverID`)
) ENGINE=InnoDB AUTO_INCREMENT=14 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `adminUser`
--

DROP TABLE IF EXISTS `adminUser`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `adminUser` (
  `id` int NOT NULL AUTO_INCREMENT,
  `device_number` varchar(300) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `name` varchar(150) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `api_keys`
--

DROP TABLE IF EXISTS `api_keys`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `api_keys` (
  `id` int NOT NULL AUTO_INCREMENT,
  `name` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `hashed_key` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `blacklist_driver`
--

DROP TABLE IF EXISTS `blacklist_driver`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `blacklist_driver` (
  `id` int NOT NULL AUTO_INCREMENT,
  `driver_id` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `phone` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `reason` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT 'Violation',
  `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `canecl`
--

DROP TABLE IF EXISTS `canecl`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `canecl` (
  `id` int NOT NULL AUTO_INCREMENT,
  `driverID` varchar(111) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `passengerID` varchar(111) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `rideID` varchar(111) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `note` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT 'nothing',
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `captains_car`
--

DROP TABLE IF EXISTS `captains_car`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `captains_car` (
  `id` int NOT NULL AUTO_INCREMENT,
  `driverID` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `vin` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `car_plate` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `make` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `model` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `year` varchar(6) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `expiration_date` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `color` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `owner` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `color_hex` char(15) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `address` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `displacement` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `fuel` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `registration_date` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `isDefault` tinyint(1) NOT NULL DEFAULT '0',
  `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `car_plate` (`car_plate`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `carPlateEdit`
--

DROP TABLE IF EXISTS `carPlateEdit`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `carPlateEdit` (
  `id` int NOT NULL AUTO_INCREMENT,
  `driverId` varchar(50) NOT NULL,
  `carPlate` varchar(155) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
  `color` varchar(20) NOT NULL,
  `make` varchar(50) NOT NULL,
  `model` varchar(20) NOT NULL,
  `expiration_date` varchar(50) NOT NULL,
  `owner` varchar(155) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
  `year` int NOT NULL,
  `isEdit` tinyint(1) NOT NULL DEFAULT '0',
  `employee` varchar(30) NOT NULL DEFAULT 'any',
  `createdAt` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `driverId` (`driverId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `car_locations`
--

DROP TABLE IF EXISTS `car_locations`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `car_locations` (
  `driver_id` varchar(100) NOT NULL,
  `latitude` decimal(10,7) NOT NULL,
  `longitude` decimal(10,7) NOT NULL,
  `heading` decimal(10,2) NOT NULL,
  `speed` double(10,3) NOT NULL,
  `distance` decimal(10,2) NOT NULL,
  `status` varchar(6) NOT NULL DEFAULT 'off',
  `carType` varchar(100) NOT NULL DEFAULT 'Awfar',
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `location_point` point NOT NULL /*!80003 SRID 4326 */,
  PRIMARY KEY (`driver_id`),
  KEY `idx_loc_status_time` (`status`,`updated_at`,`latitude`,`longitude`),
  SPATIAL KEY `idx_location_point` (`location_point`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;
/*!40101 SET character_set_client = @saved_cs_client */;
/*!50003 SET @saved_cs_client      = @@character_set_client */ ;
/*!50003 SET @saved_cs_results     = @@character_set_results */ ;
/*!50003 SET @saved_col_connection = @@collation_connection */ ;
/*!50003 SET character_set_client  = utf8mb4 */ ;
/*!50003 SET character_set_results = utf8mb4 */ ;
/*!50003 SET collation_connection  = utf8mb4_0900_ai_ci */ ;
/*!50003 SET @saved_sql_mode       = @@sql_mode */ ;
/*!50003 SET sql_mode              = 'NO_AUTO_VALUE_ON_ZERO' */ ;
DELIMITER ;;
/*!50003 CREATE*/ /*!50017 DEFINER=`siroLocation`@`%`*/ /*!50003 TRIGGER `trg_before_insert_car_locations` BEFORE INSERT ON `car_locations` FOR EACH ROW BEGIN
SET NEW.location_point = ST_PointFromText(CONCAT('POINT(', NEW.longitude, ' ', NEW.latitude, ')'), 4326);
END */;;
DELIMITER ;
/*!50003 SET sql_mode              = @saved_sql_mode */ ;
/*!50003 SET character_set_client  = @saved_cs_client */ ;
/*!50003 SET character_set_results = @saved_cs_results */ ;
/*!50003 SET collation_connection  = @saved_col_connection */ ;
/*!50003 SET @saved_cs_client      = @@character_set_client */ ;
/*!50003 SET @saved_cs_results     = @@character_set_results */ ;
/*!50003 SET @saved_col_connection = @@collation_connection */ ;
/*!50003 SET character_set_client  = utf8mb4 */ ;
/*!50003 SET character_set_results = utf8mb4 */ ;
/*!50003 SET collation_connection  = utf8mb4_0900_ai_ci */ ;
/*!50003 SET @saved_sql_mode       = @@sql_mode */ ;
/*!50003 SET sql_mode              = 'NO_AUTO_VALUE_ON_ZERO' */ ;
DELIMITER ;;
/*!50003 CREATE*/ /*!50017 DEFINER=`siroLocation`@`%`*/ /*!50003 TRIGGER `trg_before_update_car_locations` BEFORE UPDATE ON `car_locations` FOR EACH ROW BEGIN
IF NEW.latitude <> OLD.latitude OR NEW.longitude <> OLD.longitude THEN
SET NEW.location_point = ST_PointFromText(CONCAT('POINT(', NEW.longitude, ' ', NEW.latitude, ')'), 4326);
END IF;
END */;;
DELIMITER ;
/*!50003 SET sql_mode              = @saved_sql_mode */ ;
/*!50003 SET character_set_client  = @saved_cs_client */ ;
/*!50003 SET character_set_results = @saved_cs_results */ ;
/*!50003 SET collation_connection  = @saved_col_connection */ ;

--
-- Table structure for table `car_tracks`
--

DROP TABLE IF EXISTS `car_tracks`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `car_tracks` (
  `id` int NOT NULL AUTO_INCREMENT,
  `driver_id` varchar(100) NOT NULL,
  `latitude` decimal(10,7) NOT NULL,
  `longitude` decimal(10,7) NOT NULL,
  `heading` float DEFAULT NULL,
  `speed` float DEFAULT NULL,
  `distance` float DEFAULT NULL,
  `status` enum('on','off') DEFAULT 'off',
  `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  KEY `idx_driver_time` (`driver_id`,`created_at`)
) ENGINE=InnoDB AUTO_INCREMENT=2559370 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `card_images`
--

DROP TABLE IF EXISTS `card_images`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `card_images` (
  `id` int NOT NULL AUTO_INCREMENT,
  `driverID` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `image_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `upload_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `link` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `carsToWork`
--

DROP TABLE IF EXISTS `carsToWork`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `carsToWork` (
  `id` int NOT NULL AUTO_INCREMENT,
  `owner_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `phone` varchar(15) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `car_number` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `manufacture_year` year NOT NULL,
  `car_model` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `car_type` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `site` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `registration_date` date NOT NULL,
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `complaint`
--

DROP TABLE IF EXISTS `complaint`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `complaint` (
  `id` int NOT NULL AUTO_INCREMENT,
  `ride_id` varchar(255) NOT NULL,
  `passenger_id` varchar(255) DEFAULT NULL,
  `driver_id` varchar(255) DEFAULT NULL,
  `complaint_type` enum('Driver','Passenger','Both') NOT NULL,
  `description` text,
  `date_filed` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  `statusComplaint` enum('Open','In Progress','Resolved') NOT NULL DEFAULT 'Open',
  `resolution` text,
  `passenger_report` text,
  `driver_report` text,
  `cs_solutions` text,
  `fault_determination` varchar(255) DEFAULT NULL,
  `complaint_nature` varchar(255) DEFAULT NULL,
  `date_resolved` timestamp NULL DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `contactEgypt`
--

DROP TABLE IF EXISTS `contactEgypt`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `contactEgypt` (
  `id` int NOT NULL AUTO_INCREMENT,
  `phones` varchar(20) NOT NULL,
  `name` varchar(100) NOT NULL,
  `phones2` varchar(60) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
  `createdAt` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `contactSyria`
--

DROP TABLE IF EXISTS `contactSyria`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `contactSyria` (
  `id` int NOT NULL AUTO_INCREMENT,
  `driverId` varchar(255) NOT NULL COMMENT 'معرّف السائق الذي قام بمزامنة جهة الاتصال',
  `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT 'اسم جهة الاتصال',
  `phone` varchar(50) NOT NULL COMMENT 'رقم هاتف جهة الاتصال',
  `sync_timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'وقت المزامنة',
  PRIMARY KEY (`id`),
  UNIQUE KEY `driver_contact_unique` (`driverId`,`phone`)
) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `criminalDocuments`
--

DROP TABLE IF EXISTS `criminalDocuments`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `criminalDocuments` (
  `id` int NOT NULL AUTO_INCREMENT,
  `driverId` varchar(50) NOT NULL,
  `IssueDate` varchar(20) NOT NULL,
  `createdAt` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `InspectionResult` varchar(100) NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `driverId` (`driverId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `driver`
--

DROP TABLE IF EXISTS `driver`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `driver` (
  `idn` int NOT NULL AUTO_INCREMENT,
  `id` varchar(100) NOT NULL,
  `phone` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL,
  `email` varchar(255) NOT NULL,
  `password` varchar(255) NOT NULL,
  `gender` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL DEFAULT 'Male',
  `license_type` varchar(255) DEFAULT NULL,
  `national_number` varchar(255) DEFAULT NULL,
  `name_arabic` varchar(255) DEFAULT NULL,
  `issue_date` date DEFAULT NULL,
  `expiry_date` date DEFAULT NULL,
  `license_categories` varchar(255) DEFAULT NULL,
  `address` text,
  `licenseIssueDate` varchar(50) DEFAULT NULL,
  `status` varchar(20) NOT NULL DEFAULT 'notDeleted',
  `birthdate` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL,
  `site` varchar(255) NOT NULL,
  `first_name` varchar(255) NOT NULL,
  `last_name` varchar(255) NOT NULL,
  `accountBank` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL DEFAULT 'yet',
  `bankCode` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL DEFAULT 'CIB',
  `employmentType` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL,
  `maritalStatus` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL,
  `fullNameMaritial` varchar(255) DEFAULT NULL,
  `expirationDate` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL,
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`idn`)
) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8mb3;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `driverToken`
--

DROP TABLE IF EXISTS `driverToken`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `driverToken` (
  `id` int NOT NULL AUTO_INCREMENT,
  `token` varchar(300) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `captain_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `fingerPrint` varchar(155) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  KEY `idx_captain_id` (`captain_id`)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `driverWallet`
--

DROP TABLE IF EXISTS `driverWallet`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `driverWallet` (
  `id` int NOT NULL AUTO_INCREMENT,
  `driverID` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `paymentID` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `dateCreated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `amount` varchar(5) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `paymentMethod` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `dateUpdated` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `driver_behavior`
--

DROP TABLE IF EXISTS `driver_behavior`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `driver_behavior` (
  `id` int NOT NULL AUTO_INCREMENT,
  `driver_id` varchar(255) NOT NULL,
  `trip_id` varchar(255) NOT NULL,
  `max_speed` double DEFAULT '0',
  `avg_speed` double DEFAULT '0',
  `hard_brakes` int DEFAULT '0',
  `total_distance` double DEFAULT '0',
  `behavior_score` double DEFAULT '0',
  `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=22 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `driver_daily_summary`
--

DROP TABLE IF EXISTS `driver_daily_summary`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `driver_daily_summary` (
  `id` int NOT NULL AUTO_INCREMENT,
  `driver_id` varchar(33) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL,
  `date` date NOT NULL,
  `total_seconds` int DEFAULT '0',
  `last_updated_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `unique_driver_date` (`driver_id`,`date`)
) ENGINE=InnoDB AUTO_INCREMENT=308443 DEFAULT CHARSET=utf8mb3;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `driver_daily_work`
--

DROP TABLE IF EXISTS `driver_daily_work`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `driver_daily_work` (
  `driver_id` int NOT NULL,
  `work_date` date NOT NULL,
  `total_seconds` int NOT NULL DEFAULT '0',
  `last_point_at` datetime DEFAULT NULL,
  `last_status` enum('on','off') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT 'off',
  `updated_at` datetime NOT NULL,
  PRIMARY KEY (`driver_id`,`work_date`),
  KEY `idx_driver_date` (`driver_id`,`work_date`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `driver_documents`
--

DROP TABLE IF EXISTS `driver_documents`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `driver_documents` (
  `id` int NOT NULL AUTO_INCREMENT,
  `driverID` varchar(64) NOT NULL,
  `doc_type` varchar(64) NOT NULL,
  `image_name` varchar(255) NOT NULL,
  `link` varchar(512) NOT NULL,
  `upload_date` datetime NOT NULL,
  PRIMARY KEY (`id`),
  KEY `driverID` (`driverID`)
) ENGINE=InnoDB AUTO_INCREMENT=33 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `driver_gifts`
--

DROP TABLE IF EXISTS `driver_gifts`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `driver_gifts` (
  `id` int NOT NULL AUTO_INCREMENT,
  `driver_id` varchar(70) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `gift_description` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `gift_date` datetime DEFAULT CURRENT_TIMESTAMP,
  `is_claimed` tinyint(1) DEFAULT '0',
  PRIMARY KEY (`id`),
  UNIQUE KEY `driver_id` (`driver_id`)
) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `driver_health_assurance`
--

DROP TABLE IF EXISTS `driver_health_assurance`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `driver_health_assurance` (
  `id` int NOT NULL AUTO_INCREMENT,
  `driver_id` varchar(155) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `assured` tinyint(1) DEFAULT '0',
  `date_created` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  `health_insurance_provider` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `driver_id` (`driver_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `driver_orders`
--

DROP TABLE IF EXISTS `driver_orders`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `driver_orders` (
  `id` int NOT NULL AUTO_INCREMENT,
  `driver_id` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `order_id` varchar(99) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL,
  `notes` varchar(200) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL DEFAULT 'nothing',
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `status` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT 'applied',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=44 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `driver_ride_scam`
--

DROP TABLE IF EXISTS `driver_ride_scam`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `driver_ride_scam` (
  `id` int NOT NULL AUTO_INCREMENT,
  `driverID` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `passendgerID` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `rideID` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `isDriverCallPassenger` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `dateCreated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `driversWantWork`
--

DROP TABLE IF EXISTS `driversWantWork`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `driversWantWork` (
  `id` int NOT NULL AUTO_INCREMENT,
  `driver_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `phone` varchar(15) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `national_id` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `birth_date` varchar(15) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `license_type` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `site` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `national_id` (`national_id`),
  UNIQUE KEY `phone` (`phone`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `email_verifications`
--

DROP TABLE IF EXISTS `email_verifications`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `email_verifications` (
  `id` int NOT NULL AUTO_INCREMENT,
  `email` varchar(255) NOT NULL,
  `token` varchar(255) NOT NULL,
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `verified` tinyint(1) NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`),
  UNIQUE KEY `email` (`email`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `employee`
--

DROP TABLE IF EXISTS `employee`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `employee` (
  `id` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `education` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `site` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `phone` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `status` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `phone` (`phone`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `error`
--

DROP TABLE IF EXISTS `error`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `error` (
  `id` int NOT NULL AUTO_INCREMENT,
  `error` varchar(400) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `userId` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `userType` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `phone` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `device` varchar(300) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `details` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci,
  `status` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'new',
  PRIMARY KEY (`id`),
  KEY `idx_error_created_at` (`created_at`),
  KEY `idx_error_phone` (`phone`)
) ENGINE=InnoDB AUTO_INCREMENT=14316 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `feedBack`
--

DROP TABLE IF EXISTS `feedBack`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `feedBack` (
  `id` int NOT NULL AUTO_INCREMENT,
  `passengerId` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `feedBack` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
  `datecreated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `helpCenter`
--

DROP TABLE IF EXISTS `helpCenter`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `helpCenter` (
  `id` int NOT NULL AUTO_INCREMENT,
  `driverID` varchar(89) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `helpQuestion` varchar(300) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL,
  `replay` varchar(400) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'not yet',
  `datecreated` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `hotels`
--

DROP TABLE IF EXISTS `hotels`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `hotels` (
  `id` int NOT NULL,
  `nameEnglish` varchar(255) DEFAULT NULL,
  `nameArabic` varchar(255) DEFAULT NULL,
  `phone` varchar(20) DEFAULT NULL,
  `countReview` int DEFAULT NULL,
  `rate` float DEFAULT NULL,
  `stars` varchar(50) DEFAULT NULL,
  `address` text,
  `website` varchar(255) DEFAULT NULL,
  `email` varchar(255) DEFAULT NULL,
  `PlusCode` varchar(50) DEFAULT NULL,
  `closeTime` varchar(50) DEFAULT NULL,
  `latitude` decimal(10,6) DEFAULT NULL,
  `longitude` decimal(10,6) DEFAULT NULL,
  `instagram` varchar(255) DEFAULT NULL,
  `facebook` varchar(255) DEFAULT NULL,
  `linkedin` varchar(255) DEFAULT NULL,
  `twitter` varchar(255) DEFAULT NULL,
  `photo` varchar(255) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `imageProfileCaptain`
--

DROP TABLE IF EXISTS `imageProfileCaptain`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `imageProfileCaptain` (
  `id` int NOT NULL AUTO_INCREMENT,
  `driverID` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `image_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `upload_date` datetime DEFAULT CURRENT_TIMESTAMP,
  `link` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `invites`
--

DROP TABLE IF EXISTS `invites`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `invites` (
  `id` int NOT NULL AUTO_INCREMENT,
  `driverId` varchar(50) NOT NULL,
  `inviterDriverPhone` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
  `createdAt` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `inviteCode` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
  `isInstall` tinyint(1) NOT NULL DEFAULT '0',
  `isGiftToken` tinyint(1) NOT NULL DEFAULT '0',
  `expirationTime` datetime NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `inviterDriverId` (`inviterDriverPhone`),
  UNIQUE KEY `inviteCode` (`inviteCode`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `invitesToPassengers`
--

DROP TABLE IF EXISTS `invitesToPassengers`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `invitesToPassengers` (
  `id` int NOT NULL AUTO_INCREMENT,
  `driverId` varchar(70) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `passengerID` varchar(80) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'yet',
  `inviterPassengerPhone` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `inviteCode` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `expirationTime` datetime NOT NULL,
  `createdAt` datetime DEFAULT CURRENT_TIMESTAMP,
  `isInstall` tinyint(1) DEFAULT '0',
  `isGiftToken` tinyint(1) NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`),
  UNIQUE KEY `inviteCode` (`inviteCode`)
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `invoice_records`
--

DROP TABLE IF EXISTS `invoice_records`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `invoice_records` (
  `id` int NOT NULL AUTO_INCREMENT,
  `driverID` int NOT NULL,
  `invoice_number` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `amount` decimal(10,2) DEFAULT NULL,
  `date` date DEFAULT NULL,
  `image_link` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci,
  `created_at` datetime DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=36 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `invoicesAdmin`
--

DROP TABLE IF EXISTS `invoicesAdmin`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `invoicesAdmin` (
  `id` int NOT NULL AUTO_INCREMENT,
  `item_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `amount` decimal(10,2) NOT NULL,
  `image_url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=22 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `kazan`
--

DROP TABLE IF EXISTS `kazan`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `kazan` (
  `id` int NOT NULL AUTO_INCREMENT,
  `country` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `kazan` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `comfortPrice` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `speedPrice` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `familyPrice` varchar(4) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `deliveryPrice` varchar(11) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `freePrice` varchar(11) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `latePrice` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `heavyPrice` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `adminId` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `createdAt` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `naturePrice` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `fuelPrice` varchar(6) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `lisenceDetails`
--

DROP TABLE IF EXISTS `lisenceDetails`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `lisenceDetails` (
  `id` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
  `driverID` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
  `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `licenseClass` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `documentNo` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `address` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `height` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `postalCode` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `sex` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `stateCode` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `expireDate` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `dateOfBirth` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `dateCreated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `documentNo` (`documentNo`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `login_attempts`
--

DROP TABLE IF EXISTS `login_attempts`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `login_attempts` (
  `id` int NOT NULL AUTO_INCREMENT,
  `ip_address` varchar(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `attempt_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=18 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `login_attempts_drivers`
--

DROP TABLE IF EXISTS `login_attempts_drivers`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `login_attempts_drivers` (
  `id` int NOT NULL AUTO_INCREMENT,
  `ip_address` varchar(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `attempt_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `mishwaritrips`
--

DROP TABLE IF EXISTS `mishwaritrips`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `mishwaritrips` (
  `id` int NOT NULL AUTO_INCREMENT,
  `driverId` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `phone` varchar(15) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `gender` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `name_english` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `address` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `religion` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `age` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `startNameAddress` varchar(150) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'none',
  `locationCoordinate` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'none',
  `education` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `license_type` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `national_number` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `car_plate` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `make` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `model` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `color` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `color_hex` char(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `token` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `rating` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `countRide` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `passengerId` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `timeSelected` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `createdAt` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  `status` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT 'pending',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `notesForDriverService`
--

DROP TABLE IF EXISTS `notesForDriverService`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `notesForDriverService` (
  `id` int NOT NULL AUTO_INCREMENT,
  `phone` varchar(70) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
  `note` varchar(250) NOT NULL,
  `editor` varchar(50) NOT NULL,
  `createdAt` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `phone` (`phone`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `notesForPassengerService`
--

DROP TABLE IF EXISTS `notesForPassengerService`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `notesForPassengerService` (
  `id` int NOT NULL AUTO_INCREMENT,
  `phone` int NOT NULL,
  `note` varchar(250) NOT NULL,
  `editor` varchar(50) NOT NULL,
  `createdAt` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `notificationCaptain`
--

DROP TABLE IF EXISTS `notificationCaptain`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `notificationCaptain` (
  `id` int NOT NULL AUTO_INCREMENT,
  `driverID` varchar(80) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `title` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL,
  `body` varchar(200) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL,
  `isShown` varchar(6) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'false',
  `isPin` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'unPin',
  `dateCreated` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `notifications`
--

DROP TABLE IF EXISTS `notifications`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `notifications` (
  `id` int NOT NULL AUTO_INCREMENT,
  `title` varchar(111) NOT NULL,
  `body` varchar(265) NOT NULL,
  `passenger_id` varchar(111) NOT NULL,
  `isShown` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL DEFAULT 'false',
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8mb3;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `otp_verification_fingerPrint`
--

DROP TABLE IF EXISTS `otp_verification_fingerPrint`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `otp_verification_fingerPrint` (
  `id` int NOT NULL,
  `phone` varchar(20) NOT NULL,
  `otp` varchar(6) NOT NULL,
  `createdAt` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `packageInfo`
--

DROP TABLE IF EXISTS `packageInfo`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `packageInfo` (
  `id` int NOT NULL AUTO_INCREMENT,
  `platform` varchar(50) NOT NULL,
  `appName` varchar(20) NOT NULL,
  `createdAt` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `version` varchar(10) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `palces11`
--

DROP TABLE IF EXISTS `palces11`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `palces11` (
  `id` int NOT NULL AUTO_INCREMENT,
  `latitude` varchar(50) NOT NULL,
  `longitude` varchar(50) NOT NULL,
  `name` varchar(180) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,
  `name_ar` varchar(200) NOT NULL,
  `name_en` varchar(200) NOT NULL,
  `address` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,
  `category` varchar(55) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `location` point NOT NULL,
  PRIMARY KEY (`id`),
  SPATIAL KEY `idx_spatial_location` (`location`),
  FULLTEXT KEY `idx_fulltext_search` (`name`,`name_ar`,`name_en`,`address`,`category`)
) ENGINE=InnoDB AUTO_INCREMENT=28951 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `passengerWallet`
--

DROP TABLE IF EXISTS `passengerWallet`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `passengerWallet` (
  `id` int NOT NULL AUTO_INCREMENT,
  `passenger_id` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `balance` decimal(10,2) NOT NULL,
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  KEY `passenger_id` (`passenger_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `passenger_blacklist`
--

DROP TABLE IF EXISTS `passenger_blacklist`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `passenger_blacklist` (
  `id` bigint unsigned NOT NULL AUTO_INCREMENT,
  `phone` varchar(150) NOT NULL,
  `phone_normalized` varchar(64) NOT NULL,
  `reason` varchar(255) DEFAULT NULL,
  `expires_at` datetime DEFAULT CURRENT_TIMESTAMP,
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `uq_phone_norm` (`phone_normalized`),
  KEY `idx_expires` (`expires_at`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb3;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `passengerlocation`
--

DROP TABLE IF EXISTS `passengerlocation`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `passengerlocation` (
  `id` int NOT NULL AUTO_INCREMENT,
  `passengerId` varchar(60) NOT NULL,
  `lat` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
  `lng` varchar(20) NOT NULL,
  `rideId` varchar(10) NOT NULL,
  `createdAt` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3172 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `passengers`
--

DROP TABLE IF EXISTS `passengers`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `passengers` (
  `id` varchar(100) NOT NULL,
  `phone` varchar(150) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL,
  `email` varchar(255) NOT NULL,
  `password` varchar(100) NOT NULL,
  `gender` varchar(150) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL,
  `status` varchar(150) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL DEFAULT 'notDeleted',
  `birthdate` varchar(150) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL,
  `site` varchar(255) NOT NULL,
  `first_name` varchar(255) NOT NULL,
  `last_name` varchar(255) NOT NULL,
  `sosPhone` varchar(150) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL DEFAULT 'sos',
  `education` varchar(150) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL DEFAULT 'none',
  `employmentType` varchar(150) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL DEFAULT 'none',
  `maritalStatus` varchar(150) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL DEFAULT 'none',
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `phone` (`phone`,`email`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `payment_tokens`
--

DROP TABLE IF EXISTS `payment_tokens`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `payment_tokens` (
  `id` int NOT NULL AUTO_INCREMENT,
  `token` varchar(255) NOT NULL,
  `driverID` varchar(255) NOT NULL,
  `dateCreated` datetime NOT NULL,
  `amount` decimal(10,2) NOT NULL,
  `isUsed` tinyint(1) DEFAULT '0',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `payment_tokens_passenger`
--

DROP TABLE IF EXISTS `payment_tokens_passenger`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `payment_tokens_passenger` (
  `id` int NOT NULL AUTO_INCREMENT,
  `token` varchar(255) NOT NULL,
  `passengerId` varchar(255) NOT NULL,
  `dateCreated` datetime NOT NULL,
  `amount` decimal(10,2) NOT NULL,
  `isUsed` tinyint(1) DEFAULT '0',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `payments`
--

DROP TABLE IF EXISTS `payments`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `payments` (
  `id` varchar(111) NOT NULL,
  `amount` decimal(10,2) NOT NULL,
  `payment_method` varchar(255) NOT NULL,
  `passengerID` varchar(100) NOT NULL,
  `rideId` varchar(100) NOT NULL,
  `driverID` varchar(100) NOT NULL,
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `isGiven` varchar(20) NOT NULL DEFAULT 'waiting',
  PRIMARY KEY (`id`),
  UNIQUE KEY `rideId` (`rideId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `paymentsDriverPoints`
--

DROP TABLE IF EXISTS `paymentsDriverPoints`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `paymentsDriverPoints` (
  `id` int NOT NULL AUTO_INCREMENT,
  `amount` decimal(10,2) NOT NULL,
  `payment_method` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `driverID` varchar(60) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `created_at` datetime DEFAULT CURRENT_TIMESTAMP,
  `updated_at` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `phone_verification`
--

DROP TABLE IF EXISTS `phone_verification`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `phone_verification` (
  `id` int NOT NULL AUTO_INCREMENT,
  `phone_number` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
  `driverId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT 'yet',
  `email` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT 'yet',
  `token_code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
  `expiration_time` datetime NOT NULL,
  `is_verified` tinyint(1) DEFAULT '0',
  `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=111 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `phone_verification_passenger`
--

DROP TABLE IF EXISTS `phone_verification_passenger`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `phone_verification_passenger` (
  `id` int NOT NULL AUTO_INCREMENT,
  `phone_number` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,
  `token` varchar(80) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
  `expiration_time` datetime NOT NULL,
  `verified` tinyint(1) DEFAULT '0',
  `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  `status` varchar(22) NOT NULL DEFAULT 'yet',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=109 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `places`
--

DROP TABLE IF EXISTS `places`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `places` (
  `id` int NOT NULL AUTO_INCREMENT,
  `latitude` double NOT NULL,
  `longitude` double NOT NULL,
  `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `name_ar` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `name_en` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `address` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `category` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=8996 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `placesEgypt`
--

DROP TABLE IF EXISTS `placesEgypt`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `placesEgypt` (
  `id` int NOT NULL,
  `nameEnglish` varchar(255) DEFAULT NULL,
  `nameArabic` varchar(255) DEFAULT NULL,
  `phone` varchar(20) DEFAULT NULL,
  `countReview` int DEFAULT NULL,
  `rate` float DEFAULT NULL,
  `stars` varchar(50) DEFAULT NULL,
  `address` text,
  `website` varchar(255) DEFAULT NULL,
  `email` varchar(255) DEFAULT NULL,
  `PlusCode` varchar(50) DEFAULT NULL,
  `closeTime` varchar(50) DEFAULT NULL,
  `latitude` decimal(10,6) DEFAULT NULL,
  `longitude` decimal(10,6) DEFAULT NULL,
  `instagram` varchar(255) DEFAULT NULL,
  `facebook` varchar(255) DEFAULT NULL,
  `linkedin` varchar(255) DEFAULT NULL,
  `twitter` varchar(255) DEFAULT NULL,
  `photo` varchar(255) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `promos`
--

DROP TABLE IF EXISTS `promos`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `promos` (
  `id` int NOT NULL AUTO_INCREMENT,
  `promo_code` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `amount` varchar(4) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '0',
  `description` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL,
  `passengerID` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'none',
  `validity_start_date` date DEFAULT NULL,
  `validity_end_date` date DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `passengerID` (`passengerID`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `promptDriverIDEgypt`
--

DROP TABLE IF EXISTS `promptDriverIDEgypt`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `promptDriverIDEgypt` (
  `id` int NOT NULL AUTO_INCREMENT,
  `type` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `prompt` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `createdAt` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  `updatedAt` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `ratingApp`
--

DROP TABLE IF EXISTS `ratingApp`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `ratingApp` (
  `id` int NOT NULL AUTO_INCREMENT,
  `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `email` varchar(150) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `phone` varchar(80) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `userId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `userType` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `rating` varchar(2) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `comment` varchar(300) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `ratingDriver`
--

DROP TABLE IF EXISTS `ratingDriver`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `ratingDriver` (
  `id` int NOT NULL AUTO_INCREMENT,
  `passenger_id` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci,
  `driver_id` varchar(33) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `ride_id` int DEFAULT NULL,
  `rating` float DEFAULT NULL,
  `comment` text CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci,
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `ride_id` (`ride_id`),
  KEY `idx_driver_id` (`driver_id`)
) ENGINE=InnoDB AUTO_INCREMENT=17 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `ratingPassenger`
--

DROP TABLE IF EXISTS `ratingPassenger`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `ratingPassenger` (
  `id` int NOT NULL AUTO_INCREMENT,
  `passenger_id` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `driverID` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `rideId` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `rating` float NOT NULL,
  `comment` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci,
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `rideId` (`rideId`)
) ENGINE=InnoDB AUTO_INCREMENT=17 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `ride`
--

DROP TABLE IF EXISTS `ride`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `ride` (
  `id` int NOT NULL AUTO_INCREMENT,
  `start_location` varchar(255) NOT NULL,
  `end_location` varchar(255) NOT NULL,
  `date` date NOT NULL,
  `time` time NOT NULL,
  `endtime` time NOT NULL,
  `price` decimal(10,2) NOT NULL DEFAULT '0.00',
  `passenger_id` varchar(111) NOT NULL,
  `driver_id` varchar(111) NOT NULL,
  `status` varchar(200) NOT NULL DEFAULT 'nothing',
  `paymentMethod` varchar(20) NOT NULL DEFAULT 'Cash',
  `carType` varchar(20) NOT NULL DEFAULT 'Speed',
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `DriverIsGoingToPassenger` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `rideTimeStart` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `rideTimeFinish` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `price_for_driver` decimal(10,2) NOT NULL DEFAULT '0.00',
  `price_for_passenger` decimal(10,2) NOT NULL DEFAULT '0.00',
  `distance` float DEFAULT '0',
  PRIMARY KEY (`id`),
  KEY `passengerfk` (`passenger_id`),
  KEY `driverfk` (`driver_id`)
) ENGINE=InnoDB AUTO_INCREMENT=94 DEFAULT CHARSET=utf8mb3;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `seferWallet`
--

DROP TABLE IF EXISTS `seferWallet`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `seferWallet` (
  `id` int NOT NULL AUTO_INCREMENT,
  `driverId` varchar(100) NOT NULL,
  `passengerId` varchar(100) NOT NULL,
  `amount` varchar(10) NOT NULL,
  `paymentMethod` varchar(50) NOT NULL,
  `token` varchar(100) NOT NULL,
  `createdAt` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `server_locations`
--

DROP TABLE IF EXISTS `server_locations`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `server_locations` (
  `id` int NOT NULL AUTO_INCREMENT,
  `name` varchar(255) NOT NULL,
  `min_latitude` decimal(10,6) NOT NULL,
  `max_latitude` decimal(10,6) NOT NULL,
  `min_longitude` decimal(10,6) NOT NULL,
  `max_longitude` decimal(10,6) NOT NULL,
  `server_link` varchar(255) NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `name` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `smsSender`
--

DROP TABLE IF EXISTS `smsSender`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `smsSender` (
  `id` int NOT NULL AUTO_INCREMENT,
  `senderId` varchar(20) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `test`
--

DROP TABLE IF EXISTS `test`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `test` (
  `id` int NOT NULL AUTO_INCREMENT,
  `name` varchar(22) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `testApp`
--

DROP TABLE IF EXISTS `testApp`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `testApp` (
  `id` int NOT NULL AUTO_INCREMENT,
  `isTest` tinyint(1) NOT NULL,
  `createdAt` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `appPlatform` varchar(20) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `tips`
--

DROP TABLE IF EXISTS `tips`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `tips` (
  `id` int NOT NULL AUTO_INCREMENT,
  `driverID` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `passengerID` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `rideID` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `tipAmount` decimal(10,2) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `token_verification`
--

DROP TABLE IF EXISTS `token_verification`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `token_verification` (
  `id` int NOT NULL AUTO_INCREMENT,
  `phone_number` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `token` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `expiration_time` datetime NOT NULL,
  `verified` tinyint(1) DEFAULT '0',
  `created_at` datetime DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=49 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `token_verification_admin`
--

DROP TABLE IF EXISTS `token_verification_admin`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `token_verification_admin` (
  `id` int NOT NULL AUTO_INCREMENT,
  `phone_number` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `token` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `expiration_time` datetime NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `phone_number` (`phone_number`)
) ENGINE=InnoDB AUTO_INCREMENT=29 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `token_verification_driver`
--

DROP TABLE IF EXISTS `token_verification_driver`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `token_verification_driver` (
  `id` int NOT NULL AUTO_INCREMENT,
  `phone_number` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `token` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `expiration_time` datetime NOT NULL,
  `verified` tinyint(1) NOT NULL DEFAULT '0',
  `created_at` datetime DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=49 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `tokens`
--

DROP TABLE IF EXISTS `tokens`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `tokens` (
  `id` int NOT NULL AUTO_INCREMENT,
  `token` varchar(333) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `passengerID` varchar(80) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `fingerPrint` varchar(250) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `status` varchar(22) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'yet',
  PRIMARY KEY (`id`),
  UNIQUE KEY `passengerID` (`passengerID`)
) ENGINE=InnoDB AUTO_INCREMENT=53 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `users`
--

DROP TABLE IF EXISTS `users`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `users` (
  `id` varchar(111) NOT NULL,
  `phone` varchar(15) NOT NULL,
  `email` varchar(255) NOT NULL,
  `gender` varchar(10) NOT NULL,
  `password` varchar(100) NOT NULL,
  `birthdate` date NOT NULL,
  `site` varchar(255) NOT NULL,
  `first_name` varchar(255) NOT NULL,
  `last_name` varchar(255) NOT NULL,
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `user_type` varchar(44) NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `email` (`email`),
  UNIQUE KEY `phone` (`phone`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `vehicles`
--

DROP TABLE IF EXISTS `vehicles`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `vehicles` (
  `id` int NOT NULL AUTO_INCREMENT,
  `driverID` varchar(100) NOT NULL,
  `make` varchar(255) NOT NULL,
  `model` varchar(255) NOT NULL,
  `license_plate` varchar(255) NOT NULL,
  `seats` int NOT NULL,
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `license_plate` (`license_plate`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `videos`
--

DROP TABLE IF EXISTS `videos`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `videos` (
  `id` int NOT NULL AUTO_INCREMENT,
  `title` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `description` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `url` varchar(150) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `waitingRides`
--

DROP TABLE IF EXISTS `waitingRides`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `waitingRides` (
  `id` varchar(100) NOT NULL,
  `start_location` varchar(255) NOT NULL,
  `end_location` varchar(255) NOT NULL,
  `date` date NOT NULL,
  `time` time NOT NULL,
  `price` decimal(10,2) NOT NULL DEFAULT '0.00',
  `passenger_id` varchar(111) NOT NULL,
  `status` varchar(200) NOT NULL DEFAULT 'nothing',
  `carType` varchar(19) NOT NULL,
  `passengerRate` decimal(10,2) NOT NULL,
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `price_for_passenger` decimal(10,2) NOT NULL DEFAULT '0.00',
  `distance` varchar(255) NOT NULL,
  `duration` varchar(10) NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `welcomeDriverCall`
--

DROP TABLE IF EXISTS `welcomeDriverCall`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `welcomeDriverCall` (
  `id` int NOT NULL AUTO_INCREMENT,
  `driverId` varchar(50) NOT NULL,
  `isCall` tinyint(1) NOT NULL DEFAULT '0',
  `notes` varchar(255) NOT NULL,
  `createdAt` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `write_argument_after_applied_from_background`
--

DROP TABLE IF EXISTS `write_argument_after_applied_from_background`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `write_argument_after_applied_from_background` (
  `id` int unsigned NOT NULL AUTO_INCREMENT,
  `ride_id` varchar(50) NOT NULL,
  `driver_id` varchar(50) NOT NULL,
  `passenger_id` varchar(50) NOT NULL,
  `passenger_location` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
  `passenger_destination` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
  `duration` varchar(255) NOT NULL,
  `duration_to_passenger` varchar(255) NOT NULL,
  `duration_of_ride` varchar(255) NOT NULL,
  `distance` varchar(255) NOT NULL,
  `total_cost` varchar(255) NOT NULL,
  `payment_amount` varchar(255) NOT NULL,
  `payment_method` enum('visa','cash') NOT NULL,
  `wallet_checked` varchar(255) NOT NULL,
  `has_steps` varchar(255) NOT NULL,
  `step0` varchar(255) DEFAULT NULL,
  `step1` varchar(255) DEFAULT NULL,
  `step2` varchar(255) DEFAULT NULL,
  `step3` varchar(255) DEFAULT NULL,
  `step4` varchar(255) DEFAULT NULL,
  `passenger_wallet_burc` varchar(33) NOT NULL,
  `token_passenger` varchar(255) NOT NULL,
  `name` varchar(100) NOT NULL,
  `phone` varchar(20) NOT NULL,
  `email` varchar(150) NOT NULL,
  `start_name_location` varchar(255) NOT NULL,
  `end_name_location` varchar(255) NOT NULL,
  `car_type` varchar(50) NOT NULL,
  `kazan` varchar(255) NOT NULL,
  `direction_url` text NOT NULL,
  `time_of_order` datetime NOT NULL,
  `total_passenger` varchar(255) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Dumping events for database 'locationDB'
--

--
-- Dumping routines for database 'locationDB'
--
/*!50112 SET @disable_bulk_load = IF (@is_rocksdb_supported, 'SET SESSION rocksdb_bulk_load = @old_rocksdb_bulk_load', 'SET @dummy_rocksdb_bulk_load = 0') */;
/*!50112 PREPARE s FROM @disable_bulk_load */;
/*!50112 EXECUTE s */;
/*!50112 DEALLOCATE PREPARE s */;
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;

/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;

-- Dump completed on 2026-04-22 20:48:59

File: loginJwtDriver.php

<?php
// ============================================================
// loginJwtDriver.php — تجديد توكن السائق
// ============================================================

require_once __DIR__ . '/core/bootstrap.php';

header('Content-Type: application/json; charset=utf-8');
header('Access-Control-Allow-Origin: https://intaleqapp.com');
header('Access-Control-Allow-Methods: POST, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type, Authorization, X-Device-FP');

if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
    http_response_code(204);
    exit;
}

$startTime = microtime(true);

function unauthorizedDriver(): never {
    global $startTime;
    $elapsed = microtime(true) - $startTime;
    if ($elapsed < 0.1) usleep((int)((0.1 - $elapsed) * 1000000));
    jsonError('Invalid driver credentials', 401);
}

try {
    $limiter = new RateLimiter($redis);
    $limiter->enforce(RateLimiter::identifier(), 'login');

    $id          = filterRequest('id');
    $audience    = filterRequest('aud');
    $fingerprint = filterRequest('fingerPrint') ?? filterRequest('fingerprint'); 

    $aud1 = getenv('allowedDriver1');
    $aud2 = getenv('allowedDriver2');
    $allowedAudiences = array_values(array_filter([$aud1, $aud2]));

    if (empty($id) || empty($audience)) {
        jsonError('Missing required fields', 400);
    }

    if (!in_array($audience, $allowedAudiences, true)) {
        jsonError('Invalid audience', 400);
    }

    $con = Database::get('main');
    $pepper = getenv('SECRET_KEY_HMAC');

    $stmt = $con->prepare('
        SELECT id, phone, national_number, email, password
        FROM driver
        WHERE id = :id
        LIMIT 1
    ');
    $stmt->execute([':id' => $id]);
    $driver = $stmt->fetch();

    if (!$driver || empty($driver['password'])) {
        unauthorizedDriver();
    }

    $decPhone = !empty($driver['phone']) ? $encryptionHelper->decryptData($driver['phone']) : null;
    $decNat   = !empty($driver['national_number']) ? $encryptionHelper->decryptData($driver['national_number']) : null;

    if (empty($decPhone) || empty($decNat)) {
        unauthorizedDriver();
    }

    $baseString = $driver['id'] . '|' . trim($decPhone) . '|' . trim($decNat);
    $hmacHex    = hash_hmac('sha256', $baseString, $pepper, false);

    if (!password_verify($hmacHex, $driver['password'])) {
        unauthorizedDriver();
    }

    $limiter->reset(RateLimiter::identifier(), 'login');

    $jwtService = new JwtService($redis);
    $jwt = $jwtService->generateAccessToken($driver['id'], 'driver', $audience, $fingerprint);
    $refresh = $jwtService->generateRefreshToken($driver['id']);

    jsonSuccess([
        'jwt' => $jwt,
        'refresh_token' => $refresh['token'],
        'expires_in' => 900
    ]);

} catch (PDOException $e) {
    securityLog("LoginDriver PDO Error", ['msg' => $e->getMessage()]);
    jsonError('Database error', 500);
} catch (Exception $e) {
    securityLog("LoginDriver Error", ['msg' => $e->getMessage()]);
    jsonError('Server error', 500);
}

File: get_connect.php

<?php
// ============================================================
// get_connect.php
// بديل con.php و jwtconnect.php للاتصالات الداخلية
// ============================================================

require_once __DIR__ . '/core/bootstrap.php';

// 1. التحقق من مفتاح الحماية الداخلي (بديل الـ JWT للسيرفرات)
JwtService::validateInternalKey();

// 2. Rate Limiting خفيف للطلبات الداخلية
$limiter = new RateLimiter($redis);
$limiter->enforce(RateLimiter::identifier(), 'api');

// 3. الاتصال الافتراضي بقاعدة البيانات (Lazy Load)
try {
    $con = Database::get('main');
} catch (Exception $e) {
    http_response_code(500);
    exit(json_encode(['error' => 'Database connection failed']));
}

File: composer.json

{
    "require": {
        "vlucas/phpdotenv": "^5.6"
    }
}

File: upload_audio.php

<?php
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
require_once __DIR__ . '/connect.php'; // Ensure this is correct and contains the connection logic

// Get the audio file from the request
$audio_file = $_FILES['audio'];
$passengerId = filterRequest("passengerId"); // Ensure this is defined correctly

// Check if the audio file was uploaded successfully
if ($audio_file['error'] !== UPLOAD_ERR_OK) {
    error_log("File upload error: " . $audio_file['error']);
    echo json_encode(array('status' => 'The audio file was not uploaded successfully.'));
    exit;
}

// Get the file name and extension of the audio file
$audio_name = $audio_file['name'];
$audio_extension = pathinfo($audio_name, PATHINFO_EXTENSION);

// Check if the audio file is a valid audio format
if (!in_array($audio_extension, array('m4a', 'mp3', 'wav'))) {
    echo json_encode(array('status' => 'The audio file is not a valid format.'));
    exit;
}

// Generate a new filename using the passenger ID to avoid conflicts
$new_filename = $audio_name . '.' . $audio_extension;

// Move the audio file to the uploads directory with the new filename
$target_dir = "audio_uploads/";
if (!is_dir($target_dir)) {
    mkdir($target_dir, 0755, true); // Create directory if it doesn't exist
}
$target_file = $target_dir . $new_filename;
if (!move_uploaded_file($audio_file['tmp_name'], $target_file)) {
    error_log("Failed to move file to target directory: " . print_r($audio_file, true));
    echo json_encode(array('status' => 'Failed to move the audio file.'));
    exit;
}

// Construct the link to the uploaded audio file
$base_url = 'https://sefer.click/sefer/audio_uploads/'; // Replace with your actual domain
$linkAudio = $base_url . $new_filename;

// Respond with success and the audio file link
echo json_encode(array('status' => 'Audio file uploaded successfully.', 'link' => $linkAudio));

// Close the database connection if it was established
if (isset($conn)) {
    mysqli_close($conn);
}
?>

File: schema_ride.sql

-- MySQL dump 10.13  Distrib 8.0.36-28, for Linux (x86_64)
--
-- Host: localhost    Database: intaleq-ridesDB
-- ------------------------------------------------------
-- Server version	8.0.36-28

/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!50503 SET NAMES utf8mb4 */;
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
/*!40103 SET TIME_ZONE='+00:00' */;
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
/*!50717 SELECT COUNT(*) INTO @rocksdb_has_p_s_session_variables FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'performance_schema' AND TABLE_NAME = 'session_variables' */;
/*!50717 SET @rocksdb_get_is_supported = IF (@rocksdb_has_p_s_session_variables, 'SELECT COUNT(*) INTO @rocksdb_is_supported FROM performance_schema.session_variables WHERE VARIABLE_NAME=\'rocksdb_bulk_load\'', 'SELECT 0') */;
/*!50717 PREPARE s FROM @rocksdb_get_is_supported */;
/*!50717 EXECUTE s */;
/*!50717 DEALLOCATE PREPARE s */;
/*!50717 SET @rocksdb_enable_bulk_load = IF (@rocksdb_is_supported, 'SET SESSION rocksdb_bulk_load = 1', 'SET @rocksdb_dummy_bulk_load = 0') */;
/*!50717 PREPARE s FROM @rocksdb_enable_bulk_load */;
/*!50717 EXECUTE s */;
/*!50717 DEALLOCATE PREPARE s */;

--
-- Table structure for table `CarRegistration`
--

DROP TABLE IF EXISTS `CarRegistration`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `CarRegistration` (
  `id` int NOT NULL AUTO_INCREMENT,
  `driverID` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL,
  `vin` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL,
  `car_plate` varchar(150) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL,
  `make` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL,
  `model` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL,
  `year` varchar(10) CHARACTER SET utf32 COLLATE utf32_general_ci NOT NULL,
  `expiration_date` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `color` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL,
  `owner` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL,
  `color_hex` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `fuel` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL,
  `isDefault` tinyint(1) NOT NULL DEFAULT '0',
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `status` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'yet',
  PRIMARY KEY (`id`),
  UNIQUE KEY `car_plate` (`car_plate`),
  KEY `idx_driverID` (`driverID`)
) ENGINE=InnoDB AUTO_INCREMENT=14 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `adminUser`
--

DROP TABLE IF EXISTS `adminUser`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `adminUser` (
  `id` int NOT NULL AUTO_INCREMENT,
  `device_number` varchar(300) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `name` varchar(150) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `api_keys`
--

DROP TABLE IF EXISTS `api_keys`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `api_keys` (
  `id` int NOT NULL AUTO_INCREMENT,
  `name` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `hashed_key` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `blacklist_driver`
--

DROP TABLE IF EXISTS `blacklist_driver`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `blacklist_driver` (
  `id` int NOT NULL AUTO_INCREMENT,
  `driver_id` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `phone` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `reason` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT 'Violation',
  `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `canecl`
--

DROP TABLE IF EXISTS `canecl`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `canecl` (
  `id` int NOT NULL AUTO_INCREMENT,
  `driverID` varchar(111) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `passengerID` varchar(111) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `rideID` varchar(111) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `note` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT 'nothing',
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `captains_car`
--

DROP TABLE IF EXISTS `captains_car`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `captains_car` (
  `id` int NOT NULL AUTO_INCREMENT,
  `driverID` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `vin` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `car_plate` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `make` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `model` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `year` varchar(6) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `expiration_date` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `color` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `owner` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `color_hex` char(15) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `address` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `displacement` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `fuel` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `registration_date` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `isDefault` tinyint(1) NOT NULL DEFAULT '0',
  `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `car_plate` (`car_plate`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `carPlateEdit`
--

DROP TABLE IF EXISTS `carPlateEdit`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `carPlateEdit` (
  `id` int NOT NULL AUTO_INCREMENT,
  `driverId` varchar(50) NOT NULL,
  `carPlate` varchar(155) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
  `color` varchar(20) NOT NULL,
  `make` varchar(50) NOT NULL,
  `model` varchar(20) NOT NULL,
  `expiration_date` varchar(50) NOT NULL,
  `owner` varchar(155) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
  `year` int NOT NULL,
  `isEdit` tinyint(1) NOT NULL DEFAULT '0',
  `employee` varchar(30) NOT NULL DEFAULT 'any',
  `createdAt` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `driverId` (`driverId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `car_locations`
--

DROP TABLE IF EXISTS `car_locations`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `car_locations` (
  `driver_id` varchar(100) NOT NULL,
  `latitude` decimal(10,7) NOT NULL,
  `longitude` decimal(10,7) NOT NULL,
  `heading` decimal(10,2) NOT NULL,
  `speed` double(10,3) NOT NULL,
  `distance` decimal(10,2) NOT NULL,
  `status` varchar(6) NOT NULL DEFAULT 'off',
  `carType` varchar(100) NOT NULL DEFAULT 'Awfar',
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `location_point` point NOT NULL /*!80003 SRID 4326 */,
  PRIMARY KEY (`driver_id`),
  KEY `idx_loc_status_time` (`status`,`updated_at`,`latitude`,`longitude`),
  SPATIAL KEY `idx_location_point` (`location_point`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;
/*!40101 SET character_set_client = @saved_cs_client */;
/*!50003 SET @saved_cs_client      = @@character_set_client */ ;
/*!50003 SET @saved_cs_results     = @@character_set_results */ ;
/*!50003 SET @saved_col_connection = @@collation_connection */ ;
/*!50003 SET character_set_client  = utf8mb4 */ ;
/*!50003 SET character_set_results = utf8mb4 */ ;
/*!50003 SET collation_connection  = utf8mb4_0900_ai_ci */ ;
/*!50003 SET @saved_sql_mode       = @@sql_mode */ ;
/*!50003 SET sql_mode              = 'NO_AUTO_VALUE_ON_ZERO' */ ;
DELIMITER ;;
/*!50003 CREATE*/ /*!50017 DEFINER=`intaleq-rides`@`%`*/ /*!50003 TRIGGER `trg_before_insert_car_locations` BEFORE INSERT ON `car_locations` FOR EACH ROW BEGIN
SET NEW.location_point = ST_PointFromText(CONCAT('POINT(', NEW.longitude, ' ', NEW.latitude, ')'), 4326);
END */;;
DELIMITER ;
/*!50003 SET sql_mode              = @saved_sql_mode */ ;
/*!50003 SET character_set_client  = @saved_cs_client */ ;
/*!50003 SET character_set_results = @saved_cs_results */ ;
/*!50003 SET collation_connection  = @saved_col_connection */ ;
/*!50003 SET @saved_cs_client      = @@character_set_client */ ;
/*!50003 SET @saved_cs_results     = @@character_set_results */ ;
/*!50003 SET @saved_col_connection = @@collation_connection */ ;
/*!50003 SET character_set_client  = utf8mb4 */ ;
/*!50003 SET character_set_results = utf8mb4 */ ;
/*!50003 SET collation_connection  = utf8mb4_0900_ai_ci */ ;
/*!50003 SET @saved_sql_mode       = @@sql_mode */ ;
/*!50003 SET sql_mode              = 'NO_AUTO_VALUE_ON_ZERO' */ ;
DELIMITER ;;
/*!50003 CREATE*/ /*!50017 DEFINER=`intaleq-rides`@`%`*/ /*!50003 TRIGGER `trg_before_update_car_locations` BEFORE UPDATE ON `car_locations` FOR EACH ROW BEGIN
IF NEW.latitude <> OLD.latitude OR NEW.longitude <> OLD.longitude THEN
SET NEW.location_point = ST_PointFromText(CONCAT('POINT(', NEW.longitude, ' ', NEW.latitude, ')'), 4326);
END IF;
END */;;
DELIMITER ;
/*!50003 SET sql_mode              = @saved_sql_mode */ ;
/*!50003 SET character_set_client  = @saved_cs_client */ ;
/*!50003 SET character_set_results = @saved_cs_results */ ;
/*!50003 SET collation_connection  = @saved_col_connection */ ;

--
-- Table structure for table `car_tracks`
--

DROP TABLE IF EXISTS `car_tracks`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `car_tracks` (
  `id` int NOT NULL AUTO_INCREMENT,
  `driver_id` varchar(100) NOT NULL,
  `latitude` decimal(10,7) NOT NULL,
  `longitude` decimal(10,7) NOT NULL,
  `heading` float DEFAULT NULL,
  `speed` float DEFAULT NULL,
  `distance` float DEFAULT NULL,
  `status` enum('on','off') DEFAULT 'off',
  `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `card_images`
--

DROP TABLE IF EXISTS `card_images`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `card_images` (
  `id` int NOT NULL AUTO_INCREMENT,
  `driverID` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `image_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `upload_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `link` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `carsToWork`
--

DROP TABLE IF EXISTS `carsToWork`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `carsToWork` (
  `id` int NOT NULL AUTO_INCREMENT,
  `owner_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `phone` varchar(15) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `car_number` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `manufacture_year` year NOT NULL,
  `car_model` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `car_type` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `site` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `registration_date` date NOT NULL,
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `complaint`
--

DROP TABLE IF EXISTS `complaint`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `complaint` (
  `id` int NOT NULL AUTO_INCREMENT,
  `ride_id` varchar(255) NOT NULL,
  `passenger_id` varchar(255) DEFAULT NULL,
  `driver_id` varchar(255) DEFAULT NULL,
  `complaint_type` enum('Driver','Passenger','Both') NOT NULL,
  `description` text,
  `date_filed` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  `statusComplaint` enum('Open','In Progress','Resolved') NOT NULL DEFAULT 'Open',
  `resolution` text,
  `passenger_report` text,
  `driver_report` text,
  `cs_solutions` text,
  `fault_determination` varchar(255) DEFAULT NULL,
  `complaint_nature` varchar(255) DEFAULT NULL,
  `date_resolved` timestamp NULL DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `contactEgypt`
--

DROP TABLE IF EXISTS `contactEgypt`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `contactEgypt` (
  `id` int NOT NULL AUTO_INCREMENT,
  `phones` varchar(20) NOT NULL,
  `name` varchar(100) NOT NULL,
  `phones2` varchar(60) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
  `createdAt` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `contactSyria`
--

DROP TABLE IF EXISTS `contactSyria`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `contactSyria` (
  `id` int NOT NULL AUTO_INCREMENT,
  `driverId` varchar(255) NOT NULL COMMENT 'معرّف السائق الذي قام بمزامنة جهة الاتصال',
  `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT 'اسم جهة الاتصال',
  `phone` varchar(50) NOT NULL COMMENT 'رقم هاتف جهة الاتصال',
  `sync_timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'وقت المزامنة',
  PRIMARY KEY (`id`),
  UNIQUE KEY `driver_contact_unique` (`driverId`,`phone`)
) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `criminalDocuments`
--

DROP TABLE IF EXISTS `criminalDocuments`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `criminalDocuments` (
  `id` int NOT NULL AUTO_INCREMENT,
  `driverId` varchar(50) NOT NULL,
  `IssueDate` varchar(20) NOT NULL,
  `createdAt` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `InspectionResult` varchar(100) NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `driverId` (`driverId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `driver`
--

DROP TABLE IF EXISTS `driver`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `driver` (
  `idn` int NOT NULL AUTO_INCREMENT,
  `id` varchar(100) NOT NULL,
  `phone` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL,
  `email` varchar(255) NOT NULL,
  `password` varchar(255) NOT NULL,
  `gender` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL DEFAULT 'Male',
  `license_type` varchar(255) DEFAULT NULL,
  `national_number` varchar(255) DEFAULT NULL,
  `name_arabic` varchar(255) DEFAULT NULL,
  `issue_date` date DEFAULT NULL,
  `expiry_date` date DEFAULT NULL,
  `license_categories` varchar(255) DEFAULT NULL,
  `address` text,
  `licenseIssueDate` varchar(50) DEFAULT NULL,
  `status` varchar(20) NOT NULL DEFAULT 'notDeleted',
  `birthdate` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL,
  `site` varchar(255) NOT NULL,
  `first_name` varchar(255) NOT NULL,
  `last_name` varchar(255) NOT NULL,
  `accountBank` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL DEFAULT 'yet',
  `bankCode` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL DEFAULT 'CIB',
  `employmentType` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL,
  `maritalStatus` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL,
  `fullNameMaritial` varchar(255) DEFAULT NULL,
  `expirationDate` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL,
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`idn`)
) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8mb3;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `driverToken`
--

DROP TABLE IF EXISTS `driverToken`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `driverToken` (
  `id` int NOT NULL AUTO_INCREMENT,
  `token` varchar(300) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `captain_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `fingerPrint` varchar(155) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  KEY `idx_captain_id` (`captain_id`)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `driverWallet`
--

DROP TABLE IF EXISTS `driverWallet`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `driverWallet` (
  `id` int NOT NULL AUTO_INCREMENT,
  `driverID` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `paymentID` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `dateCreated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `amount` varchar(5) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `paymentMethod` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `dateUpdated` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `driver_behavior`
--

DROP TABLE IF EXISTS `driver_behavior`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `driver_behavior` (
  `id` int NOT NULL,
  `driver_id` varchar(255) NOT NULL,
  `trip_id` varchar(255) NOT NULL,
  `max_speed` double DEFAULT '0',
  `avg_speed` double DEFAULT '0',
  `hard_brakes` int DEFAULT '0',
  `total_distance` double DEFAULT '0',
  `behavior_score` double DEFAULT '0',
  `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `driver_documents`
--

DROP TABLE IF EXISTS `driver_documents`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `driver_documents` (
  `id` int NOT NULL AUTO_INCREMENT,
  `driverID` varchar(64) NOT NULL,
  `doc_type` varchar(64) NOT NULL,
  `image_name` varchar(255) NOT NULL,
  `link` varchar(512) NOT NULL,
  `upload_date` datetime NOT NULL,
  PRIMARY KEY (`id`),
  KEY `driverID` (`driverID`)
) ENGINE=InnoDB AUTO_INCREMENT=33 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `driver_gifts`
--

DROP TABLE IF EXISTS `driver_gifts`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `driver_gifts` (
  `id` int NOT NULL AUTO_INCREMENT,
  `driver_id` varchar(70) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `gift_description` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `gift_date` datetime DEFAULT CURRENT_TIMESTAMP,
  `is_claimed` tinyint(1) DEFAULT '0',
  PRIMARY KEY (`id`),
  UNIQUE KEY `driver_id` (`driver_id`)
) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `driver_health_assurance`
--

DROP TABLE IF EXISTS `driver_health_assurance`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `driver_health_assurance` (
  `id` int NOT NULL AUTO_INCREMENT,
  `driver_id` varchar(155) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `assured` tinyint(1) DEFAULT '0',
  `date_created` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  `health_insurance_provider` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `driver_id` (`driver_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `driver_orders`
--

DROP TABLE IF EXISTS `driver_orders`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `driver_orders` (
  `id` int NOT NULL AUTO_INCREMENT,
  `driver_id` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `order_id` varchar(99) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL,
  `notes` varchar(200) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL DEFAULT 'nothing',
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `status` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT 'applied',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=44 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `driver_ride_scam`
--

DROP TABLE IF EXISTS `driver_ride_scam`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `driver_ride_scam` (
  `id` int NOT NULL AUTO_INCREMENT,
  `driverID` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `passendgerID` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `rideID` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `isDriverCallPassenger` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `dateCreated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `driversWantWork`
--

DROP TABLE IF EXISTS `driversWantWork`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `driversWantWork` (
  `id` int NOT NULL AUTO_INCREMENT,
  `driver_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `phone` varchar(15) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `national_id` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `birth_date` varchar(15) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `license_type` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `site` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `national_id` (`national_id`),
  UNIQUE KEY `phone` (`phone`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `email_verifications`
--

DROP TABLE IF EXISTS `email_verifications`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `email_verifications` (
  `id` int NOT NULL AUTO_INCREMENT,
  `email` varchar(255) NOT NULL,
  `token` varchar(255) NOT NULL,
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `verified` tinyint(1) NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`),
  UNIQUE KEY `email` (`email`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `employee`
--

DROP TABLE IF EXISTS `employee`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `employee` (
  `id` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `education` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `site` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `phone` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `status` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `phone` (`phone`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `error`
--

DROP TABLE IF EXISTS `error`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `error` (
  `id` int NOT NULL AUTO_INCREMENT,
  `error` varchar(400) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `userId` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `userType` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `phone` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `device` varchar(300) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `details` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci,
  `status` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'new',
  PRIMARY KEY (`id`),
  KEY `idx_error_created_at` (`created_at`),
  KEY `idx_error_phone` (`phone`)
) ENGINE=InnoDB AUTO_INCREMENT=14316 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `feedBack`
--

DROP TABLE IF EXISTS `feedBack`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `feedBack` (
  `id` int NOT NULL AUTO_INCREMENT,
  `passengerId` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `feedBack` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
  `datecreated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `helpCenter`
--

DROP TABLE IF EXISTS `helpCenter`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `helpCenter` (
  `id` int NOT NULL AUTO_INCREMENT,
  `driverID` varchar(89) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `helpQuestion` varchar(300) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL,
  `replay` varchar(400) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'not yet',
  `datecreated` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `hotels`
--

DROP TABLE IF EXISTS `hotels`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `hotels` (
  `id` int NOT NULL,
  `nameEnglish` varchar(255) DEFAULT NULL,
  `nameArabic` varchar(255) DEFAULT NULL,
  `phone` varchar(20) DEFAULT NULL,
  `countReview` int DEFAULT NULL,
  `rate` float DEFAULT NULL,
  `stars` varchar(50) DEFAULT NULL,
  `address` text,
  `website` varchar(255) DEFAULT NULL,
  `email` varchar(255) DEFAULT NULL,
  `PlusCode` varchar(50) DEFAULT NULL,
  `closeTime` varchar(50) DEFAULT NULL,
  `latitude` decimal(10,6) DEFAULT NULL,
  `longitude` decimal(10,6) DEFAULT NULL,
  `instagram` varchar(255) DEFAULT NULL,
  `facebook` varchar(255) DEFAULT NULL,
  `linkedin` varchar(255) DEFAULT NULL,
  `twitter` varchar(255) DEFAULT NULL,
  `photo` varchar(255) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `imageProfileCaptain`
--

DROP TABLE IF EXISTS `imageProfileCaptain`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `imageProfileCaptain` (
  `id` int NOT NULL AUTO_INCREMENT,
  `driverID` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `image_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `upload_date` datetime DEFAULT CURRENT_TIMESTAMP,
  `link` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `invites`
--

DROP TABLE IF EXISTS `invites`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `invites` (
  `id` int NOT NULL AUTO_INCREMENT,
  `driverId` varchar(50) NOT NULL,
  `inviterDriverPhone` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
  `createdAt` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `inviteCode` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
  `isInstall` tinyint(1) NOT NULL DEFAULT '0',
  `isGiftToken` tinyint(1) NOT NULL DEFAULT '0',
  `expirationTime` datetime NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `inviterDriverId` (`inviterDriverPhone`),
  UNIQUE KEY `inviteCode` (`inviteCode`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `invitesToPassengers`
--

DROP TABLE IF EXISTS `invitesToPassengers`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `invitesToPassengers` (
  `id` int NOT NULL AUTO_INCREMENT,
  `driverId` varchar(70) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `passengerID` varchar(80) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'yet',
  `inviterPassengerPhone` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `inviteCode` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `expirationTime` datetime NOT NULL,
  `createdAt` datetime DEFAULT CURRENT_TIMESTAMP,
  `isInstall` tinyint(1) DEFAULT '0',
  `isGiftToken` tinyint(1) NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`),
  UNIQUE KEY `inviteCode` (`inviteCode`)
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `invoice_records`
--

DROP TABLE IF EXISTS `invoice_records`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `invoice_records` (
  `id` int NOT NULL AUTO_INCREMENT,
  `driverID` int NOT NULL,
  `invoice_number` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `amount` decimal(10,2) DEFAULT NULL,
  `date` date DEFAULT NULL,
  `image_link` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci,
  `created_at` datetime DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=36 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `invoicesAdmin`
--

DROP TABLE IF EXISTS `invoicesAdmin`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `invoicesAdmin` (
  `id` int NOT NULL AUTO_INCREMENT,
  `item_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `amount` decimal(10,2) NOT NULL,
  `image_url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=22 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `kazan`
--

DROP TABLE IF EXISTS `kazan`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `kazan` (
  `id` int NOT NULL AUTO_INCREMENT,
  `country` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `kazan` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `comfortPrice` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `speedPrice` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `familyPrice` varchar(4) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `deliveryPrice` varchar(11) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `freePrice` varchar(11) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `latePrice` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `heavyPrice` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `adminId` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `createdAt` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `naturePrice` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `fuelPrice` varchar(6) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `lisenceDetails`
--

DROP TABLE IF EXISTS `lisenceDetails`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `lisenceDetails` (
  `id` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
  `driverID` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
  `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `licenseClass` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `documentNo` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `address` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `height` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `postalCode` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `sex` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `stateCode` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `expireDate` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `dateOfBirth` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `dateCreated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `documentNo` (`documentNo`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `login_attempts`
--

DROP TABLE IF EXISTS `login_attempts`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `login_attempts` (
  `id` int NOT NULL AUTO_INCREMENT,
  `ip_address` varchar(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `attempt_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=18 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `login_attempts_drivers`
--

DROP TABLE IF EXISTS `login_attempts_drivers`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `login_attempts_drivers` (
  `id` int NOT NULL AUTO_INCREMENT,
  `ip_address` varchar(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `attempt_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `mishwaritrips`
--

DROP TABLE IF EXISTS `mishwaritrips`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `mishwaritrips` (
  `id` int NOT NULL AUTO_INCREMENT,
  `driverId` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `phone` varchar(15) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `gender` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `name_english` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `address` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `religion` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `age` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `startNameAddress` varchar(150) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'none',
  `locationCoordinate` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'none',
  `education` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `license_type` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `national_number` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `car_plate` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `make` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `model` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `color` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `color_hex` char(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `token` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `rating` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `countRide` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `passengerId` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `timeSelected` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `createdAt` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  `status` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT 'pending',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `notesForDriverService`
--

DROP TABLE IF EXISTS `notesForDriverService`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `notesForDriverService` (
  `id` int NOT NULL AUTO_INCREMENT,
  `phone` varchar(70) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
  `note` varchar(250) NOT NULL,
  `editor` varchar(50) NOT NULL,
  `createdAt` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `phone` (`phone`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `notesForPassengerService`
--

DROP TABLE IF EXISTS `notesForPassengerService`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `notesForPassengerService` (
  `id` int NOT NULL AUTO_INCREMENT,
  `phone` int NOT NULL,
  `note` varchar(250) NOT NULL,
  `editor` varchar(50) NOT NULL,
  `createdAt` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `notificationCaptain`
--

DROP TABLE IF EXISTS `notificationCaptain`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `notificationCaptain` (
  `id` int NOT NULL AUTO_INCREMENT,
  `driverID` varchar(80) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `title` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL,
  `body` varchar(200) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL,
  `isShown` varchar(6) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'false',
  `isPin` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'unPin',
  `dateCreated` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `notifications`
--

DROP TABLE IF EXISTS `notifications`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `notifications` (
  `id` int NOT NULL AUTO_INCREMENT,
  `title` varchar(111) NOT NULL,
  `body` varchar(265) NOT NULL,
  `passenger_id` varchar(111) NOT NULL,
  `isShown` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL DEFAULT 'false',
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8mb3;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `otp_verification_fingerPrint`
--

DROP TABLE IF EXISTS `otp_verification_fingerPrint`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `otp_verification_fingerPrint` (
  `id` int NOT NULL,
  `phone` varchar(20) NOT NULL,
  `otp` varchar(6) NOT NULL,
  `createdAt` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `packageInfo`
--

DROP TABLE IF EXISTS `packageInfo`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `packageInfo` (
  `id` int NOT NULL AUTO_INCREMENT,
  `platform` varchar(50) NOT NULL,
  `appName` varchar(20) NOT NULL,
  `createdAt` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `version` varchar(10) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `palces11`
--

DROP TABLE IF EXISTS `palces11`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `palces11` (
  `id` int NOT NULL AUTO_INCREMENT,
  `latitude` varchar(50) NOT NULL,
  `longitude` varchar(50) NOT NULL,
  `name` varchar(180) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,
  `name_ar` varchar(200) NOT NULL,
  `name_en` varchar(200) NOT NULL,
  `address` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,
  `category` varchar(55) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `location` point NOT NULL,
  PRIMARY KEY (`id`),
  SPATIAL KEY `idx_spatial_location` (`location`),
  FULLTEXT KEY `idx_fulltext_search` (`name`,`name_ar`,`name_en`,`address`,`category`)
) ENGINE=InnoDB AUTO_INCREMENT=28951 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `passengerWallet`
--

DROP TABLE IF EXISTS `passengerWallet`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `passengerWallet` (
  `id` int NOT NULL AUTO_INCREMENT,
  `passenger_id` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `balance` decimal(10,2) NOT NULL,
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  KEY `passenger_id` (`passenger_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `passenger_blacklist`
--

DROP TABLE IF EXISTS `passenger_blacklist`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `passenger_blacklist` (
  `id` bigint unsigned NOT NULL AUTO_INCREMENT,
  `phone` varchar(150) NOT NULL,
  `phone_normalized` varchar(64) NOT NULL,
  `reason` varchar(255) DEFAULT NULL,
  `expires_at` datetime DEFAULT CURRENT_TIMESTAMP,
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `uq_phone_norm` (`phone_normalized`),
  KEY `idx_expires` (`expires_at`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb3;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `passengerlocation`
--

DROP TABLE IF EXISTS `passengerlocation`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `passengerlocation` (
  `id` int NOT NULL AUTO_INCREMENT,
  `passengerId` varchar(60) NOT NULL,
  `lat` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
  `lng` varchar(20) NOT NULL,
  `rideId` varchar(10) NOT NULL,
  `createdAt` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=31 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `passengers`
--

DROP TABLE IF EXISTS `passengers`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `passengers` (
  `id` varchar(100) NOT NULL,
  `phone` varchar(150) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL,
  `email` varchar(255) NOT NULL,
  `password` varchar(100) NOT NULL,
  `gender` varchar(150) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL,
  `status` varchar(150) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL DEFAULT 'notDeleted',
  `birthdate` varchar(150) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL,
  `site` varchar(255) NOT NULL,
  `first_name` varchar(255) NOT NULL,
  `last_name` varchar(255) NOT NULL,
  `sosPhone` varchar(150) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL DEFAULT 'sos',
  `education` varchar(150) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL DEFAULT 'none',
  `employmentType` varchar(150) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL DEFAULT 'none',
  `maritalStatus` varchar(150) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL DEFAULT 'none',
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `phone` (`phone`,`email`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `payment_tokens`
--

DROP TABLE IF EXISTS `payment_tokens`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `payment_tokens` (
  `id` int NOT NULL AUTO_INCREMENT,
  `token` varchar(255) NOT NULL,
  `driverID` varchar(255) NOT NULL,
  `dateCreated` datetime NOT NULL,
  `amount` decimal(10,2) NOT NULL,
  `isUsed` tinyint(1) DEFAULT '0',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `payment_tokens_passenger`
--

DROP TABLE IF EXISTS `payment_tokens_passenger`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `payment_tokens_passenger` (
  `id` int NOT NULL AUTO_INCREMENT,
  `token` varchar(255) NOT NULL,
  `passengerId` varchar(255) NOT NULL,
  `dateCreated` datetime NOT NULL,
  `amount` decimal(10,2) NOT NULL,
  `isUsed` tinyint(1) DEFAULT '0',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `payments`
--

DROP TABLE IF EXISTS `payments`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `payments` (
  `id` varchar(111) NOT NULL,
  `amount` decimal(10,2) NOT NULL,
  `payment_method` varchar(255) NOT NULL,
  `passengerID` varchar(100) NOT NULL,
  `rideId` varchar(100) NOT NULL,
  `driverID` varchar(100) NOT NULL,
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `isGiven` varchar(20) NOT NULL DEFAULT 'waiting',
  PRIMARY KEY (`id`),
  UNIQUE KEY `rideId` (`rideId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `paymentsDriverPoints`
--

DROP TABLE IF EXISTS `paymentsDriverPoints`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `paymentsDriverPoints` (
  `id` int NOT NULL AUTO_INCREMENT,
  `amount` decimal(10,2) NOT NULL,
  `payment_method` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `driverID` varchar(60) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `created_at` datetime DEFAULT CURRENT_TIMESTAMP,
  `updated_at` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `phone_verification`
--

DROP TABLE IF EXISTS `phone_verification`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `phone_verification` (
  `id` int NOT NULL AUTO_INCREMENT,
  `phone_number` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
  `driverId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT 'yet',
  `email` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT 'yet',
  `token_code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
  `expiration_time` datetime NOT NULL,
  `is_verified` tinyint(1) DEFAULT '0',
  `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=111 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `phone_verification_passenger`
--

DROP TABLE IF EXISTS `phone_verification_passenger`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `phone_verification_passenger` (
  `id` int NOT NULL AUTO_INCREMENT,
  `phone_number` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,
  `token` varchar(80) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
  `expiration_time` datetime NOT NULL,
  `verified` tinyint(1) DEFAULT '0',
  `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  `status` varchar(22) NOT NULL DEFAULT 'yet',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=109 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `places`
--

DROP TABLE IF EXISTS `places`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `places` (
  `id` int NOT NULL AUTO_INCREMENT,
  `latitude` double NOT NULL,
  `longitude` double NOT NULL,
  `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `name_ar` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `name_en` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `address` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `category` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=58830 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `placesEgypt`
--

DROP TABLE IF EXISTS `placesEgypt`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `placesEgypt` (
  `id` int NOT NULL,
  `nameEnglish` varchar(255) DEFAULT NULL,
  `nameArabic` varchar(255) DEFAULT NULL,
  `phone` varchar(20) DEFAULT NULL,
  `countReview` int DEFAULT NULL,
  `rate` float DEFAULT NULL,
  `stars` varchar(50) DEFAULT NULL,
  `address` text,
  `website` varchar(255) DEFAULT NULL,
  `email` varchar(255) DEFAULT NULL,
  `PlusCode` varchar(50) DEFAULT NULL,
  `closeTime` varchar(50) DEFAULT NULL,
  `latitude` decimal(10,6) DEFAULT NULL,
  `longitude` decimal(10,6) DEFAULT NULL,
  `instagram` varchar(255) DEFAULT NULL,
  `facebook` varchar(255) DEFAULT NULL,
  `linkedin` varchar(255) DEFAULT NULL,
  `twitter` varchar(255) DEFAULT NULL,
  `photo` varchar(255) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `promos`
--

DROP TABLE IF EXISTS `promos`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `promos` (
  `id` int NOT NULL AUTO_INCREMENT,
  `promo_code` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `amount` varchar(4) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '0',
  `description` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL,
  `passengerID` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'none',
  `validity_start_date` date DEFAULT NULL,
  `validity_end_date` date DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `passengerID` (`passengerID`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `promptDriverIDEgypt`
--

DROP TABLE IF EXISTS `promptDriverIDEgypt`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `promptDriverIDEgypt` (
  `id` int NOT NULL AUTO_INCREMENT,
  `type` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `prompt` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `createdAt` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  `updatedAt` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `ratingApp`
--

DROP TABLE IF EXISTS `ratingApp`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `ratingApp` (
  `id` int NOT NULL AUTO_INCREMENT,
  `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `email` varchar(150) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `phone` varchar(80) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `userId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `userType` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `rating` varchar(2) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `comment` varchar(300) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `ratingDriver`
--

DROP TABLE IF EXISTS `ratingDriver`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `ratingDriver` (
  `id` int NOT NULL AUTO_INCREMENT,
  `passenger_id` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci,
  `driver_id` varchar(33) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `ride_id` int DEFAULT NULL,
  `rating` float DEFAULT NULL,
  `comment` text CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci,
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `ride_id` (`ride_id`),
  KEY `idx_driver_id` (`driver_id`)
) ENGINE=InnoDB AUTO_INCREMENT=17 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `ratingPassenger`
--

DROP TABLE IF EXISTS `ratingPassenger`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `ratingPassenger` (
  `id` int NOT NULL AUTO_INCREMENT,
  `passenger_id` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `driverID` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `rideId` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `rating` float NOT NULL,
  `comment` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci,
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `rideId` (`rideId`)
) ENGINE=InnoDB AUTO_INCREMENT=17 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `ride`
--

DROP TABLE IF EXISTS `ride`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `ride` (
  `id` int NOT NULL AUTO_INCREMENT,
  `start_location` varchar(255) NOT NULL,
  `end_location` varchar(255) NOT NULL,
  `date` date NOT NULL,
  `time` time NOT NULL,
  `endtime` time NOT NULL,
  `price` decimal(10,2) NOT NULL DEFAULT '0.00',
  `passenger_id` varchar(111) NOT NULL,
  `driver_id` varchar(111) NOT NULL,
  `status` varchar(200) NOT NULL DEFAULT 'nothing',
  `paymentMethod` varchar(20) NOT NULL DEFAULT 'Cash',
  `carType` varchar(20) NOT NULL DEFAULT 'Speed',
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `DriverIsGoingToPassenger` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `rideTimeStart` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `rideTimeFinish` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `price_for_driver` decimal(10,2) NOT NULL DEFAULT '0.00',
  `price_for_passenger` decimal(10,2) NOT NULL DEFAULT '0.00',
  `distance` float DEFAULT '0',
  PRIMARY KEY (`id`),
  KEY `passengerfk` (`passenger_id`),
  KEY `driverfk` (`driver_id`)
) ENGINE=InnoDB AUTO_INCREMENT=831 DEFAULT CHARSET=utf8mb3;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `seferWallet`
--

DROP TABLE IF EXISTS `seferWallet`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `seferWallet` (
  `id` int NOT NULL AUTO_INCREMENT,
  `driverId` varchar(100) NOT NULL,
  `passengerId` varchar(100) NOT NULL,
  `amount` varchar(10) NOT NULL,
  `paymentMethod` varchar(50) NOT NULL,
  `token` varchar(100) NOT NULL,
  `createdAt` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `server_locations`
--

DROP TABLE IF EXISTS `server_locations`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `server_locations` (
  `id` int NOT NULL AUTO_INCREMENT,
  `name` varchar(255) NOT NULL,
  `min_latitude` decimal(10,6) NOT NULL,
  `max_latitude` decimal(10,6) NOT NULL,
  `min_longitude` decimal(10,6) NOT NULL,
  `max_longitude` decimal(10,6) NOT NULL,
  `server_link` varchar(255) NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `name` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `smsSender`
--

DROP TABLE IF EXISTS `smsSender`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `smsSender` (
  `id` int NOT NULL AUTO_INCREMENT,
  `senderId` varchar(20) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `test`
--

DROP TABLE IF EXISTS `test`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `test` (
  `id` int NOT NULL AUTO_INCREMENT,
  `name` varchar(22) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `testApp`
--

DROP TABLE IF EXISTS `testApp`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `testApp` (
  `id` int NOT NULL AUTO_INCREMENT,
  `isTest` tinyint(1) NOT NULL,
  `createdAt` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `appPlatform` varchar(20) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `tips`
--

DROP TABLE IF EXISTS `tips`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `tips` (
  `id` int NOT NULL AUTO_INCREMENT,
  `driverID` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `passengerID` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `rideID` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `tipAmount` decimal(10,2) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `token_verification`
--

DROP TABLE IF EXISTS `token_verification`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `token_verification` (
  `id` int NOT NULL AUTO_INCREMENT,
  `phone_number` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `token` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `expiration_time` datetime NOT NULL,
  `verified` tinyint(1) DEFAULT '0',
  `created_at` datetime DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=49 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `token_verification_admin`
--

DROP TABLE IF EXISTS `token_verification_admin`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `token_verification_admin` (
  `id` int NOT NULL AUTO_INCREMENT,
  `phone_number` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `token` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `expiration_time` datetime NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `phone_number` (`phone_number`)
) ENGINE=InnoDB AUTO_INCREMENT=29 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `token_verification_driver`
--

DROP TABLE IF EXISTS `token_verification_driver`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `token_verification_driver` (
  `id` int NOT NULL AUTO_INCREMENT,
  `phone_number` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `token` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `expiration_time` datetime NOT NULL,
  `verified` tinyint(1) NOT NULL DEFAULT '0',
  `created_at` datetime DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=49 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `tokens`
--

DROP TABLE IF EXISTS `tokens`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `tokens` (
  `id` int NOT NULL AUTO_INCREMENT,
  `token` varchar(333) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `passengerID` varchar(80) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `fingerPrint` varchar(250) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `status` varchar(22) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'yet',
  PRIMARY KEY (`id`),
  UNIQUE KEY `passengerID` (`passengerID`)
) ENGINE=InnoDB AUTO_INCREMENT=53 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `users`
--

DROP TABLE IF EXISTS `users`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `users` (
  `id` varchar(111) NOT NULL,
  `phone` varchar(15) NOT NULL,
  `email` varchar(255) NOT NULL,
  `gender` varchar(10) NOT NULL,
  `password` varchar(100) NOT NULL,
  `birthdate` date NOT NULL,
  `site` varchar(255) NOT NULL,
  `first_name` varchar(255) NOT NULL,
  `last_name` varchar(255) NOT NULL,
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `user_type` varchar(44) NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `email` (`email`),
  UNIQUE KEY `phone` (`phone`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `vehicles`
--

DROP TABLE IF EXISTS `vehicles`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `vehicles` (
  `id` int NOT NULL AUTO_INCREMENT,
  `driverID` varchar(100) NOT NULL,
  `make` varchar(255) NOT NULL,
  `model` varchar(255) NOT NULL,
  `license_plate` varchar(255) NOT NULL,
  `seats` int NOT NULL,
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `license_plate` (`license_plate`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `videos`
--

DROP TABLE IF EXISTS `videos`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `videos` (
  `id` int NOT NULL AUTO_INCREMENT,
  `title` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `description` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `url` varchar(150) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `waitingRides`
--

DROP TABLE IF EXISTS `waitingRides`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `waitingRides` (
  `id` varchar(100) NOT NULL,
  `start_location` varchar(255) NOT NULL,
  `end_location` varchar(255) NOT NULL,
  `date` date NOT NULL,
  `time` time NOT NULL,
  `price` decimal(10,2) NOT NULL DEFAULT '0.00',
  `passenger_id` varchar(111) NOT NULL,
  `status` varchar(200) NOT NULL DEFAULT 'nothing',
  `carType` varchar(19) NOT NULL,
  `passengerRate` decimal(10,2) NOT NULL,
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `price_for_passenger` decimal(10,2) NOT NULL DEFAULT '0.00',
  `distance` varchar(255) NOT NULL,
  `duration` varchar(10) NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `welcomeDriverCall`
--

DROP TABLE IF EXISTS `welcomeDriverCall`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `welcomeDriverCall` (
  `id` int NOT NULL AUTO_INCREMENT,
  `driverId` varchar(50) NOT NULL,
  `isCall` tinyint(1) NOT NULL DEFAULT '0',
  `notes` varchar(255) NOT NULL,
  `createdAt` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `write_argument_after_applied_from_background`
--

DROP TABLE IF EXISTS `write_argument_after_applied_from_background`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `write_argument_after_applied_from_background` (
  `id` int unsigned NOT NULL AUTO_INCREMENT,
  `ride_id` varchar(50) NOT NULL,
  `driver_id` varchar(50) NOT NULL,
  `passenger_id` varchar(50) NOT NULL,
  `passenger_location` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
  `passenger_destination` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
  `duration` varchar(255) NOT NULL,
  `duration_to_passenger` varchar(255) NOT NULL,
  `duration_of_ride` varchar(255) NOT NULL,
  `distance` varchar(255) NOT NULL,
  `total_cost` varchar(255) NOT NULL,
  `payment_amount` varchar(255) NOT NULL,
  `payment_method` enum('visa','cash') NOT NULL,
  `wallet_checked` varchar(255) NOT NULL,
  `has_steps` varchar(255) NOT NULL,
  `step0` varchar(255) DEFAULT NULL,
  `step1` varchar(255) DEFAULT NULL,
  `step2` varchar(255) DEFAULT NULL,
  `step3` varchar(255) DEFAULT NULL,
  `step4` varchar(255) DEFAULT NULL,
  `passenger_wallet_burc` varchar(33) NOT NULL,
  `token_passenger` varchar(255) NOT NULL,
  `name` varchar(100) NOT NULL,
  `phone` varchar(20) NOT NULL,
  `email` varchar(150) NOT NULL,
  `start_name_location` varchar(255) NOT NULL,
  `end_name_location` varchar(255) NOT NULL,
  `car_type` varchar(50) NOT NULL,
  `kazan` varchar(255) NOT NULL,
  `direction_url` text NOT NULL,
  `time_of_order` datetime NOT NULL,
  `total_passenger` varchar(255) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Dumping events for database 'intaleq-ridesDB'
--

--
-- Dumping routines for database 'intaleq-ridesDB'
--
/*!50112 SET @disable_bulk_load = IF (@is_rocksdb_supported, 'SET SESSION rocksdb_bulk_load = @old_rocksdb_bulk_load', 'SET @dummy_rocksdb_bulk_load = 0') */;
/*!50112 PREPARE s FROM @disable_bulk_load */;
/*!50112 EXECUTE s */;
/*!50112 DEALLOCATE PREPARE s */;
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;

/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;

-- Dump completed on 2026-04-22 20:58:51

File: encrypt_decrypt.php

<?php
//encrypt_decrypt.php
require_once realpath(__DIR__ . '/../vendor/autoload.php');

require_once 'load_env.php';
$env_file = '/home/siro-api/env/.env';
loadEnvironment($env_file);


$key = trim(file_get_contents('/home/siro-api/.enckey')); 
$iv = getenv('initializationVector'); // 16 bytes


class EncryptionHelper {
    private $key;
    private $iv;

    public function __construct($key, $iv) {
        if (strlen($key) !== 32) {
            throw new Exception("❌ المفتاح (Key) لازم يكون 32 بايت.");
        }
        if (strlen($iv) !== 16) {
            throw new Exception("❌ الـ IV لازم يكون 16 بايت.");
        }

        $this->key = $key;
        $this->iv = $iv;
    }

    // --------- النصوص ----------
    private function addPadding($data, $blockSize = 16) {
        $pad = $blockSize - (strlen($data) % $blockSize);
        return $data . str_repeat(chr($pad), $pad);
    }

    private function removePadding($data) {
        $pad = ord($data[strlen($data) - 1]);
        return substr($data, 0, -$pad);
    }

    public function encryptData($plainText) {
        $plainText = mb_convert_encoding($plainText, 'UTF-8');
        $paddedText = $this->addPadding($plainText);
        $encrypted = openssl_encrypt($paddedText, 'AES-256-CBC', $this->key, OPENSSL_RAW_DATA, $this->iv);
        return base64_encode($encrypted);
    }

    public function decryptData($encryptedText) {
    $decoded = base64_decode($encryptedText, true);

    if ($decoded === false) {
        error_log("[ERROR] base64_decode failed for input: $encryptedText");
        return false;
    }

    $decrypted = openssl_decrypt($decoded, 'AES-256-CBC', $this->key, OPENSSL_RAW_DATA, $this->iv);

    if ($decrypted === false) {
        error_log("[ERROR] openssl_decrypt failed for input: $encryptedText");
        return false;
    }

    // Verify padding is valid before removal
    $pad = ord($decrypted[strlen($decrypted) - 1]);
    if ($pad < 1 || $pad > 16) {
        error_log("[ERROR] Invalid padding value ($pad) for decrypted input: $encryptedText");
        return false;
    }

    return substr($decrypted, 0, -$pad);
}

    public function decryptFile($encryptedFilePath, $destinationPath) {
        if (!file_exists($encryptedFilePath)) {
            throw new Exception("❌ الملف المشفر غير موجود: $encryptedFilePath");
        }

        $encryptedData = file_get_contents($encryptedFilePath);
        $decryptedData = openssl_decrypt($encryptedData, 'AES-256-CBC', $this->key, OPENSSL_RAW_DATA, $this->iv);

        file_put_contents($destinationPath, $decryptedData);
        return true;
    }
  public function encryptBinary($data) {
    $encrypted = openssl_encrypt($data, 'AES-256-CBC', $this->key, OPENSSL_RAW_DATA, $this->iv);
    return $encrypted;
	}

	public function decryptBinary($data) {
    $decrypted = openssl_decrypt($data, 'AES-256-CBC', $this->key, OPENSSL_RAW_DATA, $this->iv);
    return $decrypted;
	}
}
// ✅ Load the key and IV from .env or use default values

// ✅ Ensure the lengths are correct
 //echo "Key Length: " . $key . PHP_EOL;
 //echo "IV Length: " . $iv . PHP_EOL;

try {
    $encryptionHelper = new EncryptionHelper($key, $iv);

   
} catch (Exception $e) {
    echo "Error: " . $e->getMessage() . PHP_EOL;
}

?>

File: core/bootstrap.php

<?php
// ============================================================
// core/bootstrap.php
// البوابة الرئيسية الموحدة لكل التطبيق
// ============================================================

declare(strict_types=1);

// 1. إعدادات الأخطاء والـ Headers الأساسية
error_reporting(E_ALL);
ini_set('display_errors', '0'); // لا تعرض الأخطاء في Production (ترسل لـ log)
ini_set('log_errors', '1');
ini_set('error_log', '/home/siro-api/logs/php_errors.log');

header('Content-Type: application/json; charset=UTF-8');
header('X-Content-Type-Options: nosniff');
header('X-Frame-Options: DENY');
header('Strict-Transport-Security: max-age=31536000; includeSubDomains');

// CORS (يجب تخصيصه في endpoints مخصصة إن لزم، لكن هذا افتراضي)
header('Access-Control-Allow-Methods: POST, GET, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type, Authorization, X-Device-FP, X-HMAC-Auth, X-Internal-Key');

if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
    http_response_code(200);
    exit;
}

// 2. Autoload
$vendorPath = realpath(__DIR__ . '/../../vendor/autoload.php');
if ($vendorPath) require_once $vendorPath;

// 3. Helpers & Env
require_once __DIR__ . '/helpers.php';
$envFile = '/home/siro-api/env/.env';
loadEnvironment($envFile);

// 4. Redis Connection (Singleton)
$redis = null;
try {
    if (extension_loaded('redis')) {
        $redis = new Redis();
        $redisHost = getenv('REDIS_HOST') ?: '127.0.0.1';
        $redisPort = (int)(getenv('REDIS_PORT') ?: 6379);
        $redisPass = getenv('REDIS_PASSWORD');

        if ($redis->connect($redisHost, $redisPort, 1.5)) {
            if ($redisPass) $redis->auth($redisPass);
            $redis->setOption(Redis::OPT_PREFIX, 'siro:');
        } else {
            $redis = null;
        }
    }
} catch (Exception $e) {
    error_log("[REDIS] Connection failed: " . $e->getMessage());
    $redis = null;
}

// 5. تحميل الـ Services الأساسية
require_once __DIR__ . '/Security/EncryptionHelper.php';
require_once __DIR__ . '/Database/Database.php';
require_once __DIR__ . '/Auth/RateLimiter.php';
require_once __DIR__ . '/Auth/JwtService.php';
// لا نحمّل OtpService و FcmService إلا عند الحاجة (Lazy)

// 6. تهيئة Encryption Helper العام (للتوافقية)
$secretKey = trim(@file_get_contents('/home/siro-api/.secret_key')) ?: getenv('SECRET_KEY');
if (!$secretKey) {
    error_log("[FATAL] Secret key is missing.");
    http_response_code(500);
    exit(json_encode(['error' => 'Server configuration error']));
}

$encryptionHelper = new EncryptionHelper($secretKey);

File: core/helpers.php

<?php
// ============================================================
// core/helpers.php — دوال مساعدة موحدة
// ============================================================

// ── فلترة المدخلات (محسّنة) ─────────────────────────────────
function filterRequest(string $name, string $type = 'string'): mixed
{
    // قراءة من POST أو JSON body
    $value = null;

    if (isset($_POST[$name]) && $_POST[$name] !== '') {
        $value = $_POST[$name];
    } else {
        // محاولة قراءة من JSON body
        static $jsonBody = null;
        if ($jsonBody === null) {
            $raw       = file_get_contents('php://input');
            $jsonBody  = json_decode($raw, true) ?? [];
        }
        $value = $jsonBody[$name] ?? null;
    }

    if ($value === null || $value === '') return null;

    $value = trim((string)$value);

    // إزالة control characters
    $value = preg_replace('/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/', '', $value);

    return match ($type) {
        'int'    => filter_var($value, FILTER_VALIDATE_INT)     !== false ? (int)$value    : null,
        'float'  => filter_var($value, FILTER_VALIDATE_FLOAT)   !== false ? (float)$value  : null,
        'email'  => filter_var($value, FILTER_VALIDATE_EMAIL)   ?: null,
        'url'    => filter_var($value, FILTER_VALIDATE_URL)      ?: null,
        'bool'   => filter_var($value, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE),
        default  => $value, // string — بدون htmlspecialchars (نتركه لـ PDO)
    };
}

// ── ردود JSON موحدة ─────────────────────────────────────────
function jsonSuccess(mixed $data = null, string $message = 'success', int $code = 200): never
{
    http_response_code($code);
    $response = ['status' => 'success'];
    if ($message !== 'success')       $response['message'] = $message;
    if ($data !== null)               $response['data']    = $data;
    echo json_encode($response, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
    exit;
}

function jsonError(string $message, int $code = 400, mixed $extra = null): never
{
    http_response_code($code);
    $response = ['status' => 'error', 'message' => $message];
    if ($extra !== null) $response['details'] = $extra;
    echo json_encode($response, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
    exit;
}

// (للتوافق مع الكود القديم)
function printSuccess(string $message = 'success'): void
{
    echo json_encode(['status' => 'success', 'message' => $message], JSON_UNESCAPED_UNICODE);
}
function printFailure(string $message = 'failure'): void
{
    echo json_encode(['status' => 'failure', 'message' => $message], JSON_UNESCAPED_UNICODE);
}
function result(int $count): void
{
    if ($count > 0) {
        printSuccess();
    } else {
        printFailure();
    }
}
function sendEmail(string $from, string $to, string $title, string $body): void
{
    $header = "From: $from\nCC: $from";
    mail($to, $title, $body, $header);
}

// ── رفع صورة آمن ──────────────────────────────────────────────
function uploadImageSecure(
    string $fileKey,
    string $targetDir,
    string $prefix = '',
    array $allowedMimes = ['image/jpeg', 'image/png', 'image/webp']
): array {
    if (!isset($_FILES[$fileKey]) || $_FILES[$fileKey]['error'] !== UPLOAD_ERR_OK) {
        return ['success' => false, 'error' => 'File upload error'];
    }

    $file    = $_FILES[$fileKey];
    $maxSize = 5 * 1024 * 1024; // 5MB

    // حجم الملف
    if ($file['size'] > $maxSize) {
        return ['success' => false, 'error' => 'File too large (max 5MB)'];
    }

    // MIME validation حقيقي (ليس extension فقط)
    $finfo    = new finfo(FILEINFO_MIME_TYPE);
    $mimeType = $finfo->file($file['tmp_name']);

    if (!in_array($mimeType, $allowedMimes, true)) {
        return ['success' => false, 'error' => "Invalid file type: $mimeType"];
    }

    // اسم ملف آمن وعشوائي
    $ext      = match ($mimeType) {
        'image/jpeg' => 'jpg',
        'image/png'  => 'png',
        'image/webp' => 'webp',
        default      => 'bin',
    };
    $filename = ($prefix ? "{$prefix}_" : '') . bin2hex(random_bytes(8)) . ".$ext";

    if (!is_dir($targetDir)) {
        mkdir($targetDir, 0750, true);
    }

    $targetPath = rtrim($targetDir, '/') . '/' . $filename;

    if (!move_uploaded_file($file['tmp_name'], $targetPath)) {
        return ['success' => false, 'error' => 'Failed to move uploaded file'];
    }

    return ['success' => true, 'filename' => $filename, 'path' => $targetPath];
}

// ── تحميل ملف .env ───────────────────────────────────────────
function loadEnvironment(string $path): void
{
    if (!file_exists($path)) {
        error_log("[ENV] File not found: $path");
        return;
    }
    $lines = file($path, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
    foreach ($lines as $line) {
        if (str_starts_with(trim($line), '#')) continue;
        if (!str_contains($line, '=')) continue;
        [$key, $value] = explode('=', $line, 2);
        $key   = trim($key);
        $value = trim($value, " \t\n\r\0\x0B\"'");
        if ($key && !getenv($key)) {
            putenv("$key=$value");
            $_ENV[$key] = $value;
        }
    }
}

// ── Logging منظم ──────────────────────────────────────────────
function securityLog(string $message, array $context = []): void
{
    $entry = date('Y-m-d H:i:s') . ' [SECURITY] ' . $message;
    if ($context) $entry .= ' | ' . json_encode($context, JSON_UNESCAPED_UNICODE);
    error_log($entry, 3, '/home/siro-api/logs/security.log');
}

function appLog(string $message, string $level = 'INFO'): void
{
    $entry = date('Y-m-d H:i:s') . " [$level] " . $message;
    error_log($entry, 3, '/home/siro-api/logs/app.log');
}

function debugLog(string $message): void
{
    appLog($message, 'DEBUG');
}

File: core/Database/Database.php

<?php
// ============================================================
// core/Database/Database.php — Lazy PDO Singleton
// لا يفتح اتصال إلا عند الطلب الفعلي لقاعدة البيانات
// ============================================================

class Database
{
    private static array $instances = [];

    // خريطة الـ databases المتاحة
    private static array $map = [
        'main'     => 'dbname',       // متغير ENV لاسم DB الرئيسي
        'tracking' => 'dbname_track', // متغير ENV لقاعدة التتبع
        'ride'     => 'dbname_ride',  // متغير ENV لقاعدة الرحلات
    ];

    public static function get(string $name = 'main'): PDO
    {
        if (!isset(self::$instances[$name])) {
            self::$instances[$name] = self::connect($name);
        }
        return self::$instances[$name];
    }

    private static function connect(string $name): PDO
    {
        if (!isset(self::$map[$name])) {
            throw new InvalidArgumentException("Unknown database: $name");
        }

        $dbEnvKey = self::$map[$name];
        $dbname   = getenv($dbEnvKey);
        $user     = getenv('USER');
        $pass     = getenv('PASS');
        $host     = getenv('DB_HOST') ?: 'localhost';

        if (!$dbname || !$user) {
            throw new RuntimeException("Database config missing for: $name");
        }

        $dsn = "mysql:host=$host;dbname=$dbname;charset=utf8mb4";
        $options = [
            PDO::ATTR_EMULATE_PREPARES   => false,
            PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION,
            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
            PDO::ATTR_PERSISTENT         => true, // connection reuse
            PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci",
            PDO::ATTR_TIMEOUT            => 10,
        ];

        try {
            return new PDO($dsn, $user, $pass, $options);
        } catch (PDOException $e) {
            error_log("[DB] Connection failed ($name): " . $e->getMessage());
            throw $e;
        }
    }

    // منع الاستنساخ
    private function __construct() {}
    private function __clone() {}
}

File: core/Security/EncryptionHelper.php

<?php
// ============================================================
// core/Security/EncryptionHelper.php
// يدعم AES-256-GCM الجديد + AES-256-CBC القديم (توافقية)
// ============================================================

class EncryptionHelper
{
    private string $key;
    private string $cbcIv;
    private const ALGO_GCM = 'aes-256-gcm';
    private const ALGO_CBC = 'AES-256-CBC'; // للتوافقية
    private const IV_LEN_GCM  = 12;
    private const TAG_LEN = 16;
    private const PREFIX_GCM = 'GCM:'; // للتمييز بين الجديد والقديم

    public function __construct(string $key, ?string $cbcIv = null)
    {
        if (strlen($key) !== 32) {
            throw new InvalidArgumentException('Encryption key must be exactly 32 bytes.');
        }
        $this->key = $key;
        // IV القديم للتوافقية أثناء مرحلة المايغريشن
        $this->cbcIv = $cbcIv ?: getenv('initializationVector') ?: str_repeat('0', 16);
    }

    // ─── تشفير نص (CBC مؤقتاً للتوافق التام كما طلب المستخدم) ──
    // سيتم تغييره لاحقاً لـ GCM بعد تفريغ قاعدة البيانات القديمة
    public function encryptData(string $plainText): string
    {
        // بناءً على طلب المستخدم: إبقاء التشفير الحالي CBC حتى نقوم بالترحيل لاحقاً
        $plainText = mb_convert_encoding($plainText, 'UTF-8');
        $paddedText = $this->addPadding($plainText);
        $encrypted = openssl_encrypt($paddedText, self::ALGO_CBC, $this->key, OPENSSL_RAW_DATA, $this->cbcIv);
        return base64_encode($encrypted);
    }

    // ─── فك تشفير نص (يدعم CBC والـ GCM المستقبلي) ───────────
    public function decryptData(string $cipherText): string|false
    {
        // تحقق إن كان مشفر بالنظام الجديد
        if (str_starts_with($cipherText, self::PREFIX_GCM)) {
            $raw = base64_decode(substr($cipherText, strlen(self::PREFIX_GCM)), true);
            if ($raw === false || strlen($raw) < self::IV_LEN_GCM + self::TAG_LEN) return false;

            $iv     = substr($raw, 0, self::IV_LEN_GCM);
            $tag    = substr($raw, self::IV_LEN_GCM, self::TAG_LEN);
            $cipher = substr($raw, self::IV_LEN_GCM + self::TAG_LEN);

            $plain = openssl_decrypt($cipher, self::ALGO_GCM, $this->key, OPENSSL_RAW_DATA, $iv, $tag);
            return $plain !== false ? $plain : false;
        }

        // وإلا استخدم CBC القديم
        $decoded = base64_decode($cipherText, true);
        if ($decoded === false) return false;

        $decrypted = openssl_decrypt($decoded, self::ALGO_CBC, $this->key, OPENSSL_RAW_DATA, $this->cbcIv);
        if ($decrypted === false) return false;

        $pad = ord($decrypted[strlen($decrypted) - 1]);
        if ($pad < 1 || $pad > 16) return false;

        return substr($decrypted, 0, -$pad);
    }

    // ─── تشفير/فك تشفير Binary (صور، ملفات) ───────────────
    public function encryptBinary(string $data): string
    {
        return openssl_encrypt($data, self::ALGO_CBC, $this->key, OPENSSL_RAW_DATA, $this->cbcIv);
    }

    public function decryptBinary(string $data): string|false
    {
        return openssl_decrypt($data, self::ALGO_CBC, $this->key, OPENSSL_RAW_DATA, $this->cbcIv);
    }

    // --------- دوال الـ Padding للـ CBC ----------
    private function addPadding($data, $blockSize = 16) {
        $pad = $blockSize - (strlen($data) % $blockSize);
        return $data . str_repeat(chr($pad), $pad);
    }

    private function removePadding($data) {
        $pad = ord($data[strlen($data) - 1]);
        return substr($data, 0, -$pad);
    }
}

File: core/Auth/JwtService.php

<?php
// ============================================================
// core/Auth/JwtService.php
// JWT آمن: JTI + Blacklist في Redis + Refresh Token
// ============================================================

use Firebase\JWT\JWT;
use Firebase\JWT\Key;
use Firebase\JWT\ExpiredException;
use Firebase\JWT\SignatureInvalidException;
use Firebase\JWT\BeforeValidException;

class JwtService
{
    private string $secretKey;
    private string $hmacSecret;
    private string $fpPepper;
    private ?Redis $redis;

    private string $issuer;
    private const ACCESS_TTL    = 900;     // 15 دقيقة
    private const REFRESH_TTL   = 2592000; // 30 يوم
    private const ALGO          = 'HS256';

    // Endpoints مسموح لها بتوكن نوع registration
    private const REGISTRATION_ENDPOINTS = [
        'loginFirstTime', 'loginFirstTimeDriver',
        'checkPhoneNumberISVerfiedDriver', 'checkPhoneNumberISVerfiedPassenger',
        'otpmessage', 'signup', 'verifyEmail', 'verifyOtpMessage',
        'sendVerifyEmail', 'sendWhatsAppDriver', 'register_passenger',
        'sendWhatsOpt', 'verifyOtp', 'auth_proxy', 'addToken',
        'loginFromGoogle', 'loginUsingCredentialsWithoutGoogle',
        'register', 'sendOtpMessageDriver', 'getTokensPassenger',
        'send_otp', 'verify_otp',
    ];

    public function __construct(?Redis $redis = null)
    {
        $this->secretKey  = trim(file_get_contents('/home/siro-api/.secret_key'));
        $this->hmacSecret = getenv('SECRET_KEY_HMAC') ?: '';
        $this->fpPepper   = getenv('FP_PEPPER') ?: '';
        $this->issuer     = getenv('APP_ISSUER') ;
        $this->redis      = $redis;
    }

    // ── توليد Access Token ──────────────────────────────────
    public function generateAccessToken(
        int|string $userId,
        string $role,
        string $audience,
        ?string $fingerprint = null
    ): string {
        $jti = bin2hex(random_bytes(16));

        $payload = [
            'iss'        => $this->issuer,
            'aud'        => $audience,
            'user_id'    => $userId,
            'role'       => $role,
            'token_type' => 'access',
            'jti'        => $jti,
            'iat'        => time(),
            'exp'        => time() + self::ACCESS_TTL,
        ];

        if ($fingerprint && $this->fpPepper) {
            $payload['fingerPrint'] = hash('sha256', $fingerprint . $this->fpPepper);
        }

        return JWT::encode($payload, $this->secretKey, self::ALGO);
    }

    // ── توليد Refresh Token ─────────────────────────────────
    public function generateRefreshToken(int|string $userId): array
    {
        $token = bin2hex(random_bytes(32));
        $exp   = time() + self::REFRESH_TTL;

        // تخزين في Redis
        if ($this->redis) {
            $this->redis->setex(
                "refresh:{$userId}:{$token}",
                self::REFRESH_TTL,
                json_encode(['user_id' => $userId, 'created_at' => time()])
            );
        }

        return ['token' => $token, 'expires_at' => $exp];
    }

    // ── التحقق الكامل من التوكن ────────────────────────────
    public function authenticate(): object
    {
        // 1. استخراج التوكن
        $authHeader = $_SERVER['HTTP_AUTHORIZATION'] ?? '';
        $token      = null;
        if (preg_match('/Bearer\s(\S+)/', $authHeader, $m)) {
            $token = $m[1];
        }

        if (!$token) {
            self::abort(401, 'Authorization token required');
        }

        // 2. Decode
        try {
            $decoded = JWT::decode($token, new Key($this->secretKey, self::ALGO));
        } catch (ExpiredException $e) {
            self::abort(401, 'Token expired');
        } catch (SignatureInvalidException $e) {
            self::abort(401, 'Invalid token signature');
        } catch (BeforeValidException $e) {
            self::abort(401, 'Token not yet valid');
        } catch (Exception $e) {
            self::abort(401, 'Invalid token');
        }

        // 3. Issuer
        if (($decoded->iss ?? '') !== $this->issuer) {
            self::abort(401, 'Invalid token issuer');
        }

        // 4. User ID
        $userId = $decoded->user_id ?? $decoded->sub ?? null;
        if (!$userId) {
            self::abort(401, 'Invalid JWT payload');
        }

        // 5. JTI Blacklist (تحقق من توكنات ملغاة)
        $jti = $decoded->jti ?? null;
        if ($jti && $this->redis) {
            if ($this->redis->exists("jwt:blacklist:$jti")) {
                self::abort(401, 'Token has been revoked');
            }
        }

        // 6. token_type — قيّد registration endpoints
        $tokenType = $decoded->token_type ?? 'access';
        if ($tokenType === 'registration' || $tokenType === 'new') {
            $currentFile = basename($_SERVER['PHP_SELF'], '.php');
            $allowed = false;
            foreach (self::REGISTRATION_ENDPOINTS as $ep) {
                if (strcasecmp($currentFile, $ep) === 0) {
                    $allowed = true;
                    break;
                }
            }
            if (!$allowed) {
                error_log("[SECURITY] Registration token blocked on: $currentFile | user: $userId");
                self::abort(403, 'Token not authorized for this action');
            }
        }

        // 7. Device Fingerprint (إلزامي للـ Access Tokens)
        if ($this->fpPepper && $tokenType === 'access') {
            $fpInToken = $decoded->fingerPrint ?? null;
            $fpHeader  = $_SERVER['HTTP_X_DEVICE_FP'] ?? null;

            if ($fpInToken === null || $fpHeader === null) {
                error_log("[SECURITY] Fingerprint missing | user: $userId");
                self::abort(403, 'Device verification required');
            }

            $expected = hash('sha256', $fpHeader . $this->fpPepper);
            if (!hash_equals($expected, $fpInToken)) {
                error_log("[SECURITY] Device mismatch | user: $userId | IP: " . ($_SERVER['REMOTE_ADDR'] ?? '?'));
                self::abort(403, 'Device mismatch');
            }
        }

        // 8. HMAC — مطلوب للعمليات الحساسة (Wallet/Logout)
        $hmacHeader = $_SERVER['HTTP_X_HMAC_AUTH'] ?? null;
        if ($hmacHeader !== null) {
            $timestamp = $_SERVER['HTTP_X_TIMESTAMP'] ?? '';
            $nonce     = $_SERVER['HTTP_X_NONCE'] ?? '';
            $body      = file_get_contents('php://input') ?: '';

            // التوقيع يضم الـ Body + Timestamp + Nonce لمنع التكرار والتلاعب
            $payloadToSign = $body . $timestamp . $nonce;
            $expectedHmac  = hash_hmac('sha256', $payloadToSign, $this->hmacSecret);

            if (!hash_equals($expectedHmac, $hmacHeader)) {
                error_log("[SECURITY] HMAC mismatch | user: $userId | IP: " . ($_SERVER['REMOTE_ADDR'] ?? '?'));
                self::abort(403, 'Invalid HMAC signature');
            }
        }

        return $decoded;
    }

    // ── إلغاء توكن (Logout / Password Change) ──────────────
    public function revokeToken(string $jti, int $remainingTTL = 900): void
    {
        if ($this->redis && $jti) {
            $this->redis->setex("jwt:blacklist:$jti", $remainingTTL + 60, '1');
        }
    }

    // ── Internal API Key — للـ get_connect.php ─────────────
    public static function validateInternalKey(): void
    {
        $keyPath = '/home/siro-api/.internal_socket_key';
        $sent    = $_SERVER['HTTP_X_INTERNAL_KEY'] ?? '';
        $expected = file_exists($keyPath) ? trim(file_get_contents($keyPath)) : '';

        if (!$expected || !hash_equals($expected, $sent)) {
            error_log('[SECURITY] Invalid internal key from: ' . ($_SERVER['REMOTE_ADDR'] ?? '?'));
            http_response_code(403);
            echo json_encode(['error' => 'Unauthorized internal request']);
            exit;
        }
    }

    private static function abort(int $code, string $message): never
    {
        http_response_code($code);
        echo json_encode(['error' => $message]);
        exit;
    }
}

File: core/Auth/RateLimiter.php

<?php
// ============================================================
// core/Auth/RateLimiter.php
// Sliding Window Rate Limiting باستخدام Redis
// ============================================================

class RateLimiter
{
    private ?Redis $redis;

    // حدود مختلفة لكل نوع endpoint
    private const LIMITS = [
        'login'      => ['requests' => 5,   'window' => 60],   // 5 محاولات / دقيقة
        'otp'        => ['requests' => 3,   'window' => 300],  // 3 محاولات / 5 دقائق
        'register'   => ['requests' => 3,   'window' => 3600], // 3 محاولات / ساعة
        'api'        => ['requests' => 120, 'window' => 60],   // 120 طلب / دقيقة
        'ride'       => ['requests' => 30,  'window' => 60],   // 30 طلب / دقيقة
        'upload'     => ['requests' => 10,  'window' => 300],  // 10 رفع / 5 دقائق
    ];

    public function __construct(?Redis $redis)
    {
        $this->redis = $redis;
    }

    // ── فحص الحد ─────────────────────────────────────────────
    // $identifier: IP:userId أو IP فقط
    // $type: login | otp | api | ride | upload
    public function check(string $identifier, string $type = 'api'): bool
    {
        if (!$this->redis) {
            return true; // بدون Redis نمرر (fallback)
        }

        $limit  = self::LIMITS[$type] ?? self::LIMITS['api'];
        $window = $limit['window'];
        $max    = $limit['requests'];

        $key     = "rate:{$type}:{$identifier}";
        $current = $this->redis->incr($key);

        if ($current === 1) {
            $this->redis->expire($key, $window);
        }

        return $current <= $max;
    }

    // ── تطبيق الحد وإيقاف الطلب إن تجاوز ─────────────────────
    public function enforce(string $identifier, string $type = 'api'): void
    {
        if (!$this->check($identifier, $type)) {
            $limit  = self::LIMITS[$type] ?? self::LIMITS['api'];
            $window = $limit['window'];

            error_log("[RATE_LIMIT] Blocked: $identifier | type: $type");

            http_response_code(429);
            header("Retry-After: $window");
            echo json_encode([
                'error'       => 'Too many requests. Please slow down.',
                'retry_after' => $window,
            ]);
            exit;
        }
    }

    // ── بناء معرّف المستخدم ────────────────────────────────────
    public static function identifier(?string $userId = null): string
    {
        $ip = $_SERVER['REMOTE_ADDR'] ?? 'unknown';
        return $userId ? "{$ip}:{$userId}" : $ip;
    }

    // ── إعادة تعيين عداد (مثلاً بعد تسجيل دخول ناجح) ───────────
    public function reset(string $identifier, string $type = 'login'): void
    {
        if ($this->redis) {
            $this->redis->del("rate:{$type}:{$identifier}");
        }
    }
}

File: core/Services/OtpService.php

<?php
// ============================================================
// core/Services/OtpService.php
// تخزين OTP في Redis بدلاً من MySQL (أسرع وأخف)
// ============================================================

class OtpService
{
    private ?Redis $redis;
    private const OTP_TTL     = 300;  // 5 دقائق
    private const MAX_ATTEMPTS = 3;
    private const LOCKOUT_TTL  = 1800; // 30 دقيقة إذا تجاوز المحاولات

    public function __construct(?Redis $redis)
    {
        $this->redis = $redis;
    }

    // ── توليد وحفظ OTP ─────────────────────────────────────
    public function generate(string $phone): string
    {
        // OTP آمن (6 أرقام عشوائية)
        $otp = str_pad((string)random_int(100000, 999999), 6, '0', STR_PAD_LEFT);

        if ($this->redis) {
            $key = "otp:{$phone}";
            $this->redis->setex($key, self::OTP_TTL, password_hash($otp, PASSWORD_BCRYPT));
            // إعادة تعيين عداد المحاولات
            $this->redis->del("otp:attempts:{$phone}");
        }

        return $otp;
    }

    // ── التحقق من OTP ───────────────────────────────────────
    public function verify(string $phone, string $inputOtp): bool
    {
        if (!$this->redis) return false;

        // فحص الـ lockout
        if ($this->redis->exists("otp:locked:{$phone}")) {
            return false;
        }

        $key   = "otp:{$phone}";
        $stored = $this->redis->get($key);

        if (!$stored) {
            return false; // انتهت صلاحية الـ OTP
        }

        $attemptsKey = "otp:attempts:{$phone}";

        if (!password_verify($inputOtp, $stored)) {
            $attempts = $this->redis->incr($attemptsKey);
            $this->redis->expire($attemptsKey, self::OTP_TTL);

            if ($attempts >= self::MAX_ATTEMPTS) {
                // قفل لمدة 30 دقيقة
                $this->redis->setex("otp:locked:{$phone}", self::LOCKOUT_TTL, '1');
                $this->redis->del($key);
            }
            return false;
        }

        // نجح التحقق — احذف الـ OTP
        $this->redis->del($key);
        $this->redis->del($attemptsKey);
        return true;
    }

    // ── فحص هل الرقم مقفل ──────────────────────────────────
    public function isLocked(string $phone): bool
    {
        return $this->redis && (bool)$this->redis->exists("otp:locked:{$phone}");
    }
}

File: core/Services/FcmService.php

<?php
// ============================================================
// core/Services/FcmService.php
// إرسال FCM مع كاش توكن في Redis (بدل ملف)
// ============================================================

class FcmService
{
    private ?Redis $redis;
    private string $serviceAccountFile;

    public function __construct(?Redis $redis = null)
    {
        $this->redis              = $redis;
        // المسار بناء على بنية المشروع
        $this->serviceAccountFile = __DIR__ . '/../../service-account.json';
    }

    // ── إرسال إشعار ────────────────────────────────────────
    public function send(
        string $token,
        string $title,
        string $body,
        array  $data     = [],
        string $category = 'Order',
        string $tone     = 'ding'
    ): array {
        $accessToken = $this->getAccessToken();
        if (!$accessToken) {
            return ['status' => 'error', 'message' => 'No access token'];
        }

        if (!file_exists($this->serviceAccountFile)) {
             return ['status' => 'error', 'message' => 'Service account file missing'];
        }

        $creds     = json_decode(file_get_contents($this->serviceAccountFile), true);
        $projectId = $creds['project_id'];
        $fcmUrl    = "https://fcm.googleapis.com/v1/projects/$projectId/messages:send";

        $finalData = array_merge($data, [
            'title'    => $title,
            'body'     => $body,
            'tone'     => $tone,
            'category' => $category,
            'type'     => $category,
        ]);

        // FCM يشترط أن تكون كل القيم strings
        $processedData = array_map(
            fn($v) => is_array($v) || is_object($v)
                ? json_encode($v, JSON_UNESCAPED_UNICODE)
                : (string)$v,
            $finalData
        );

        $payload = [
            'message' => [
                'token'   => $token,
                'data'    => $processedData,
                'android' => ['priority' => 'HIGH'],
                'apns'    => [
                    'headers' => ['apns-priority' => '10', 'apns-push-type' => 'background'],
                    'payload' => ['aps' => ['content-available' => 1]],
                ],
            ],
        ];

        $ch = curl_init($fcmUrl);
        curl_setopt_array($ch, [
            CURLOPT_POST          => true,
            CURLOPT_HTTPHEADER    => [
                "Authorization: Bearer $accessToken",
                'Content-Type: application/json; charset=UTF-8',
            ],
            CURLOPT_POSTFIELDS    => json_encode($payload, JSON_UNESCAPED_UNICODE),
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_TIMEOUT       => 8,
            CURLOPT_CONNECTTIMEOUT => 3,
            CURLOPT_FRESH_CONNECT  => false, // إعادة استخدام الاتصال
            CURLOPT_FORBID_REUSE   => false,
            CURLOPT_TCP_KEEPALIVE  => 1,
        ]);

        $result   = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $curlErr  = curl_errno($ch);
        curl_close($ch);

        if ($curlErr) {
            return ['status' => 'error', 'message' => 'CURL error'];
        }

        return $httpCode === 200
            ? ['status' => 'success']
            : ['status' => 'error', 'code' => $httpCode, 'response' => $result];
    }

    // ── Access Token مع Redis Cache ─────────────────────────
    private function getAccessToken(): ?string
    {
        // 1. من Redis
        if ($this->redis) {
            $cached = $this->redis->get('google_fcm_access_token');
            if ($cached) return $cached;
        }

        // 2. طلب جديد
        $token = $this->fetchGoogleToken();

        if ($token && $this->redis) {
            $this->redis->setex('google_fcm_access_token', 3500, $token);
        }

        return $token;
    }

    private function fetchGoogleToken(): ?string
    {
        if (!file_exists($this->serviceAccountFile)) return null;

        $creds       = json_decode(file_get_contents($this->serviceAccountFile), true);
        $clientEmail = $creds['client_email'];
        $privateKey  = $creds['private_key'];
        $now         = time();

        $header  = rtrim(strtr(base64_encode(json_encode(['alg' => 'RS256', 'typ' => 'JWT'])), '+/', '-_'), '=');
        $claim   = rtrim(strtr(base64_encode(json_encode([
            'iss'   => $clientEmail,
            'scope' => 'https://www.googleapis.com/auth/firebase.messaging',
            'aud'   => 'https://oauth2.googleapis.com/token',
            'exp'   => $now + 3600,
            'iat'   => $now,
        ])), '+/', '-_'), '=');

        $signature = '';
        openssl_sign("$header.$claim", $signature, $privateKey, 'SHA256');
        $jwt = "$header.$claim." . rtrim(strtr(base64_encode($signature), '+/', '-_'), '=');

        $ch = curl_init('https://oauth2.googleapis.com/token');
        curl_setopt_array($ch, [
            CURLOPT_POST           => true,
            CURLOPT_POSTFIELDS     => http_build_query([
                'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer',
                'assertion'  => $jwt,
            ]),
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_TIMEOUT        => 10,
        ]);

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

        return json_decode($res, true)['access_token'] ?? null;
    }
}

File: webhook_sms/webhook.php

<?php
header('Content-Type: application/json');

// !! تأكد أن هذا المفتاح يطابق المفتاح في تطبيق الأندرويد !!
//define('SECRET_KEY', 'YOUR_SUPER_SECRET_KEY_123__');
$secretKey = trim(file_get_contents('/home/siroapp/.secret_key'));

// --- 1. التحقق من صحة الطلب ---
$authHeader = $_SERVER['HTTP_AUTHORIZATION'] ?? '';
if ($authHeader !== 'Bearer ' . $secretKey) {
    http_response_code(403);
    echo json_encode(['status' => 'error', 'message' => 'Unauthorized Access']);
    exit();
}

// --- 2. قراءة البيانات المرسلة ---
$json_data = file_get_contents('php://input');
$data = json_decode($json_data, true);

if ($data === null || !isset($data['sender']) || !isset($data['message'])) {
    http_response_code(400);
    echo json_encode(['status' => 'error', 'message' => 'Invalid data received']);
    exit();
}

// --- 3. استخراج البيانات والتحضير للمعالجة ---
$sender = $data['sender'];
$message_body = $data['message'];
$received_at = date('Y-m-d H:i:s');
$log_entry = "[$received_at] From: $sender | Message: $message_body";

// --- 4. تحليل الرسالة (يركز على Orange Money فقط حالياً) ---

// تعريف المتغيرات التي سنستخرجها
$amount = 0;
$payer_phone = null;
$currency = null;

// النمط الوحيد الفعّال حالياً: لرسائل Orange Money الأردنية
$pattern_orangemoney_jo = '/تم استقبال حوالة مالية من (\d+)\s+من مزود الخدمة:\s+Orange Money إلى محفظتك بمبلغ ([\d,.]+)\s+دينار/';

/*
// أنماط أخرى يمكن تفعيلها لاحقاً
// $pattern_chambank = '/حوالة واردة خارجية بمبلغ\s+([\d,.]+)\s+ليرة سورية/';
// $pattern_wallet_syr = '/تم استلام مبلغ ([\d,.]+) ل\.س من الرقم (09\d{8})/';
*/

if (preg_match($pattern_orangemoney_jo, $message_body, $matches)) {
    // --- تطابق نمط Orange Money الأردني ---
    $payer_phone = $matches[1];
    $amount_str = $matches[2];
    $amount = (float) str_replace(',', '', $amount_str);
    $currency = 'JOD'; // دينار أردني

    $log_entry .= " | MATCH: Orange Money JO | SUCCESS: Parsed Amount = $amount, Payer Phone = $payer_phone, Currency = $currency" . PHP_EOL;

    // TODO: اكتب منطق قاعدة البيانات هنا
    /*
        - ابحث عن معاملة "pending" تطابق المبلغ $amount ورقم الهاتف $payer_phone.
        - $sql = "UPDATE transactions SET status = 'completed' WHERE amount = ? AND phone_number = ? AND currency = 'JOD' AND status = 'pending' LIMIT 1";
    */

} else {
    // إذا لم تتطابق الرسالة مع نمط Orange Money
    $log_entry .= " | INFO: Message did not match the Orange Money pattern. Ignored." . PHP_EOL;
}

// كتابة كل شيء في ملف السجل
file_put_contents('sms_log.txt', $log_entry, FILE_APPEND);


// --- 5. إرسال رد إلى تطبيق الأندرويد ---
http_response_code(200);
echo json_encode(['status' => 'success', 'message' => 'Data received and processed.']);
?>


File: auth/sendEmail.php

<?php
require_once __DIR__ . '/../connect.php';

$email = filterRequest("email");
$token = filterRequest("token");

$admin='support@sefer.live';
$headers = "MIME-Version: 1.0" . "\r\n";
$headers .= "Content-type: text/html; charset=UTF-8" . "\r\n";
$headers .= "From: $admin" . "\r\n";

$subject = "Verify your email address";
$bodyEmail = "
<html>
<head>
<title>Verify your email address</title>
</head>
<body>
<p>Hi [$email],</p>

<p>We recently received a request to verify your email address for your account on SEFER App.</p>

<p>To verify your email address, please write this to app .</p>
$token

<p>If you did not request to verify your email address, please ignore this email.</p>

<p>Thank you,</p>
SEFER Team.
</body>
</html>
";

mail($email, $subject, $bodyEmail, $headers);

File: auth/login.php

<?php

require_once __DIR__ . '/../connect.php';

$email = filterRequest('email');
$phone = filterRequest('phone');
$password = filterRequest('password');

// Hash the password
$hashed_password = password_hash($password, PASSWORD_DEFAULT);

$sql = "SELECT
    passengers.`id`,
    passengers.`phone`,
    passengers.`email`,
    passengers.`password`,
    passengers.`gender`,
    passengers.`birthdate`,
    passengers.`site`,
    passengers.`first_name`,
    passengers.`last_name`,
    passengers.`education`,
    passengers.`employmentType`,
    passengers.`maritalStatus`,
    passengers.`created_at`,
    passengers.`updated_at`,
    email_verifications.verified
FROM
    `passengers`
LEFT JOIN email_verifications ON email_verifications.email = passengers.email
WHERE
    passengers.phone = :phone AND passengers.email = :email ";
$stmt = $con->prepare($sql);
$stmt->bindParam(':email', $email);
$stmt->bindParam(':phone', $phone);
$stmt->execute();
$data = $stmt->fetchAll(PDO::FETCH_ASSOC);
$count = $stmt->rowCount();

if ($count > 0) {
    $stored_password = $data[0]['password'];
    if (password_verify($password, $stored_password)) {
        unset($data[0]['password']);
        echo json_encode([
            "status" => "success",
            "count" => $count,
            "data" => $data
        ]);
    } else {
        // The password is incorrect
        echo json_encode([
            "status" => "Failure",
            "data" => "Incorrect password."
        ]);
        // jsonError("Incorrect password.");
    }
} else {
    // The user does not exist
    echo json_encode([
            "status" => "Failure",
            "data" => "User does not exist."
        ]);
    // jsonError("User does not exist.");
}
$conn->close();

?>

File: auth/verifyOtpMessage.php

<?php
require_once __DIR__ . '/../connect.php';

$phone_number = filterRequest("phone_number");
$token_code = filterRequest("token");

// Check if the phone number and token code match
$sql = "SELECT
    `id`,
    `phone_number`,
    `token`,
    `expiration_time`,
    `verified`,
    `created_at`
FROM
    `phone_verification_passenger`
WHERE
    `phone_number` = :phone_number AND `token` = :token_code";

$stmt = $con->prepare($sql);

// Log the parameters used in the SQL query for debugging
error_log("Executing SELECT SQL: " . $sql . " with phone_number=" . $phone_number . " and token_code=" . $token_code);

$stmt->bindParam(':phone_number', $phone_number, PDO::PARAM_STR);
$stmt->bindParam(':token_code', $token_code, PDO::PARAM_STR);

if ($stmt->execute()) {
    $result = $stmt->fetch();

    if ($result) {
        // Update the verified status
        $sql = "UPDATE `phone_verification_passenger` SET `verified` = 1 WHERE `phone_number` = :phone_number";
        $stmt = $con->prepare($sql);

        // Log the update query execution
        error_log("Executing UPDATE SQL: " . $sql . " with phone_number=" . $phone_number);

        $stmt->bindParam(':phone_number', $phone_number, PDO::PARAM_STR);
        
        if ($stmt->execute()) {
            jsonSuccess(null, "Your phone number has been verified.");
        } else {
            // Log if the update query fails
            error_log("Error executing UPDATE SQL: " . implode(", ", $stmt->errorInfo()));
            jsonError("An error occurred while verifying your phone number. Please try again.");
        }

    } else {
        // Log if no matching record was found
        error_log("No matching record found for phone_number=" . $phone_number . " and token_code=" . $token_code);
        jsonError("Your phone number could not be verified. Please try again.");
    }

} else {
    // Log if the select query fails
    error_log("Error executing SELECT SQL: " . implode(", ", $stmt->errorInfo()));
    jsonError("An error occurred while verifying your phone number. Please try again.");
}
?>

File: auth/packageInfo.php

<?php
require_once __DIR__ . '/../connect.php';

$platform = filterRequest("platform");
$appName = filterRequest("appName");

$sql = "SELECT
    `id`,
    `platform`,
    `appName`,
    `createdAt`,
    `version`
FROM
    `packageInfo`
WHERE
     platform='$platform' and appName='$appName';";

$stmt = $con->prepare($sql);
$stmt->execute();
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);

if ($stmt->rowCount() > 0) {
    // Print all the records
    // printData($result);
     jsonSuccess($data = $result);
} else {
    // Print a failure message
    jsonError($message = "No records found");
}
?>

File: auth/passengerRemovedAccountEmail.php

<?php
require_once __DIR__ . '/../connect.php';

$email = filterRequest("email");

$headers = "MIME-Version: 1.0" . "\r\n";
$headers .= "Content-type: text/html; charset=UTF-8" . "\r\n";
$headers .= "From: SEFER Team" . "\r\n";

// Create the email subject and body
$subject = 'Your SEFER account has been deleted';
$body = '

Dear passenger,

We are sorry to see you go, but we respect your decision to delete your SEFER account.

We would like to thank you for using our platform and for being a part of the SEFER community. We hope that you had a positive experience and that we were able to make your travels easier and more enjoyable.

If you have any questions or concerns, please do not hesitate to contact us.

Sincerely,

The SEFER Team
';

// Send the email
mail($email, $subject, $body);

?>

File: auth/sendVerifyEmail.php

<?php
require_once __DIR__ . '/../connect.php';

$email = filterRequest("email");
$token = filterRequest("token");

$sql = "SELECT * FROM `email_verifications` WHERE `email` = '$email'";
$stmt = $con->prepare($sql);
$stmt->execute();

$rowCount = $stmt->rowCount();

$admin='support@mobile-app.store';
$headers = "MIME-Version: 1.0" . "\r\n";
$headers .= "Content-type: text/html; charset=UTF-8" . "\r\n";
$headers .= "From: $admin" . "\r\n";

$subject = "Verify your email address";
$bodyEmail = "
<html>
<head>
<title>Verify your email address</title>
</head>
<body>
<p>Hi [$email],</p>

<p>We recently received a request to verify your email address for your account on SEFER App.</p>

<p>To verify your email address, please write this to app .</p>
$token

<p>If you did not request to verify your email address, please ignore this email.</p>

<p>Thank you,</p>
SEFER Team.
</body>
</html>
";



if ($rowCount > 0) {
    // The email already exists, so update the data
    $sql = "UPDATE `email_verifications` SET `token` = '$token' WHERE `email` = '$email'";
    $stmt = $con->prepare($sql);
    $stmt->execute();

    if ($stmt->rowCount() > 0) {
        // The update was successful
        jsonSuccess($message = "Email verification data updated successfully");
        mail($email, $subject, $bodyEmail, $headers);
    } else {
        // The update was unsuccessful
        jsonError($message = "Failed to update email verification data");
    }
} else {
    // The email does not exist, so insert the data
    $sql = "INSERT INTO `email_verifications` (`email`, `token`) VALUES ('$email', '$token')";
    $stmt = $con->prepare($sql);
    $stmt->execute();

    if ($stmt->rowCount() > 0) {
        // The insertion was successful
        jsonSuccess($message = "Email verification data saved successfully");
        mail($email, $subject, $bodyEmail, $headers);
    } else {
        // The insertion was unsuccessful
        jsonError($message = "Failed to save email verification data");
    }
}
?>


File: auth/signup.php

<?php
$allowRegistration = true;
require_once __DIR__ . '/../connect.php';

// جلب البيانات من المستخدم
$phone       = filterRequest("phone");
$email       = filterRequest("email");
$first_name  = filterRequest("first_name");
$last_name   = filterRequest("last_name");
$password    = filterRequest("password");
$gender      = filterRequest("gender");
$birthdate   = filterRequest("birthdate");
$site        = filterRequest("site");
$id          = filterRequest("id");

// تشفير البيانات الحساسة
$phone       = $encryptionHelper->encryptData($phone);
$email       = $encryptionHelper->encryptData($email);
$gender      = $encryptionHelper->encryptData($gender);
$birthdate   = $encryptionHelper->encryptData($birthdate);
$site        = $encryptionHelper->encryptData($site);
$first_name  = $encryptionHelper->encryptData($first_name);
$last_name   = $encryptionHelper->encryptData($last_name);

// تشفير الباسورد
$hashedPassword = password_hash($password, PASSWORD_DEFAULT);

try {
    // التحقق من وجود الإيميل أو رقم الهاتف مسبقًا
    $sql = "SELECT * FROM passengers WHERE phone = :phone OR email = :email";
    $stmt = $con->prepare($sql);
    $stmt->bindParam(":phone", $phone);
    $stmt->bindParam(":email", $email);
    $stmt->execute();
    $results = $stmt->fetchAll();

    if (count($results) > 0) {
        jsonError("The email or phone number is already registered.");
        exit;
    }

    // إدخال البيانات الجديدة
    $sql = "INSERT INTO passengers (
        id, phone, email, password, gender, birthdate, site, first_name, last_name
    ) VALUES (
        :id, :phone, :email, :password, :gender, :birthdate, :site, :first_name, :last_name
    )";
    $stmt = $con->prepare($sql);
    $stmt->bindParam(":id", $id);
    $stmt->bindParam(":phone", $phone);
    $stmt->bindParam(":email", $email);
    $stmt->bindParam(":password", $hashedPassword);
    $stmt->bindParam(":gender", $gender);
    $stmt->bindParam(":birthdate", $birthdate);
    $stmt->bindParam(":site", $site);
    $stmt->bindParam(":first_name", $first_name);
    $stmt->bindParam(":last_name", $last_name);
    $stmt->execute();

    if ($stmt->rowCount() > 0) {
        jsonSuccess(null, "success to save passenger data");
    } else {
        jsonError("Failed to save passenger data");
    }

} catch (PDOException $e) {
    error_log("Database Error: " . $e->getMessage());
    jsonError("An error occurred while saving the data.");
}
?>

File: auth/resetPassword.php


File: auth/cnMap.php

<?php
require_once __DIR__ . '/../connect.php';

// Import the map
$cn = array(
  "0" => "3",
  "1" => "7",
  "2" => "1",
  "3" => "9",
  "4" => "0",
  "5" => "5",
  "6" => "2",
  "7" => "6",
  "8" => "4",
  "9" => "8"
);

// Convert the map to a JSON string with JSON_FORCE_OBJECT option
$jsonString = json_encode($cn, JSON_FORCE_OBJECT);

// Send the JSON string to the Flutter app
echo $jsonString;
?>

File: auth/checkPhoneNumberISVerfiedPassenger.php

<?php

require_once __DIR__ . '/../connect.php';

// استقبال القيم
$phoneNumber = filterRequest("phone_number");
$email       = filterRequest("email");

// تشفير القيم المطلوبة للمقارنة داخل SQL
$phoneNumber = $encryptionHelper->encryptData($phoneNumber);
$email       = $encryptionHelper->encryptData($email);

// تنفيذ الاستعلام
$sql = "
    SELECT
        pv.*,
        p.email
    FROM
        `phone_verification_passenger` pv
    INNER JOIN 
        `passengers` p ON pv.phone_number = p.phone
    WHERE
        pv.phone_number = :phoneNumber AND p.email = :email
";
$stmt = $con->prepare($sql);
$stmt->bindParam(':phoneNumber', $phoneNumber, PDO::PARAM_STR);
$stmt->bindParam(':email', $email, PDO::PARAM_STR);
$stmt->execute();

if ($stmt->rowCount() > 0) {
    $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);

    // يمكنك هنا لاحقًا تفكيك تشفير أي حقل إذا كنت ترجع phone/email مثلاً للمستخدم، لكن في حالتنا ما في حاجة.

    jsonSuccess($rows);
} else {
    jsonError("No Phone verified or related email found");
}
?>

File: auth/cn_map.json

["3","7","1","9","0","5","2","6","4","8"]

File: auth/otpmessage.php

<?php

require_once __DIR__ . '/../connect.php'; // Contains DB connection, filterRequest, printSuccess/Failure, encryptionHelper

$receiver = filterRequest("phone_number"); // رقم الهاتف

if (empty($receiver)) {
    jsonError("Receiver phone number is required.");
    exit;
}

$username = getenv('SMS_USERNAME');
$password = getenv('SMS_PASSWORD_EGYPT'); // Make sure this is the correct variable name for Egypt
$sender   = getenv('SMS_SENDER');


if (!$username || !$password || !$sender) {
   
    exit;
}

$otp = rand(10000, 99999);
$message = "Tripz app code is " . $otp;

$apiUrl = 'https://sms.kazumi.me/api/sms/send-sms';
$payload = [
    'username' => $username,
    'password' => $password,
    'language' => 'e' , // Assuming 'e' is for English as per original
    'sender'   => $sender,
    'receiver' => $receiver,
    'message'  => $message
];
$jsonPayload = json_encode($payload);
$response = callAPI("POST", $apiUrl, $jsonPayload); 

if ($response && isset($response->message) && $response->message == 'Success') {
    // 3. تخزين في Redis بدلاً من MySQL (أسرع وأكثر أماناً مع TTL تلقائي)
    if ($redis) {
        try {
            $redis->setex("otp:passenger:$receiver", 300, $otp); // صلاحية 5 دقائق
            jsonSuccess(null, "OTP sent and saved to Redis successfully");
        } catch (Exception $e) {
            error_log("Redis Error (OTP): " . $e->getMessage());
            jsonError("OTP sent but failed to save in Redis");
        }
    } else {
        jsonError("Redis service unavailable");
    }
} else {
    jsonError("OTP not sent (SMS API failed or invalid response)");
}

// دالة الاتصال بالـ API
function callAPI($method, $url, $data) {
  
    $curl = curl_init();
    curl_setopt_array($curl, [
        CURLOPT_URL => $url,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_CUSTOMREQUEST => $method,
        CURLOPT_POSTFIELDS => $data,
        CURLOPT_HTTPHEADER => [
            "Content-Type: application/json",
            "Accept: application/json" // Often good to add
        ],
        CURLOPT_TIMEOUT => 30, // Set a timeout
        CURLOPT_CONNECTTIMEOUT => 10 // Set a connection timeout
    ]);
    $api_raw_response = curl_exec($curl);

    if (curl_errno($curl)) {
        $curl_error_msg = curl_error($curl);
        $curl_error_no = curl_errno($curl);
        error_log("cURL Error (callAPI): [{$curl_error_no}] " . $curl_error_msg);
        curl_close($curl);
        return false; // Indicate cURL failure clearly
    }
    curl_close($curl);

    $decoded_response = json_decode($api_raw_response);
    if (json_last_error() !== JSON_ERROR_NONE) {
         return null; // Indicate JSON decode failure
    }
    error_log("callAPI: Decoded response: " . print_r($decoded_response, true));
    return $decoded_response;
}
?>

File: auth/checkPhoneNumberISVerfiedDriver.php

<?php

require_once __DIR__ . '/../connect.php';

// استقبال وتشفير رقم الهاتف
$phoneNumber = filterRequest("phone_number");
$phoneNumber = $encryptionHelper->encryptData($phoneNumber);

// تجهيز الاستعلام باستخدام bindParam للحماية
$sql = "SELECT * FROM `phone_verification` WHERE `phone_number` = :phone_number";
$stmt = $con->prepare($sql);
$stmt->bindParam(":phone_number", $phoneNumber);
$stmt->execute();

if ($stmt->rowCount() > 0) {
    $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
    jsonSuccess($rows);
} else {
    jsonError("No phone verified yet found");
}
?>

File: auth/verifyEmail.php

<?php
require_once __DIR__ . '/../connect.php';

$email = filterRequest("email");
$token = filterRequest("token");

$sql = "SELECT `id`, `email`, `token`, `created_at`, `updated_at`, `verified` FROM `email_verifications` WHERE `email` = '$email' AND `token` = '$token'";
$stmt = $con->prepare($sql);
$stmt->execute();
$result = $stmt->fetch();

if ($result) {
    $id = $result["id"];
    $sql = "UPDATE `email_verifications` SET `verified` = 1 WHERE `id` = $id";
    $stmt = $con->prepare($sql);
    $stmt->execute();

    $admin='support@sefer.com';
    $headers = "MIME-Version: 1.0" . "\r\n";
    $headers .= "Content-type: text/html; charset=UTF-8" . "\r\n";
    $headers .= "From: $admin" . "\r\n";

    $subject = " Verify your email address";
    $bodyEmail="Subject: Verify your email address

Hi [$email],

Your email address has been verified.

Thank you,
SEFER Team";

    mail($email, $subject, $bodyEmail, $headers);

    jsonSuccess($message = "Your email address has been verified.");
} else {
    jsonError($message ="Your email address could not be verified. Please try again.");
}
?>

File: auth/loginFromGooglePassenger.php

<?php

require_once __DIR__ . '/../connect.php';

// استدعاء المعاملات
$email    = filterRequest('email');
$id       = filterRequest('id');
$platform = filterRequest("platform") ?: 'unknown';
$appName  = filterRequest("appName") ?: 'unknown';

// تشفير الإيميل لأنه يُرسل من التطبيق غير مشفّر
$email = $encryptionHelper->encryptData($email);

// تجهيز الاستعلام
$sql = "SELECT
    p.`id`,
    p.`phone`,
    p.`email`,
    p.`gender`,
    p.`status`,
    p.`birthdate`,
    p.`site`,
    p.`first_name`,
    p.`last_name`,
    p.`sosPhone`,
    p.`education`,
    p.`employmentType`,
    p.`maritalStatus`,
    p.`created_at`,
    p.`updated_at`,
    phone_verification_passenger.verified,
    invitesToPassengers.isInstall,
    invitesToPassengers.inviteCode,
    invitesToPassengers.isGiftToken,
    (SELECT `version` FROM `packageInfo` WHERE platform = :platform AND appName = :appName) AS package,
    promos.promo_code AS promo,
    promos.amount AS discount,
    promos.validity_end_date AS validity
FROM passengers p
LEFT JOIN phone_verification_passenger 
    ON phone_verification_passenger.phone_number = p.phone
LEFT JOIN invitesToPassengers 
    ON invitesToPassengers.inviterPassengerPhone = p.phone
LEFT JOIN promos 
    ON promos.passengerID = p.id
WHERE p.email = :email AND p.id = :id AND phone_verification_passenger.verified = '1'";

// تنفيذ الاستعلام
$stmt = $con->prepare($sql);
$stmt->bindParam(':email', $email);
$stmt->bindParam(':id', $id);
$stmt->bindParam(':appName', $appName);
$stmt->bindParam(':platform', $platform);
$stmt->execute();

$data  = $stmt->fetchAll(PDO::FETCH_ASSOC);
$count = $stmt->rowCount();

// تجهيز الرد
header('Content-Type: application/json');

if ($count > 0) {
    foreach ($data as &$row) {
        // فك تشفير الحقول الحساسة
        $row['phone']           = $encryptionHelper->decryptData($row['phone']);
        $row['email']           = $encryptionHelper->decryptData($row['email']);
        $row['gender']          = $encryptionHelper->decryptData($row['gender']);
        $row['birthdate']       = $encryptionHelper->decryptData($row['birthdate']);
        $row['site']            = $encryptionHelper->decryptData($row['site']);
        $row['first_name']      = $encryptionHelper->decryptData($row['first_name']);
        $row['last_name']       = $encryptionHelper->decryptData($row['last_name']);
        $row['sosPhone']        = $encryptionHelper->decryptData($row['sosPhone']);
        $row['education']       = $encryptionHelper->decryptData($row['education']);
        $row['employmentType']  = $encryptionHelper->decryptData($row['employmentType']);
        $row['maritalStatus']   = $encryptionHelper->decryptData($row['maritalStatus']);
    }

    echo json_encode([
        "status" => "success",
        "count"  => $count,
        "data"   => $data
    ]);
} else {
    error_log("User does not exist: " . $email);
    echo json_encode([
        "status" => "Failure",
        "data"   => "User does not exist."
    ]);
}

// تنظيف الموارد
$stmt = null;
$con  = null;
exit();

File: auth/syria/verifyOtp.php

<?php
$allowRegistration = true;
require_once __DIR__ . '/../../connect.php';

// تسجيل بداية الطلب
error_log("[Auth_Debug] Start processing phone verification request.");

$phoneNumber = filterRequest("phone_number");

if (!$phoneNumber) {
    error_log("[Auth_Error] Phone number is missing in the request.");
    jsonError("Phone number is required");
    exit();
}

// تسجيل الرقم (مشفر أو عادي حسب الحاجة، يفضل عدم تسجيله عادي لأسباب الخصوصية لكن هنا للتوضيح)
error_log("[Auth_Debug] Received phone number (Masked): " . substr($phoneNumber, 0, 7) . "*****");

// تشفير رقم الهاتف
$phoneNumber_encrypted = $encryptionHelper->encryptData($phoneNumber);
error_log("[Auth_Debug] Phone number encrypted successfully.");

try {
    // ✅ 1. حذف أي رموز قديمة لنفس الرقم
    error_log("[Auth_Step_1] Deleting old verification records for this phone...");
    
    $stmtDelete = $con->prepare("DELETE FROM phone_verification_passenger WHERE phone_number = ?");
    $stmtDelete->execute([$phoneNumber_encrypted]);
    
    error_log("[Auth_Step_1] Old records deleted (if any).");

    // ✅ 2. إدخال سجل جديد مع تحقق مباشر (بدون OTP)
    $now = date('Y-m-d H:i:s');
    error_log("[Auth_Step_2] Inserting new verified record at: " . $now);

    $stmt = $con->prepare("
        INSERT INTO phone_verification_passenger (phone_number, token, expiration_time, verified, created_at)
        VALUES (?, NULL, NULL, 1, ?)
    ");
    $stmt->execute([$phoneNumber_encrypted, $now]);
    
    error_log("[Auth_Step_2] New record inserted successfully.");

    // ✅ 3. فحص هل الراكب موجود مسبقاً
    error_log("[Auth_Step_3] Checking if passenger exists in passengers table...");

    $checkPassengerStmt = $con->prepare("
        SELECT * FROM passengers WHERE phone = ?
    ");
    $checkPassengerStmt->execute([$phoneNumber_encrypted]);
    $passenger = $checkPassengerStmt->fetch(PDO::FETCH_ASSOC);

    if ($passenger) {
        // ✅ الراكب موجود
        error_log("[Auth_Result] Passenger Found. ID: " . $passenger['id']);

        printSuccess([
            "message" => "Passenger already registered.",
            "isRegistered" => true,
            "passenger" => [
                "id" => $passenger['id'],
                "first_name" => $encryptionHelper->decryptData($passenger['first_name']),
                "last_name" => $encryptionHelper->decryptData($passenger['last_name']),
                "email" => $encryptionHelper->decryptData($passenger['email']),
                "phone" => $phoneNumber
            ]
        ]);
    } else {
        // ✅ الراكب جديد
        error_log("[Auth_Result] Passenger Not Found. Treating as new user.");

        printSuccess([
            "message" => "Phone number verified automatically (no OTP required).",
            "isRegistered" => false
        ]);
    }

} catch (PDOException $e) {
    // تسجيل الخطأ بالتفصيل في ملف اللوج
    error_log("[Auth_DB_Exception] Error: " . $e->getMessage() . " | File: " . $e->getFile() . " | Line: " . $e->getLine());
    
    // طباعة رسالة الخطأ للمستخدم (يفضل عدم إظهار تفاصيل الـ SQL للمستخدم النهائي لأسباب أمنية)
    jsonError("Database error occurred. Please contact support.");
} catch (Exception $e) {
    // التقاط أي أخطاء عامة أخرى
    error_log("[Auth_General_Exception] Error: " . $e->getMessage());
    jsonError("An unexpected error occurred.");
}

// تسجيل نهاية الطلب
error_log("[Auth_Debug] Request processing finished.");

?>

File: auth/syria/send_survey.php

<?php
require_once __DIR__ . '/../../connect.php';

$receiver = filterRequest("receiver");
if (!$receiver) {
    jsonError("رقم الهاتف مفقود");
    exit;
}

// توليد تأخير عشوائي بين 45 و 90 ثانية
$delay = rand(45, 90);
sleep($delay);

// رسالة الاستطلاع مع أزرار
$surveyMessage = [
    "type" => "buttons",
    "header" => [
        "type" => "text",
        "text" => "استطلاع رأي سريع 🌟"
    ],
    "body" => [
        "text" => "هل كانت تجربة التسجيل في تطبيق *سيرو* سهلة بالنسبة لك؟\n\n👇 اضغط أحد الخيارات:"
    ],
    "footer" => [
        "text" => "للتواصل: +962 7XXXXXXX - رابط التطبيق: https://intaleq.xyz"
    ],
    "buttons" => [
        [
            "type" => "reply",
            "reply" => [
                "id" => "feedback_yes",
                "title" => "👍 نعم"
            ]
        ],
        [
            "type" => "reply",
            "reply" => [
                "id" => "feedback_no",
                "title" => "👎 لا"
            ]
        ]
    ]
];

// استدعاء الدالة لإرسال الرسالة
$response = sendWhatsAppFromServer($receiver, $surveyMessage);
if ($response && isset($response["status"]) && $response["status"] === "sent") {
    jsonSuccess(null, "تم إرسال استطلاع الرأي بنجاح بعد $delay ثانية.");
} else {
    jsonError("فشل في إرسال استطلاع الرأي");
}
?>

File: auth/syria/secure_image.php

<?php
// File: secure_image.php
// يعرض الملف فقط إذا كان الرابط موقّع وصالح زمنياً.
// يعتمد نفس الثوابت/المسارات في upload_serial_document.php

require_once __DIR__ . '/../../connect.php';

const UPLOAD_ROOT = __DIR__ . "/../../private_uploads";
const SIGN_SECRET =  getenv('SECRET_KEY_HMAC'); // نفس المفتاح

// استلام المعطيات من الرابط
$driverId = $_GET['driver_id'] ?? '';
$docType  = $_GET['doc_type']  ?? '';
$extShort = $_GET['ext']       ?? '';
$expires  = $_GET['expires']   ?? '';
$signature= $_GET['signature'] ?? '';

if ($driverId === '' || $docType === '' || $extShort === '' || $expires === '' || $signature === '') {
    http_response_code(400); echo "Missing parameters."; exit;
}

// صلاحية الوقت
if ((int)$expires < time()) {
    http_response_code(403); echo "Link expired."; exit;
}

// تحقق من doc_type
$allowedDocTypes = [
    'driver_license_front',
    'driver_license_back',
    'car_license_front',
    'car_license_back',
];
if (!in_array($docType, $allowedDocTypes, true)) {
    http_response_code(403); echo "Invalid doc_type."; exit;
}

// تحقق من الامتداد
$allowedExts = ['jpg','png','webp'];
if (!in_array($extShort, $allowedExts, true)) {
    http_response_code(403); echo "Invalid ext."; exit;
}

// إعادة توليد التوقيع للمقارنة
$driverIdSafe = preg_replace('/[^A-Za-z0-9_\-]/', '_', $driverId);
$message      = $driverIdSafe . ':' . $docType . ':' . $extShort . ':' . $expires;
$expected     = hash_hmac('sha256', $message, SIGN_SECRET);

if (!hash_equals($expected, $signature)) {
    http_response_code(403); echo "Invalid signature."; exit;
}

// بناء المسار
$h = hash('sha1', $driverIdSafe);
$subdir     = substr($h, 0, 2) . '/' . substr($h, 2, 2);
$serverName = "{$driverIdSafe}__{$docType}.{$extShort}";
$path       = UPLOAD_ROOT . '/' . $subdir . '/' . $serverName;

if (!is_file($path)) {
    http_response_code(404); echo "File not found."; exit;
}

// تحديد النوع
$finfo = new finfo(FILEINFO_MIME_TYPE);
$mime  = $finfo->file($path) ?: 'application/octet-stream';

header('Content-Type: ' . $mime);
header('Content-Length: ' . filesize($path));
header('X-Content-Type-Options: nosniff');
// (اختياري) اطلب توكن وصول إضافي عبر Authorization للتحكم الأدق.
// مثال: تحقق من $_SERVER['HTTP_AUTHORIZATION'] هنا إن أردت.
readfile($path);

File: auth/syria/register_passenger.php

<?php
// File: register_passenger.php

// إعدادات إظهار الأخطاء
ini_set('display_errors', 0);
error_reporting(E_ALL);
$allowRegistration = true;
require_once __DIR__ . '/../../connect.php';

// تعريف بادئة للوج (Tag) لسهولة البحث عنها في ملف الأخطاء
$logTag = "[Register_Debug_passenger]";

$step = 0;

try {
    // ======================================================
    // Step 1: استقبال البيانات
    // ======================================================
    $step = 1;
    $phoneNumber = filterRequest("phone_number");
    $firstName   = filterRequest("first_name");
    $lastName    = filterRequest("last_name");
    $email       = filterRequest("email"); 

    // طباعة وصول البيانات (مع إخفاء جزء من الرقم)
    error_log("$logTag Step 1: Received request. Phone: " . substr($phoneNumber, 0, 7) . "*****");

    // ======================================================
    // Step 2: التحقق من المدخلات
    // ======================================================
    $step = 2;
    if (empty($phoneNumber) || empty($firstName) || empty($lastName)) {
        error_log("$logTag Step 2 Error: Missing required fields.");
        jsonError("Required fields are missing.");
        exit();
    }

    // ======================================================
    // Step 3: معالجة الإيميل
    // ======================================================
    $step = 3;
    if (empty($email)) {
        $email = $phoneNumber . '@intaleqapp.com';
        error_log("$logTag Step 3: Email was empty, generated default: " . substr($email, 0, 5) . "***");
    }

    // ======================================================
    // Step 4: تشفير البيانات
    // ======================================================
    $step = 4;
    error_log("$logTag Step 4: Encrypting data...");
    
    if (!isset($encryptionHelper)) {
        throw new Exception("Encryption Helper class is missing.");
    }
    
    $phoneNumber_encrypted = $encryptionHelper->encryptData($phoneNumber);
    $firstName_encrypted   = $encryptionHelper->encryptData($firstName);
    $lastName_encrypted    = $encryptionHelper->encryptData($lastName);
    $email_encrypted       = $encryptionHelper->encryptData($email);
    $password_hashed       = password_hash($email, PASSWORD_DEFAULT); 
    $unknown_encrypted     = $encryptionHelper->encryptData("unknown yet");

    // ======================================================
    // Step 5: إنشاء ID فريد
    // ======================================================
    $step = 5;
   // $uniqueId = substr(md5(uniqid(mt_rand(), true)), 0, 20);
    
    $uniqueId = substr(md5($phoneNumber_encrypted), 0, 20);

    error_log("$logTag Step 5: Generated Unique ID: $uniqueId");

    // ======================================================
    // Step 6: التحقق من وجود المستخدم (Database Check)
    // ======================================================
    $step = 6;
    $checkStmt = $con->prepare("SELECT id FROM passengers WHERE phone = ?");
    $checkStmt->execute([$phoneNumber_encrypted]);
    
    if ($checkStmt->rowCount() > 0) {
        error_log("$logTag Step 6 Error: User already exists.");
        jsonError("User with this phone number or email already exists.");
        exit();
    }

    // ======================================================
    // Step 7: الإضافة (Insert User)
    // ======================================================
    $step = 7;
    error_log("$logTag Step 7: Inserting into passengers table...");

    $insertStmt = $con->prepare("
        INSERT INTO passengers (id, first_name, last_name, email, phone, password, gender, birthdate, site, sosPhone, education, employmentType, maritalStatus, status, created_at, updated_at)
        VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'active', NOW(), NOW())
    ");
    $success = $insertStmt->execute([
        $uniqueId, 
        $firstName_encrypted, 
        $lastName_encrypted, 
        $email_encrypted, 
        $phoneNumber_encrypted, 
        $password_hashed, 
        $unknown_encrypted, 
        $unknown_encrypted, 
        $unknown_encrypted, 
        $unknown_encrypted, 
        $unknown_encrypted, 
        $unknown_encrypted, 
        $unknown_encrypted 
    ]);

    if (!$success) {
        $errorInfo = $insertStmt->errorInfo();
        // طباعة تفاصيل خطأ الـ SQL في اللوج
        error_log("$logTag Step 7 Error: SQL Insert Failed. Details: " . json_encode($errorInfo));
        jsonError("Failed to create user account.");
        exit();
    }

    
    // ======================================================
    // Step 9: جلب البيانات لإعادتها
    // ======================================================
    $step = 9;
    $userStmt = $con->prepare("SELECT * FROM passengers WHERE id = ?");
    $userStmt->execute([$uniqueId]);
    $newUser = $userStmt->fetch(PDO::FETCH_ASSOC);
    
    // ======================================================
    // Step 10: فك التشفير وإرسال الرد
    // ======================================================
    $step = 10;
    if ($newUser) {
        unset($newUser['password']);
        foreach ($newUser as $key => &$value) {
            if ($key !== 'id' && $key !== 'status' && $key !== 'created_at' && $key !== 'updated_at' && !is_null($value)) {
                $value = $encryptionHelper->decryptData($value);
            }
        }
    }

    error_log("$logTag Success: User registered successfully.");
    jsonSuccess(["status" => "registration_success", "data" => $newUser]);

} catch (PDOException $e) {
    // طباعة خطأ قاعدة البيانات في اللوج
    error_log("$logTag PDO Exception at Step $step: " . $e->getMessage());
    jsonError("Database Error.");
} catch (Exception $e) {
    // طباعة الأخطاء العامة في اللوج
    error_log("$logTag General Exception at Step $step: " . $e->getMessage());
    jsonError("General Error.");
}
?>

File: auth/syria/uploadSyrianDocs.php

<?php
// File: upload_serial_document.php
// يرفع صورة وثيقة إلى مسار خاص (خارج الويب العام) ويُرجع Signed URL مؤقّت.

// بيئتك
require_once __DIR__ . '/../../connect.php'; // يجب أن يوفّر: $con (اختياري) + printSuccess/printFailure + filterRequest

// --------- إعدادات ---------
const MAX_FILE_MB     = 5; 
const ALLOWED_MIMES   = ['image/jpeg','image/png','image/webp']; // فقط صور
const UPLOAD_ROOT     = __DIR__ . "/../../private_uploads"; // مجلد خاص (غير عام)
const SIGN_SECRET     = getenv('SECRET_KEY_HMAC'); // غيّرها واقرأها من .env
const PUBLIC_BASE     = 'https://syria.intaleq.xyz/siro'; // الدومين العلني
const SIGNED_TTL_SEC  = 172800; // 2 days = 60*60*24

// أنشئ مجلد الرفع إن لم يكن موجودًا
if (!is_dir(UPLOAD_ROOT)) { @mkdir(UPLOAD_ROOT, 0700, true); }

// (اختياري) هيدرز أمان
$authHeader = $_SERVER['HTTP_AUTHORIZATION'] ?? '';
$hmacHeader = $_SERVER['HTTP_X_HMAC_AUTH'] ?? '';
// TODO: تحقّق حسب منطقك إن أردت فرض المصادقة هنا.

// --------- حقول مطلوبة من Flutter عبر filterRequest ---------
$driverId = filterRequest('driver_id');
$docType  = filterRequest('doc_type');
$purpose  = filterRequest('purpose'); // اختياري

if (empty($driverId) || empty($docType)) {
    jsonError("driver_id and doc_type are required.");
    exit;
}

// اسمح فقط بقيم محددة للوثائق
$allowedDocTypes = [
    'driver_license_front',
    'driver_license_back',
    'car_license_front',
    'car_license_back',
];
if (!in_array($docType, $allowedDocTypes, true)) {
    jsonError("Invalid doc_type.");
    exit;
}

// --------- التحقق من الملف ---------
if (!isset($_FILES['file']) || $_FILES['file']['error'] !== UPLOAD_ERR_OK) {
    jsonError("No file uploaded or upload error.");
    exit;
}
$tmpPath  = $_FILES['file']['tmp_name'];
$origName = $_FILES['file']['name'] ?? 'upload.bin';
$size     = filesize($tmpPath);
if ($size === false || $size <= 0) {
    jsonError("Invalid file size."); exit;
}
if ($size > MAX_FILE_MB * 1024 * 1024) {
    jsonError("File too large. Max " . MAX_FILE_MB . " MB."); exit;
}

// MIME دقيق
$finfo = new finfo(FILEINFO_MIME_TYPE);
$mime  = $finfo->file($tmpPath) ?: 'application/octet-stream';
if (!in_array($mime, ALLOWED_MIMES, true)) {
    jsonError("Unsupported file type: $mime"); exit;
}

// لاحقة الامتداد
$extMap = [
    'image/jpeg' => '.jpg',
    'image/png'  => '.png',
    'image/webp' => '.webp',
];
$ext = $extMap[$mime];

// --------- توليد مسار حتمي بدون تاريخ ---------
// تنظيف driver_id لاسم ملف آمن
$driverIdSafe = preg_replace('/[^A-Za-z0-9_\-]/', '_', $driverId);
// شجرة مجلدات ثابتة من hash(driver_id) لتوزيع الملفات
$h = hash('sha1', $driverIdSafe);
$subdir  = substr($h, 0, 2) . '/' . substr($h, 2, 2);
$destDir = UPLOAD_ROOT . '/' . $subdir;
if (!is_dir($destDir)) { @mkdir($destDir, 0700, true); }

// الاسم النهائي بدون تاريخ
$serverName = "{$driverIdSafe}__{$docType}{$ext}";
$destPath   = $destDir . '/' . $serverName;

// استبدال أي نسخة قديمة عن قصد (overwrite)
if (is_file($destPath)) { @unlink($destPath); }

// نقل الملف
if (!move_uploaded_file($tmpPath, $destPath)) {
    jsonError("Failed to save the uploaded file.");
    exit;
}
@chmod($destPath, 0600);

// --------- Signed URL ---------
// سنضمّن driver_id و doc_type و ext في الرابط والتوقيع.
// ext بدون النقطة
$extShort = ltrim($ext, '.');
$expires  = time() + SIGNED_TTL_SEC;

// الرسالة الموقّعة: driver_id:doc_type:ext:expires
$message   = $driverIdSafe . ':' . $docType . ':' . $extShort . ':' . $expires;
$signature = hash_hmac('sha256', $message, SIGN_SECRET);

// رابط القراءة عبر البوابة الآمنة فقط
// ملاحظة: لا نُرجع المسار الحقيقي، فقط معطيات موقّعة
$fileUrl = PUBLIC_BASE . "/secure_image.php"
        . "?driver_id={$driverIdSafe}"
        . "&doc_type={$docType}"
        . "&ext={$extShort}"
        . "&expires={$expires}"
        . "&signature={$signature}";

// --------- استجابة ---------
printSuccess([
    "status"        => "success",
    "success_file"  => true,
    "file_url"      => $fileUrl,
    "file_name"     => $serverName,        // الاسم الفعلي المحفوظ
    "driver_id"     => $driverIdSafe,
    "doc_type"      => $docType,
    "mime_type"     => $mime,
    "size_bytes"    => $size,
    "expires_at"    => date('c', $expires)
]);

File: auth/syria/delete_old_images.php

<?php
/**
 * delete_old_serial_docs.php
 * يحذف صور الوثائق الأقدم من مدة محددة (افتراضي 48 ساعة) من private_uploads
 * ضع الملف بجانب upload_serial_document.php ليستخدم نفس الشجرة.
 */

date_default_timezone_set('Asia/Damascus');

// === الإعدادات ===
// نفس ما في upload_serial_document.php:
const UPLOAD_ROOT    = __DIR__ . "/../../private_uploads";
const ALLOWED_EXTS   = ['jpg','png','webp'];

// المدة قبل الحذف (ثواني): افتراضي يومين، ويمكن تمريرها عبر CLI
$ttlSeconds = 2 * 24 * 60 * 60; // 48 ساعة
if (PHP_SAPI === 'cli' && isset($argv[1]) && ctype_digit($argv[1])) {
    $ttlSeconds = (int)$argv[1];
}

// ملف لوج اختياري
$logFile = __DIR__ . '/delete_old_serial_docs.log';
$log = @fopen($logFile, 'ab');

// دالة بسيطة للّوج
$logln = function(string $msg) use ($log) {
    $line = '[' . date('Y-m-d H:i:s') . '] ' . $msg . PHP_EOL;
    if ($log) @fwrite($log, $line);
};

// تحقّق أن مجلد الرفع صحيح وموجود
$root = realpath(UPLOAD_ROOT);
if ($root === false || !is_dir($root)) {
    $logln("❌ UPLOAD_ROOT not found: " . UPLOAD_ROOT);
    exit(1);
}

$logln("===== Start cleanup in: {$root} | TTL={$ttlSeconds}s =====");

// مُكرّر آمن عبر RecursiveIterator
$it = new RecursiveIteratorIterator(
    new RecursiveDirectoryIterator($root, FilesystemIterator::SKIP_DOTS),
    RecursiveIteratorIterator::CHILD_FIRST
);

$now = time();
$deleted = 0;
$checked = 0;

// اسم الملف المتوقع: driverId__docType.ext
$docTypes = [
  'driver_license_front','driver_license_back',
  'car_license_front','car_license_back',
];
$docTypesRegex = implode('|', array_map('preg_quote', $docTypes));

foreach ($it as $node) {
    if (!$node->isFile()) continue;
    $checked++;

    $path = $node->getPathname();
    $ext  = strtolower($node->getExtension());

    // فلترة الامتدادات
    if (!in_array($ext, ALLOWED_EXTS, true)) continue;

    // فلترة اسم الملف (حماية من حذف ملفات أخرى)
    $name = $node->getBasename();
    if (!preg_match('/^[A-Za-z0-9_-]+__(' . $docTypesRegex . ')\.(jpg|png|webp)$/i', $name)) {
        continue;
    }

    $age = $now - $node->getMTime();
    if ($age >= $ttlSeconds) {
        if (@unlink($path)) {
            $deleted++;
            $logln("🗑 Deleted: {$path} | age=" . round($age/3600, 1) . "h");
        } else {
            $logln("⚠️ Failed to delete: {$path}");
        }
    }
}

$logln("Done. checked={$checked}, deleted={$deleted}");
if ($log) @fclose($log);

File: auth/syria/sendWhatsOpt.php

<?php
$allowRegistration = true;
require_once __DIR__ . '/../../connect.php';

error_log("--- [send_otp_pass.php] Started ---");

/* Helpers */
function normalize_phone($s) { return preg_replace('/\D+/', '', (string)$s); }

/**
 * Check blacklist by encrypted phone
 */
function is_blacklisted(PDO $con, $encryptionHelper, string $phone): bool {
    $raw   = trim($phone);
    $norm  = normalize_phone($raw);

    $enc_raw  = $encryptionHelper->encryptData($raw);
    $enc_norm = $encryptionHelper->encryptData($norm);

    $sql = "SELECT 1
              FROM passenger_blacklist
             WHERE phone IN (:enc_raw, :enc_norm)
               AND (expires_at IS NULL OR expires_at > NOW())
             LIMIT 1";

    $q = $con->prepare($sql);
    $q->execute([
        'enc_raw'  => $enc_raw,
        'enc_norm' => $enc_norm,
    ]);

    return (bool)$q->fetchColumn();
}

/* 0) Get phone number */
$receiver = filterRequest("receiver");
if (!$receiver) {
    jsonError('Phone number is required.');
    exit();
}

if (is_blacklisted($con, $encryptionHelper, $receiver)) {
    jsonError('This phone is blacklisted and cannot receive OTP.');
    error_log("[send_otp] BLOCKED (blacklisted): $receiver");
    exit();
}

/* 1) Generate OTP */
$otp = rand(10000, 99999);
$messageBody = "Your verification code for Siro is: " . $otp;

/* 🟢 2) Skip sending and log instead */
error_log("[send_otp] Skipping actual send. OTP generated for $receiver: $otp");

/* 3) Save OTP (encrypted) */
$receiver_enc = $encryptionHelper->encryptData($receiver);
$otp_enc      = $encryptionHelper->encryptData($otp);

$exp = date('Y-m-d H:i:s', strtotime('+5 minutes'));
$now = date('Y-m-d H:i:s');

try {
    $con->prepare("DELETE FROM phone_verification_passenger WHERE phone_number = ?")
        ->execute([$receiver_enc]);

    $stmt = $con->prepare("
        INSERT INTO phone_verification_passenger
            (phone_number, token, expiration_time, verified, created_at)
        VALUES (?, ?, ?, 0, ?)
    ");
    $stmt->execute([$receiver_enc, $otp_enc, $exp, $now]);

    jsonSuccess(null, 'OTP generated and saved successfully (no message sent)');
    error_log("[send_otp] OTP saved successfully for $receiver");

} catch (PDOException $e) {
    error_log("[send_otp] DB error: ".$e->getMessage());
    jsonError('OTP generated but failed to save to database');
}

/*
require_once __DIR__ . '/../../connect.php';

error_log("--- [send_otp.php] Started ---");


function normalize_phone($s) { return preg_replace('/\D+/', '', (string)$s); }


function is_blacklisted(PDO $con, $encryptionHelper, string $phone): bool {
    $raw   = trim($phone);
    $norm  = normalize_phone($raw);

    // شَفِّر قبل السؤال
    $enc_raw  = $encryptionHelper->encryptData($raw);
    $enc_norm = $encryptionHelper->encryptData($norm);

    $sql = "SELECT 1
              FROM passenger_blacklist
             WHERE phone IN (:enc_raw, :enc_norm)
               AND (expires_at IS NULL OR expires_at > NOW())
             LIMIT 1";

    $q = $con->prepare($sql);
    $q->execute([
        'enc_raw'  => $enc_raw,
        'enc_norm' => $enc_norm,
    ]);

    return (bool)$q->fetchColumn();
}

$receiver = filterRequest("receiver");
if (!$receiver) { jsonError('Phone number is required.'); exit(); }

if (is_blacklisted($con, $encryptionHelper, $receiver)) {
    jsonError('This phone is blacklisted and cannot receive OTP.');
    error_log("[send_otp] BLOCKED (blacklisted): $receiver");
    exit();
}

$otp = rand(10000, 99999);
$messageBody = "Your verification code for Siro is: " . $otp;

function normalize($raw) {
    if (is_string($raw)) return json_decode($raw, true) ?: [];
    if ($raw instanceof stdClass) return (array)$raw;
    return is_array($raw) ? $raw : [];
}

$response = normalize(sendWhatsAppFromServer($receiver, $messageBody));
$sentOK   = $response['success'] ?? false;

if (!$sentOK) {
    error_log("[send_otp] WA-Server failed ⇒ ".(($response['message'] ?? null) ?: json_encode($response)));

    $payload = [
        "number"       => $receiver,
        "type"         => "text",
        "message"      => $messageBody,
        "instance_id"  => getenv("RASEEL_DRIVER_INSTANCE_ID"),
        "access_token" => getenv("RASEEL_DRIVER_ACCESS_TOKEN")
    ];
    $response = callAPI("POST", "https://raseelplus.com/api/send", json_encode($payload));
    $response = normalize($response);

    $sentOK   = ($response['status'] ?? '') === 'success';
    if (!$sentOK) {
        error_log("[send_otp] RaseelPlus failed ⇒ ".json_encode($response));
        jsonError('Failed to send OTP: '.($response['message'] ?? 'Unknown error'));
        exit();
    }
}

$receiver_enc = $encryptionHelper->encryptData($receiver);          // الهاتف المُرسل (خام) مُشفّر
$otp_enc      = $encryptionHelper->encryptData($otp);

$exp = date('Y-m-d H:i:s', strtotime('+5 minutes'));
$now = date('Y-m-d H:i:s');

try {
    $con->prepare("DELETE FROM phone_verification_passenger WHERE phone_number = ?")
        ->execute([$receiver_enc]);

    $stmt = $con->prepare("
        INSERT INTO phone_verification_passenger
            (phone_number, token, expiration_time, verified, created_at)
        VALUES (?, ?, ?, 0, ?)
    ");
    $stmt->execute([$receiver_enc, $otp_enc, $exp, $now]);

    jsonSuccess(null, 'OTP sent and saved successfully');
    error_log("[send_otp] OTP saved for $receiver");

} catch (PDOException $e) {
    error_log("[send_otp] DB error: ".$e->getMessage());
    jsonError('OTP sent but failed to save to database');
}

function callAPI($method, $url, $data) {
    $ch = curl_init();
    curl_setopt_array($ch, [
        CURLOPT_URL            => $url,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_CUSTOMREQUEST  => $method,
        CURLOPT_POSTFIELDS     => $data,
        CURLOPT_HTTPHEADER     => [
            "Content-Type: application/json",
            "Accept: application/json"
        ],
    ]);
    $body = curl_exec($ch);
    $err  = curl_error($ch);
    curl_close($ch);
    return $err ? [] : json_decode($body, true);
}
*/

File: auth/syria/auth_proxy.php

<?php
// Start a session to store state and tokens.
session_start();

// 1. SETUP: Install the Google API Client Library
// Run this command in your project directory: composer require google/apiclient:^2.0
require_once __DIR__ . '/vendor/autoload.php';

// 2. CONFIGURATION: Replace with your credentials from Google Cloud Console
$clientID = '1086900987150-j8brn0i5s97315kh1ej9jr72grkfqgh5.apps.googleusercontent.com'; // Replace with your Client ID
$clientSecret = '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'; // Replace with your Client Secret
// This must be the exact URL of this script.
$redirectUri = 'https://api.tripz-egypt.com/tripz/auth/syria/auth_proxy.php'; // Replace with your script's URL

// 3. APP CONFIGURATION: Your Flutter app's custom URI scheme
// This is how the browser will redirect back to your app.
$appRedirectScheme = 'siroapp://auth'; // e.g., myapp://auth

// Create a new Google Client object
$client = new Google_Client();
$client->setClientId($clientID);
$client->setClientSecret($clientSecret);
$client->setRedirectUri($redirectUri);
$client->addScope("email");
$client->addScope("profile");

// 4. LOGIC: Handle the authentication flow
if (isset($_GET['code'])) {
    // A. User has been redirected back from Google with an authorization code.
    try {
        // Exchange the authorization code for an access token.
        $token = $client->fetchAccessTokenWithAuthCode($_GET['code']);
        
        if (isset($token['error'])) {
            // Handle error from Google
            throw new Exception('Error fetching access token: ' . $token['error_description']);
        }
        
        $client->setAccessToken($token['access_token']);

        // Get user profile information from Google.
        $google_oauth = new Google_Service_Oauth2($client);
        $google_account_info = $google_oauth->userinfo->get();
        
        $id = $google_account_info->id;
        $email = $google_account_info->email;
        $name = $google_account_info->name;
        $picture = $google_account_info->picture;

        // B. Redirect back to the Flutter app with the user data in the URL.
        // We use urlencode to ensure data is passed correctly.
        $redirectUrl = $appRedirectScheme . 
                       '?status=success' . 
                       '&id=' . urlencode($id) . 
                       '&email=' . urlencode($email) . 
                       '&name=' . urlencode($name) .
                       '&picture=' . urlencode($picture);
                       
        header('Location: ' . $redirectUrl);
        exit();

    } catch (Exception $e) {
        // C. Handle any errors and redirect back to the app with an error status.
        $error_message = urlencode($e->getMessage());
        header('Location: ' . $appRedirectScheme . '?status=error&message=' . $error_message);
        exit();
    }
} else {
    // D. This is the initial request from the Flutter app.
    // Redirect the user to Google's OAuth 2.0 server for authentication.
    $authUrl = $client->createAuthUrl();
    header('Location: ' . $authUrl);
    exit();
}
?>

File: auth/syria/driver/isPhoneVerified.php

<?php
require_once __DIR__ . '/../../../connect.php';

$phoneNumber = filterRequest("phone_number");

// تشفير الرقم قبل البحث
$phoneNumber_encrypted = $encryptionHelper->encryptData($phoneNumber);

try {
    // الاستعلام عن السائق حسب رقم الهاتف وحالة التحقق
    $stmt = $con->prepare("
        SELECT * FROM phone_verification 
        WHERE phone_number = ? AND is_verified = 1
    ");
    $stmt->execute([$phoneNumber_encrypted]);
    $driver = $stmt->fetch(PDO::FETCH_ASSOC);

    if ($driver) {
        jsonSuccess(null, "Phone number is verified.");
    } else {
        jsonError("Phone number is not verified or does not exist.");
    }

} catch (PDOException $e) {
    jsonError("Database error: " . $e->getMessage());
}

File: auth/syria/driver/verifyOtp.php

<?php
require_once __DIR__ . '/../../../connect.php';

$phoneNumber = filterRequest("phone_number");
$email = $phoneNumber . '@intaleqapp.com';

error_log("📥 [verifyOtp.php] Received phone number: $phoneNumber");

// 🔐 تشفير البيانات
$phoneNumber_encrypted = $encryptionHelper->encryptData($phoneNumber);
$email_encrypted       = $encryptionHelper->encryptData($email);

try {
    // 🧹 حذف أي رموز قديمة لنفس الرقم
    $con->prepare("DELETE FROM phone_verification WHERE phone_number = ?")
        ->execute([$phoneNumber_encrypted]);

    // 🧾 توليد driverID فريد
    $raw = $phoneNumber;
    $driverID = substr(md5($raw), 2, 20);

    // 🔐 توليد رمز تجريبي (بدون OTP حقيقي لتجنب Null)
    $dummyToken = $encryptionHelper->encryptData('AUTO');

    // 🕒 الوقت الحالي
    $now = date('Y-m-d H:i:s');

    // ✅ إدخال سجل تحقق مباشر
    $stmt = $con->prepare("
        INSERT INTO phone_verification 
            (phone_number, token_code, email, driverId, expiration_time, is_verified, created_at)
        VALUES (?, ?, ?, ?, NULL, 1, ?)
    ");
    $stmt->execute([$phoneNumber_encrypted, $dummyToken, $email_encrypted, $driverID, $now]);

    error_log("✅ [verifyOtp.php] Auto verification record inserted successfully for $phoneNumber");

    // 🔍 التحقق إذا السائق موجود مسبقاً
    $checkDriverStmt = $con->prepare("SELECT * FROM driver WHERE phone = ?");
    $checkDriverStmt->execute([$phoneNumber_encrypted]);
    $driver = $checkDriverStmt->fetch(PDO::FETCH_ASSOC);

    if ($driver) {
        error_log("👤 [verifyOtp.php] Driver already registered. Returning driver info.");
        printSuccess([
            "message" => "Driver already registered.",
            "isRegistered" => true,
            "driver" => [
                "id"         => $driver['id'],
                "first_name" => $encryptionHelper->decryptData($driver['first_name']),
                "last_name"  => $encryptionHelper->decryptData($driver['last_name']),
                "email"      => $encryptionHelper->decryptData($driver['email']),
                "phone"      => $phoneNumber
            ]
        ]);
    } else {
        error_log("🆕 [verifyOtp.php] Phone verified automatically. Driver not found.");
        printSuccess([
            "message" => "Phone number verified automatically (no OTP required).",
            "isRegistered" => false,
            "driverID" => $driverID
        ]);
    }

} catch (PDOException $e) {
    error_log("💥 [verifyOtp.php] PDO ERROR: " . $e->getMessage());
    jsonError("Database error: " . $e->getMessage());
}
?>

File: auth/syria/driver/driver_details.php

<?php
require_once __DIR__ . '/../../../connect.php';

$driverId = filterRequest("id");

if (empty($driverId)) {
    jsonError("driver_id is required.");
    exit;
}

try {
    // تفاصيل السائق
    $sql = "SELECT * FROM driver WHERE id = :id LIMIT 1";
    $stmt = $con->prepare($sql);
    $stmt->execute([':id' => $driverId]);
    $driver = $stmt->fetch(PDO::FETCH_ASSOC);

    if (!$driver) {
        jsonError("Driver not found.");
        exit;
    }

    // فك التشفير للحقول الحساسة
    foreach ($driver as $k => $v) {
        if (in_array($k, ['phone',
            'email',
            'first_name',
            'last_name',
            'national_number',
            'address','gender','site',
            'birthdate',
            'name_arabic'])) {
            $driver[$k] = $encryptionHelper->decryptData($v);
        }
    }

    // الوثائق
    $sql2 = "SELECT doc_type, image_name, link FROM driver_documents WHERE driverID = :id";
    $stmt2 = $con->prepare($sql2);
    $stmt2->execute([':id' => $driverId]);
    $docs = $stmt2->fetchAll(PDO::FETCH_ASSOC);

    printSuccess([
        "driver" => $driver,
        "documents" => $docs
    ]);
} catch (PDOException $e) {
    jsonError("Error: " . $e->getMessage());
}

File: auth/syria/driver/register_driver_and_car_signed.php

<?php
/**
 * Endpoint: register_driver_and_car.php (نسخة محدثة)
 * Method: POST (multipart/form-data أو x-www-form-urlencoded)
 * الوظيفة: إنشاء سائق + تسجيل مركبة + حفظ روابط الوثائق الموقّعة (من السيرفر السوري)
 * ملاحظة: لا نتلقّى ملفات هنا. نتلقى فقط روابط secure_image.php الموقّعة.
 */
$allowRegistration = true;
require_once __DIR__ . '/../../../connect.php';
header('Content-Type: application/json; charset=utf-8');

try {
    if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
        jsonError("Invalid method.");
        exit;
    }

    /* ========== إعدادات عامة ========== */
    // الدومينات المسموح بها للروابط الموقّعة (السيرفر السوري)
    $ALLOWED_SIGNED_HOSTS = [
        'syria.intaleq.xyz',   // عدّل حسب بيئتك
        'applink.syria',       // مثال آخر إن كان لديك دومين إضافي
    ];

    // توثيق شكل الروابط:  secure_image.php?driver_id=...&doc_type=...&ext=jpg|png|webp&expires=...&signature=...
    $allowedDocTypes = [
        'driver_license_front',
        'driver_license_back',
        'car_license_front',
        'car_license_back',
    ];
    $allowedExts = ['jpg','png','webp'];

    /* ========== 1) جلب الحقول ========== */
    $required = ["phone", "password", "first_name", "last_name"];
    $optional = [
        "id","email","gender","license_type","national_number",
        "name_arabic","issue_date","expiry_date","license_categories",
        "address","licenseIssueDate","status","birthdate","site",
        "employmentType","maritalStatus","fullNameMaritial","expirationDate"
    ];

    // حقول السيارة (مطلوبة)
    $carRequired = [
        "vin","car_plate","make","model","year","expiration_date",
        "color","owner","color_hex","fuel"
    ];

    // روابط الوثائق (مطلوبة)
    $docUrlKeys = [
        'driver_license_front_url',
        'driver_license_back_url',
        'car_license_front_url',
        'car_license_back_url'
    ];

    $data = [];
    foreach ($required as $f) {
        $v = filterRequest($f);
        if ($v === null || $v === '') {
            jsonError("Missing required field: $f");
            exit;
        }
        $data[$f] = $v;
    }

    foreach ($optional as $f) {
        $v = filterRequest($f);
        $data[$f] = ($v === null || $v === '' || $v === 'Not specified') ? null : $v;
    }

    $car = [];
    foreach ($carRequired as $f) {
        $v = filterRequest($f);
        if ($v === null || $v === '') {
            jsonError("Missing required field: $f");
            exit;
        }
        $car[$f] = $v;
    }

    $docUrls = [];
    foreach ($docUrlKeys as $k) {
        $v = filterRequest($k);
        if ($v === null || trim($v) === '') {
            jsonError("Missing signed URL: $k");
            exit;
        }
        $docUrls[$k] = trim($v);
    }

    /* ========== 2) توليد id إذا مفقود + بناء email افتراضي إن لزم ========== */
    if (empty($data['id'])) {
        $data['id'] = 'DRV' . date('YmdHis') . random_int(1000, 9999);
    }
    if ($data['email'] === null) {
        $data['email'] = $data['phone'] . '@intaleqapp.com';
    }
    $driverID = $data['id'];

    /* ========== 3) تشفير الحقول الحساسة ========== */
    $toEncryptDriver = [
        "phone","email","first_name","last_name","name_arabic","gender",
        "national_number","address","site","fullNameMaritial"
    ];
    foreach ($toEncryptDriver as $f) {
        if (!empty($data[$f])) {
            $data[$f] = $encryptionHelper->encryptData($data[$f]);
        }
    }
    // حساسات السيارة
    $car['vin']       = $encryptionHelper->encryptData($car['vin']);
    $car['car_plate'] = $encryptionHelper->encryptData($car['car_plate']);
    $car['owner']     = $encryptionHelper->encryptData($car['owner']);

    /* ========== 4) هَش كلمة المرور ========== */
    $pwdHashed = password_hash(filterRequest('password'), PASSWORD_DEFAULT);

    /* ========== 5) بدء معاملة ========== */
    $con->beginTransaction();

    /* ========== 6) فحص تكرار هاتف/ايميل (المشفّرين) ========== */
    $dup = $con->prepare("SELECT id FROM driver WHERE phone = :p OR email = :e");
    $dup->execute([':p' => $data['phone'], ':e' => $data['email']]);
    if ($dup->rowCount() > 0) {
        $con->rollBack();
        jsonError("Phone or email already registered.");
        exit;
    }

    /* ========== 7) إدراج السائق ========== */
    $sqlDriver = "
      INSERT INTO driver (
        id, phone, email, password, gender, license_type, national_number,
        name_arabic, issue_date, expiry_date, license_categories,
        address, licenseIssueDate, status, birthdate, site,
        first_name, last_name, accountBank, bankCode,
        employmentType, maritalStatus, fullNameMaritial, expirationDate,
        created_at, updated_at
      ) VALUES (
        :id, :phone, :email, :pwd, :gender, :license_type, :national_number,
        :name_arabic, :issue_date, :expiry_date, :license_categories,
        :address, :licenseIssueDate, :status, :birthdate, :site,
        :first_name, :last_name, :accountBank, :bankCode,
        :employmentType, :maritalStatus, :fullNameMaritial, :expirationDate,
        NOW(), NOW()
      )
    ";
    $insD = $con->prepare($sqlDriver);
    $okD = $insD->execute([
        ':id'               => $driverID,
        ':phone'            => $data['phone'],
        ':email'            => $data['email'],
        ':pwd'              => $pwdHashed,
        ':gender'           => $data['gender'],
        ':license_type'     => $data['license_type'],
        ':national_number'  => $data['national_number'],
        ':name_arabic'      => $data['name_arabic'],
        ':issue_date'       => $data['issue_date'],
        ':expiry_date'      => $data['expiry_date'],
        ':license_categories'=> !empty($data['license_categories']) ? $data['license_categories'] : 'B',
        ':address'          => $data['address'],
        ':licenseIssueDate' => $data['licenseIssueDate'],
        ':status'           => !empty($data['status']) ? $data['status'] : 'yet',
        ':birthdate'        => $data['birthdate'],
        ':site'             => $data['site'],
        ':first_name'       => $data['first_name'],
        ':last_name'        => $data['last_name'],
        ':accountBank'      => 'yet',
        ':bankCode'         => 'yet',
        ':employmentType'   => !empty($data['employmentType']) ? $data['employmentType'] : 'yet',
        ':maritalStatus'    => !empty($data['maritalStatus']) ? $data['maritalStatus'] : 'yet',
        ':fullNameMaritial' => !empty($data['fullNameMaritial']) ? $data['fullNameMaritial'] : 'yet',
        ':expirationDate'   => !empty($data['expirationDate']) ? $data['expirationDate'] : 'yet',
    ]);
    if (!$okD) { $con->rollBack(); jsonError("Failed to insert driver."); exit; }

    /* ========== 8) إدراج السيارة ========== */
    $hasCar = $con->prepare("SELECT 1 FROM CarRegistration WHERE driverID = :d LIMIT 1");
    $hasCar->execute([':d' => $driverID]);
    $isDefault = $hasCar->rowCount() === 0 ? 1 : 0;

    $sqlCar = "
      INSERT INTO CarRegistration (
        driverID, vin, car_plate, make, model, year, expiration_date,
        color, owner, color_hex, fuel, isDefault, created_at, status
      ) VALUES (
        :driverID, :vin, :car_plate, :make, :model, :year, :expiration_date,
        :color, :owner, :color_hex, :fuel, :isDefault, NOW(), 'yet'
      )
    ";
    $insC = $con->prepare($sqlCar);
    $okC = $insC->execute([
        ':driverID'        => $driverID,
        ':vin'             => $car['vin'],
        ':car_plate'       => $car['car_plate'],
        ':make'            => $car['make'],
        ':model'           => $car['model'],
        ':year'            => $car['year'],
        ':expiration_date' => $car['expiration_date'],
        ':color'           => $car['color'],
        ':owner'           => $car['owner'],
        ':color_hex'       => $car['color_hex'],
        ':fuel'            => $car['fuel'],
        ':isDefault'       => $isDefault,
    ]);
    if (!$okC) { $con->rollBack(); jsonError("Failed to insert car registration."); exit; }

    $carRegID = $con->lastInsertId();

    /* ========== 9) التحقّق من الروابط الموقّعة وحفظها ========== */

    // دالة مساعدة تتحقّق من شكل الرابط وتستخرج doc_type/ext
    $validateSignedUrl = function(string $url) use ($allowedDocTypes, $allowedExts) {
        $parts = parse_url($url);
        if (!$parts || empty($parts['scheme']) || empty($parts['host']) || empty($parts['path'])) {
            throw new Exception("Invalid URL format.");
        }
        if (!in_array($parts['host'], $ALLOWED_SIGNED_HOSTS, true)) {
            throw new Exception("URL host not allowed: {$parts['host']}");
        }
        if (stripos($parts['path'], 'secure_image.php') === false) {
            throw new Exception("URL path not allowed.");
        }
        if (empty($parts['query'])) {
            throw new Exception("URL missing query string.");
        }
        parse_str($parts['query'], $q);
        foreach (['driver_id','doc_type','ext','expires','signature'] as $k) {
            if (empty($q[$k])) throw new Exception("URL missing param: $k");
        }
        if (!in_array($q['doc_type'], $allowedDocTypes, true)) {
            throw new Exception("Invalid doc_type in URL.");
        }
        if (!in_array(strtolower($q['ext']), $allowedExts, true)) {
            throw new Exception("Invalid ext in URL.");
        }
        return [
            'doc_type' => $q['doc_type'],
            'ext'      => strtolower($q['ext']),
            // بإمكانك التحقق من driver_id = $driverID إذا تحب تربطهما
            'driver_id_in_url' => $q['driver_id'],
        ];
    };

    $docsToInsert = [];  // [['doc_type'=>..., 'link'=>..., 'image_name'=>...], ...]
    foreach ($docUrlKeys as $k) {
        $link = $docUrls[$k];
        $meta = $validateSignedUrl($link);
        // image_name ليس ضروريًا هنا (الرابط موقّع إلى بوابة قراءة)، احفظ doc_type + link فقط
        $docsToInsert[] = [
            'doc_type'   => $meta['doc_type'], // يجب أن يتطابق مع $k منطقيًا
            'link'       => $link,
            'image_name' => $meta['doc_type'] . '.' . $meta['ext'], // اسماً رمزياً فقط
        ];
    }

    // إدراج في driver_documents
    // CREATE TABLE driver_documents (
    //   id INT AUTO_INCREMENT PRIMARY KEY,
    //   driverID VARCHAR(64) NOT NULL,
    //   doc_type VARCHAR(64) NOT NULL,
    //   image_name VARCHAR(255) NULL,
    //   link VARCHAR(1024) NOT NULL,
    //   upload_date DATETIME NOT NULL,
    //   INDEX(driverID)
    // ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
    $insDoc = $con->prepare("
        INSERT INTO driver_documents (driverID, doc_type, image_name, link, upload_date)
        VALUES (:driverID, :doc_type, :image_name, :link, NOW())
    ");
    foreach ($docsToInsert as $row) {
        $insDoc->execute([
            ':driverID'   => $driverID,
            ':doc_type'   => $row['doc_type'],
            ':image_name' => $row['image_name'],
            ':link'       => $row['link'],
        ]);
    }

    /* ========== 10) إنهاء المعاملة ========== */
    $con->commit();

    printSuccess([
        'driverID'  => $driverID,
        'carRegID'  => $carRegID,
        'documents' => [
            'driver_license_front_url' => $docUrls['driver_license_front_url'],
            'driver_license_back_url'  => $docUrls['driver_license_back_url'],
            'car_license_front_url'    => $docUrls['car_license_front_url'],
            'car_license_back_url'     => $docUrls['car_license_back_url'],
        ]
    ]);

} catch (Exception $e) {
    if (isset($con) && $con->inTransaction()) { $con->rollBack(); }
    error_log("register_driver_and_car ERROR: " . $e->getMessage());
    jsonError("Server error: " . $e->getMessage());
} catch (PDOException $e) {
    if (isset($con) && $con->inTransaction()) { $con->rollBack(); }
    error_log("register_driver_and_car PDO: " . $e->getMessage());
    jsonError("Database error.");
}

File: auth/syria/driver/register_driver_and_car.php

<?php
/**
 * Endpoint: register_driver_and_car.php
 * [MODIFIED] Added vehicle_category_id and fuel_type_id support.
 * [MODIFIED] Fixed birthdate logic: Append -01-01 BEFORE encryption.
 * [MODIFIED] Added Syrian phone number formatting logic.
 */
//register_driver_and_car.php
$allowRegistration = true;
require_once __DIR__ . '/../../../connect.php';
header('Content-Type: application/json; charset=utf-8');

try {
    if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
        jsonError("Invalid method.");
        exit;
    }

    /* ================== General Settings ================== */
    $PUBLIC_BASE  = "https://intaleq.xyz/driver_docs";

    /* ================== 1) Input Fields ================== */
    $raw_first_name = null;
    $raw_last_name = null;

    $required = ["phone", "password", "first_name", "last_name"];
    $optional = [
        "id","email","gender","license_type","national_number",
        "name_arabic","issue_date","expiry_date","license_categories",
        "address","licenseIssueDate","status","birthdate","site",
        "employmentType","maritalStatus","fullNameMaritial","expirationDate"
    ];
    $carRequired = [
        "vin","car_plate","make","model","year","expiration_date",
        "color","owner","color_hex","fuel"
    ];
    // حقول اختيارية للسيارة (التصنيف والوقود الرقمي)
    // vehicle_category_id, fuel_type_id
    
    $docKeys = [
        'driver_license_front',
        'driver_license_back',
        'car_license_front',
        'car_license_back'
    ];

    // Read driver fields
    $data = [];
    foreach ($required as $f) {
        $v = filterRequest($f);
        if ($v === null || $v === '') {
            jsonError("Missing required field: $f");
            exit;
        }
        $data[$f] = $v;
        
        if ($f === 'first_name') $raw_first_name = $v;
        if ($f === 'last_name') $raw_last_name = $v;
    }
    foreach ($optional as $f) {
        $v = filterRequest($f);
        $data[$f] = ($v === null || $v === '' || $v === 'Not specified') ? null : $v;
    }

    /* ================== 🟢 START PHONE FORMATTING LOGIC 🟢 ================== */
    if (!empty($data['phone'])) {
        $phone = $data['phone'];

        // 1. إزالة المسافات والرموز
        $phone = preg_replace('/[ \-\(\)\+]/', '', $phone);
        $phone = trim($phone);

        // 2. توحيد البادئات الدولية
        if (strpos($phone, '00963') === 0) {
            $phone = substr($phone, 2); 
        } elseif (strpos($phone, '0963') === 0) { 
             $phone = substr($phone, 1); 
        }

        // 3. معالجة الحالات الخاصة بالصفر الزائد بعد الرمز الدولي
        if (strpos($phone, '96309') === 0) {
             $phone = '9639' . substr($phone, 5);
        }
        elseif (strpos($phone, '9630') === 0) {
             $phone = '9639' . substr($phone, 4);
        }

        // 4. معالجة الأرقام المحلية
        elseif (strpos($phone, '09') === 0) {
            $phone = '963' . substr($phone, 1);
        }
        elseif (strpos($phone, '9') === 0 && strlen($phone) == 9) {
            $phone = '963' . $phone;
        }
        elseif (strpos($phone, '0') === 0 && strlen($phone) == 10) {
             $phone = '963' . substr($phone, 1);
        }
        
        // 5. التأكد من وجود 9 بعد الرمز الدولي
        if (strpos($phone, '963') === 0 && strlen($phone) > 3) {
            if (strpos($phone, '9639') !== 0) {
                 $phone = '9639' . substr($phone, 3);
            }
        }

        $data['phone'] = $phone;
    }
    /* ================== 🔴 END PHONE FORMATTING LOGIC 🔴 ================== */


    // تجهيز تاريخ الميلاد قبل التشفير
    if (!empty($data['birthdate'])) {
        $data['birthdate'] = trim($data['birthdate']);
        $data['birthdate'] = $data['birthdate'] . '-01-01';
    } else {
        $data['birthdate'] = '1970-01-01';
    }

    // Read car fields
    $car = [];
    foreach ($carRequired as $f) {
        $v = filterRequest($f);
        if ($v === null || $v === '') {
            jsonError("Missing required field: $f");
            exit;
        }
        $car[$f] = $v;
    }

    // Read document links
    $docUrls = [];
    foreach ($docKeys as $k) {
        $u = filterRequest($k);
        if ($u === null || $u === '') {
            jsonError("Missing document URL: $k");
            exit;
        }
        if (!filter_var($u, FILTER_VALIDATE_URL)) {
            jsonError("Invalid document URL: $k");
            exit;
        }
        $docUrls[$k] = $u;
    }

    /* ================== 2) Generate default id/email ================== */
    if (empty($data['id'])) {
        $data['id'] = 'DRV' . date('YmdHis') . random_int(1000, 9999);
    }
    if ($data['email'] === null) {
        $data['email'] = $data['phone'] . '@intaleqapp.com';
    }

    /* ================== 3) Encrypt sensitive fields ================== */
    $toEncryptDriver = [
        "phone","email","first_name","last_name","name_arabic","gender",
        "national_number","address","site","fullNameMaritial","birthdate"
    ];
      
    foreach ($toEncryptDriver as $f) {
        if (!empty($data[$f])) {
            $data[$f] = $encryptionHelper->encryptData($data[$f]);
        }
    }

    // Encrypt car sensitive data
    $car['vin']       = $encryptionHelper->encryptData($car['vin']);
    $car['car_plate'] = $encryptionHelper->encryptData($car['car_plate']);
    $car['owner']     = $encryptionHelper->encryptData($car['owner']);

    /* ================== 4) Hash password (HMAC + password_hash) ================== */

// نقرأ الـ HMAC key من env
$pepper = getenv('SECRET_KEY_HMAC');

// نبني baseString من أكثر من بارامتر
// هنا نستخدم id + phone (بعد ما طبّقنا منطق تنسيق الهاتف)
$baseParts = [
    $data['id'],
    $data['phone'],
];

// نضيف رقم وطني أو سنة الميلاد إن توفروا (كما في الـ migration)
if (!empty($data['national_number'])) {
    $baseParts[] = $data['national_number'];
} elseif (!empty($data['birthdate'])) {
    // birthdate حالياً أصبح بصيغة YYYY-01-01
    $year = substr($data['birthdate'], 0, 4);
    if (preg_match('/^\d{4}$/', $year)) {
        $baseParts[] = $year;
    }
}

$baseString = implode('|', $baseParts);

// نشتق السر الخام باستخدام HMAC-SHA256 مع SECRET_KEY_HMAC
$rawSecret = hash_hmac('sha256', $baseString, $pepper, true);

// نخزّن فقط الهاش الناتج من password_hash في قاعدة البيانات
$pwdHashed = password_hash($rawSecret, PASSWORD_DEFAULT);

    /* ================== 5) Start transaction ================== */
    $con->beginTransaction();

    /* ================== 6) Check duplicate ================== */
    $dup = $con->prepare("SELECT id FROM driver WHERE phone = :p OR email = :e");
    $dup->execute([':p' => $data['phone'], ':e' => $data['email']]);
    if ($dup->rowCount() > 0) {
        $con->rollBack();
        jsonError("Phone or email already registered.");
        exit;
    }

    /* ================== 7) Insert Driver ================== */
    $sqlDriver = "
      INSERT INTO driver (
        id, phone, email, password, gender, license_type, national_number,
        name_arabic, issue_date, expiry_date, license_categories,
        address, licenseIssueDate, status, birthdate, site,
        first_name, last_name, accountBank, bankCode,
        employmentType, maritalStatus, fullNameMaritial, expirationDate,
        created_at, updated_at
      ) VALUES (
        :id, :phone, :email, :pwd, :gender, :license_type, :national_number,
        :name_arabic, :issue_date, :expiry_date, :license_categories,
        :address, :licenseIssueDate, :status, :birthdate, :site,
        :first_name, :last_name, :accountBank, :bankCode,
        :employmentType, :maritalStatus, :fullNameMaritial, :expirationDate,
        NOW(), NOW()
      )
    ";
    $insD = $con->prepare($sqlDriver);
    $okD = $insD->execute([
        ':id'                 => $data['id'],
        ':phone'              => $data['phone'],
        ':email'              => $data['email'],
        ':pwd'                => $pwdHashed,
        ':gender'             => !empty($data['gender']) ? $data['gender'] : 'Male',
        ':license_type'       => !empty($data['license_type']) ? $data['license_type'] : 'yet',
        ':national_number'    => $data['national_number'],
        ':name_arabic'        => $data['name_arabic'],
        ':issue_date'         => !empty($data['issue_date']) ? $data['issue_date'] : '2020-01-01',
        ':expiry_date'        => !empty($data['expiry_date']) ? $data['expiry_date'] : 'yet',
        ':license_categories' => !empty($data['license_categories']) ? $data['license_categories'] : 'B',
        ':address'            => $data['address'],
        ':licenseIssueDate'   => !empty($data['licenseIssueDate']) ? $data['licenseIssueDate'] : '2020-01-01',
        ':status'             => !empty($data['status']) ? $data['status'] : 'yet',
        ':birthdate'          => $data['birthdate'],
        ':site'               => !empty($data['site']) ? $data['site'] : 'demascus',
        ':first_name'         => $data['first_name'],
        ':last_name'          => $data['last_name'],
        ':accountBank'        => 'yet',
        ':bankCode'           => 'yet',
        ':employmentType'     => !empty($data['employmentType']) ? $data['employmentType'] : 'yet',
        ':maritalStatus'      => !empty($data['maritalStatus']) ? $data['maritalStatus'] : 'yet',
        ':fullNameMaritial'   => !empty($data['fullNameMaritial']) ? $data['fullNameMaritial'] : 'yet',
        ':expirationDate'     => !empty($data['expirationDate']) ? $data['expirationDate'] : 'yet',
    ]);
    if (!$okD) {
        $con->rollBack();
        jsonError("Failed to insert driver.");
        exit;
    }

    $driverID = $data['id'];

    /* ================== 8) Insert Vehicle ================== */
    // ✅ استقبال القيم الجديدة (التصنيف والوقود) مع تعيين افتراضي 1
    $vCatID = filterRequest("vehicle_category_id");
    $vCatID = ($vCatID !== null && $vCatID !== '') ? $vCatID : 1; // 1 = Car

    $fTypeID = filterRequest("fuel_type_id");
    $fTypeID = ($fTypeID !== null && $fTypeID !== '') ? $fTypeID : 1; // 1 = Petrol

    $hasCar = $con->prepare("SELECT 1 FROM CarRegistration WHERE driverID = :d LIMIT 1");
    $hasCar->execute([':d' => $driverID]);
    $isDefault = $hasCar->rowCount() === 0 ? 1 : 0;

    $sqlCar = "
      INSERT INTO CarRegistration (
        driverID, vin, car_plate, make, model, year, expiration_date,
        color, owner, color_hex, fuel, 
        vehicle_category_id, fuel_type_id, 
        isDefault, created_at, status
      ) VALUES (
        :driverID, :vin, :car_plate, :make, :model, :year, :expiration_date,
        :color, :owner, :color_hex, :fuel, 
        :vehicle_category_id, :fuel_type_id,
        :isDefault, NOW(), 'yet'
      )
    ";
    $insC = $con->prepare($sqlCar);
    $okC = $insC->execute([
        ':driverID'            => $driverID,
        ':vin'                 => $car['vin'],
        ':car_plate'           => $car['car_plate'],
        ':make'                => $car['make'],
        ':model'               => $car['model'],
        ':year'                => $car['year'],
        ':expiration_date'     => $car['expiration_date'],
        ':color'               => $car['color'],
        ':owner'               => $car['owner'],
        ':color_hex'           => $car['color_hex'],
        ':fuel'                => $car['fuel'], // النص القديم (للتوافق)
        ':vehicle_category_id' => $vCatID,      // ✅ العمود الجديد
        ':fuel_type_id'        => $fTypeID,     // ✅ العمود الجديد
        ':isDefault'           => $isDefault,
    ]);
    if (!$okC) {
        $con->rollBack();
        jsonError("Failed to insert car registration.");
        exit;
    }

    $carRegID = $con->lastInsertId();

    /* ================== 9) Store document links ================== */
    $insDoc = $con->prepare("
        INSERT INTO driver_documents (driverID, doc_type, image_name, link, upload_date)
        VALUES (:driverID, :doc_type, :image_name, :link, NOW())
    ");

    foreach ($docKeys as $k) {
        $url  = $docUrls[$k];
        $name = basename(parse_url($url, PHP_URL_PATH) ?? '');
        if ($name === '') { $name = $k . '_' . time() . '.jpg'; }

        $insDoc->execute([
            ':driverID'   => $driverID,
            ':doc_type'   => $k,
            ':image_name' => $name,
            ':link'       => $url,
        ]);
    }

    /* ================== 10) Commit ================== */
    $con->commit();

    /* ================== 11) Notification ================== */
    try {
        $fcmSendUrl = 'https://api.intaleq.xyz/siro/ride/firebase/send_fcm.php';
        
        $driverFullName = $raw_first_name . ' ' . $raw_last_name;
        $notificationTitle = 'تسجيل سائق جديد';
        $notificationBody = "سائق جديد ($driverFullName) سجل برقم ID: $driverID وهو بانتظار المراجعة والتفعيل.";

        $notificationPayload = json_encode([
            'target'    => 'service',
            'title'     => $notificationTitle,
            'body'      => $notificationBody,
            'isTopic'   => true,
            'category'  => 'new_driver_registration'
        ]);

        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $fcmSendUrl);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json; charset=UTF-8']);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $notificationPayload);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_TIMEOUT, 5);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
        
        curl_exec($ch);
        curl_close($ch);

    } catch (Exception $notifyEx) {
        error_log("register_driver_and_car NOTIFY ERROR: " . $notifyEx->getMessage());
    }

    printSuccess([
        'status'    => 'success',
        'driverID'  => $driverID,
        'carRegID'  => $carRegID,
        'documents' => $docUrls
    ]);

} catch (Exception $e) {
    if (isset($con) && $con instanceof PDO && $con->inTransaction()) {
        $con->rollBack();
    }
    error_log("register_driver_and_car ERROR: " . $e->getMessage());
    jsonError("Server error: " . $e->getMessage());
} catch (PDOException $e) {
    if (isset($con) && $con instanceof PDO && $con->inTransaction()) {
        $con->rollBack();
    }
    error_log("register_driver_and_car PDO: " . $e->getMessage());
    jsonError("Database error.");
}
?>

File: auth/syria/driver/drivers_pending_list.php

<?php
require_once __DIR__ . '/../../../connect.php';

try {
    $sql = "SELECT id, first_name,last_name, phone FROM driver WHERE status <> 'active' ORDER BY id DESC";
    $stmt = $con->prepare($sql);
    $stmt->execute();
    $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);

    // فك التشفير
    foreach ($rows as &$r) {
        $r['phone'] = $encryptionHelper->decryptData($r['phone']);
        $r['first_name']  = $encryptionHelper->decryptData($r['first_name']);
      	$r['last_name']  = $encryptionHelper->decryptData($r['last_name']);
    }

    jsonSuccess($rows); // يرجع كـ message: [...]
} catch (PDOException $e) {
    jsonError("Error: " . $e->getMessage());
}

File: auth/syria/driver/sendWhatsAppDriver.php

<?php
require_once __DIR__ . '/../../../connect.php';
//sendWhatsAppDriver.php
error_log("--- [send_otp_driver.php] Started ---");

/**
 * فحص البلاك ليست (خاصة بالسائقين)
 * - يشفّر الهاتف الخام ويبحث عنه في جدول blacklist_driver
 */
function is_blacklisted_driver(PDO $con, $encryptionHelper, string $phone): bool {
    $raw     = trim($phone);
    $enc_raw = $encryptionHelper->encryptData($raw);

    $sql = "SELECT 1 FROM blacklist_driver WHERE phone = :ph LIMIT 1";
    $q = $con->prepare($sql);
    $q->execute(['ph' => $enc_raw]);

    return (bool)$q->fetchColumn();
}

/* 0) استقبل الرقم وتحقق من البلاك ليست */
$receiver = filterRequest("receiver");

if (!$receiver) {
    jsonError('Phone number is required.');
    error_log("[send_otp_driver.php] Error: phone empty");
    exit();
}

if (is_blacklisted_driver($con, $encryptionHelper, $receiver)) {
    jsonError('This driver is blacklisted and cannot receive OTP.');
    error_log("[send_otp_driver.php] BLOCKED (blacklisted): $receiver");
    exit();
}

/* 1) توليد الـ OTP */
$otp = rand(10000, 99999);
$messageBody = "Your verification code for Siro is: " . $otp;

/* 🟢 2) تخطي الإرسال الفعلي */
error_log("[send_otp_driver.php] Skipping actual WhatsApp send. OTP for $receiver: $otp");

/* 3) حفظ الـ OTP في قاعدة البيانات */
$receiver_enc = $encryptionHelper->encryptData($receiver);
$otp_enc      = $encryptionHelper->encryptData($otp);

$exp = date('Y-m-d H:i:s', strtotime('+5 minutes'));
$now = date('Y-m-d H:i:s');

try {
    // حذف أي رموز سابقة لنفس الرقم
    $con->prepare("DELETE FROM phone_verification WHERE phone_number = ?")
        ->execute([$receiver_enc]);

    $stmt = $con->prepare("
        INSERT INTO phone_verification
            (phone_number, token_code, expiration_time, is_verified, created_at)
        VALUES (?, ?, ?, 0, ?)
    ");
    $stmt->execute([$receiver_enc, $otp_enc, $exp, $now]);

    jsonSuccess(null, 'OTP generated and saved successfully (no message sent)');
    error_log("[send_otp_driver.php] OTP saved for driver $receiver");

} catch (PDOException $e) {
    error_log("[send_otp_driver.php] DB error: ".$e->getMessage());
    jsonError('OTP generated but failed to save to database');
}
?>

File: auth/sms_new_backend/sendOtpPassenger.php

<?php

require_once __DIR__ . '/../../connect.php';


$text='444';

$encryptedText = $encryptionHelper->encryptData($text);

$username = getenv('SMS_USERNAME');
$password = getenv('SMS_PASSWORD_EGYPT');
$sender   = getenv('SMS_SENDER');

$language = filterRequest("language");
$receiver = filterRequest("receiver");

$otp = rand(10000, 99999);
$message0 = "Tripz app code is " . $otp;

$apiUrl = 'https://sms.kazumi.me/api/sms/send-sms';

$payload = [
    'username' => $username,
    'password' => $password,
    'language' => $language,
    'sender'   => $sender,
    'receiver' => $receiver,
    'message'  => $message0
];

error_log("Sending SMS to $receiver with OTP: $otp");

$response = callAPI("POST", $apiUrl, json_encode($payload));

error_log("API Response: " . print_r($response, true));

// التحقق من رسالة الاستجابة
if ($response && isset($response->message) && $response->message == "Success") {
    $expiration_time = date('Y-m-d H:i:s', strtotime('+5 minutes'));
    $created_at = date('Y-m-d H:i:s');

    error_log("Saving to DB: phone=$receiver, token=$otp, expires=$expiration_time");

    try {
        $receiver1=$encryptionHelper->encryptData($receiver);
        $otp1=$encryptionHelper->encryptData($otp);
        
        $stmt = $con->prepare("
            INSERT INTO phone_verification_passenger 
            (phone_number, token, expiration_time, verified, created_at) 
            VALUES (?, ?, ?, 0, ?)
        ");
        $success = $stmt->execute([$receiver1, $otp1, $expiration_time, $created_at]);

        if ($success) {
            error_log("OTP saved successfully to DB.");
            jsonSuccess(null, 'OTP sent and saved successfully');
        } else {
            error_log("SQL execution failed.");
            jsonError('OTP sent but not saved to database');
        }

    } catch (PDOException $e) {
        error_log("Database Error: " . $e->getMessage());
        jsonError('Database error');
    }

} else {
    error_log("OTP not sent. API response did not indicate success. Response: " . print_r($response, true));
    jsonError('OTP not sent');
}

// دالة التعامل مع API
function callAPI($method, $url, $data)
{
    $curl = curl_init();

    curl_setopt_array($curl, [
        CURLOPT_URL => $url,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_CUSTOMREQUEST => $method,
        CURLOPT_POSTFIELDS => $data,
        CURLOPT_HTTPHEADER => ["Content-Type: application/json"]
    ]);

    $response = curl_exec($curl);
    
    if (curl_errno($curl)) {
        error_log("cURL Error: " . curl_error($curl));
    }

    curl_close($curl);

    return json_decode($response);
}

?>

File: auth/sms_new_backend/rasel_whatsapp.php

<?php

// تضمين ملف الاتصال بقاعدة البيانات والدوال المساعدة
require_once __DIR__ . '/../../connect.php'; 
// include "functions.php"; // افترض أن دالة filterRequest موجودة هنا


// --- بداية التعديل: استخدام واجهة RaseelPlus API ---

// توليد رمز تحقق عشوائي مكون من 5 أرقام
$otp = rand(10000, 99999);

// استقبال رقم الهاتف من الطلب
// تأكد من أن دالة filterRequest تقوم بتنقية المدخلات بشكل آمن
$receiver = filterRequest("receiver"); 

// رسالة الـ OTP. يمكنك تخصيصها حسب الحاجة
// تذكر أن التطبيق اسمه Tripz-egypt.com
$messageBody = "Your verification code for Tripz is: " . $otp;

// عنوان API الجديد
$apiUrl = 'https://raseelplus.com/api/send';

// بيانات الطلب (Payload) الجديدة لتتوافق مع RaseelPlus
$payload = [
    "number"      => $receiver, // رقم المستلم
    "type"        => "text",
    "message"     => $messageBody,
    "instance_id" => "6863C59A7AFBD", // المعرف المأخوذ من مثال cURL
    "access_token"=> "68617b9b8fe53"  // مفتاح الوصول المأخوذ من مثال cURL
];

error_log("Sending OTP to $receiver via RaseelPlus. Message: $messageBody");

// استدعاء الـ API
$response = callAPI("POST", $apiUrl, json_encode($payload));

error_log("RaseelPlus API Response: " . print_r($response, true));

// --- نهاية التعديل ---


// التحقق من الاستجابة من الـ API
// ملاحظة: قد تحتاج إلى تعديل هذا الشرط بناءً على شكل الاستجابة الفعلي من RaseelPlus
// نفترض هنا أن الاستجابة الناجحة تحتوي على "status":"success" أو شيء مشابه
if ($response && !isset($response->error) && (isset($response->status) && $response->status == 'success' || isset($response->message))) {
    
    // تحديد وقت انتهاء صلاحية الرمز (بعد 5 دقائق)
    $expiration_time = date('Y-m-d H:i:s', strtotime('+5 minutes'));
    $created_at = date('Y-m-d H:i:s');

    error_log("API call successful. Saving to DB: phone=$receiver, token=$otp, expires=$expiration_time");

    try {
        // تشفير البيانات قبل حفظها (ممارسة أمنية جيدة)
        // $receiver_encrypted = $encryptionHelper->encryptData($receiver);
        // $otp_encrypted = $encryptionHelper->encryptData($otp);
        
        // استخدام البيانات غير المشفرة مؤقتاً إذا لم تكن تستخدم التشفير حالياً
        $receiver_to_db = $receiver;
        $otp_to_db = $otp;

        $stmt = $con->prepare("
            INSERT INTO phone_verification_passenger 
            (phone_number, token, expiration_time, verified, created_at) 
            VALUES (?, ?, ?, 0, ?)
        ");
        $success = $stmt->execute([$receiver_to_db, $otp_to_db, $expiration_time, $created_at]);

        if ($success) {
            error_log("OTP saved successfully to DB.");
            // jsonSuccess() هي دالة مخصصة لديك لطباعة استجابة نجاح
            jsonSuccess(null, 'OTP sent and saved successfully');
        } else {
            error_log("SQL execution failed.");
            // jsonError() هي دالة مخصصة لديك لطباعة استجابة فشل
            jsonError('OTP sent but failed to save to database');
        }

    } catch (PDOException $e) {
        error_log("Database Error: " . $e->getMessage());
        jsonError('Database error occurred');
    }

} else {
    // فشل إرسال الـ OTP
    $errorMessage = isset($response->message) ? $response->message : "Unknown error";
    error_log("Failed to send OTP. API response: " . $errorMessage);
    jsonError('Failed to send OTP: ' . $errorMessage);
}

/**
 * دالة لإجراء استدعاءات API باستخدام cURL
 * @param string $method نوع الطلب (e.g., "POST", "GET")
 * @param string $url عنوان URL للـ API
 * @param mixed $data البيانات المراد إرسالها
 * @return mixed الاستجابة من الـ API بعد فك تشفير JSON
 */
function callAPI($method, $url, $data)
{
    $curl = curl_init();

    curl_setopt_array($curl, [
        CURLOPT_URL => $url,
        CURLOPT_RETURNTRANSFER => true, // إرجاع الاستجابة كنص بدلاً من طباعتها
        CURLOPT_ENCODING => "",
        CURLOPT_MAXREDIRS => 10,
        CURLOPT_TIMEOUT => 30, // مهلة زمنية للطلب
        CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
        CURLOPT_CUSTOMREQUEST => $method,
        CURLOPT_POSTFIELDS => $data,
        CURLOPT_HTTPHEADER => [
            "Content-Type: application/json",
            "Accept: application/json"
        ],
    ]);

    $response = curl_exec($curl);
    $err = curl_error($curl);

    curl_close($curl);

    if ($err) {
        error_log("cURL Error #: " . $err);
        return null; // إرجاع null في حالة وجود خطأ في cURL
    } else {
        return json_decode($response); // فك تشفير استجابة JSON
    }
}

// مثال على دالة طباعة النجاح (ضعها في ملف functions.php)


?>

File: auth/captin/updateDriverSecure.php

<?php
require_once __DIR__ . '/../../connect.php';

$id = filterRequest("id");

// تحقق من وجود بيانات
if (empty($_POST)) {
    jsonError("No passenger data provided for update.");
    exit;
}

// الحقول الحساسة التي يجب تشفيرها
$fieldsToEncrypt = ["phone", "email", "gender", "birthdate", "site", "first_name", "last_name", "sosPhone"];

// بناء الحقول والمعاملات
$columnValues = [];
$params = [];

foreach ($fieldsToEncrypt as $field) {
    if (isset($_POST[$field])) {
        $value = filterRequest($field);
        $encryptedValue = $encryptionHelper->encryptData($value);
        $columnValues[] = "`$field` = ?";
        $params[] = $encryptedValue;
    }
}

// تحقق من أن هناك حقول للتحديث
if (empty($columnValues)) {
    jsonError("No valid encrypted passenger data provided for update.");
    exit;
}

// تركيب جملة SQL
$setClause = implode(", ", $columnValues);
$params[] = $id;

$sql = "UPDATE `passengers` SET $setClause WHERE `id` = ?";

try {
    $stmt = $con->prepare($sql);

    foreach ($params as $index => $value) {
        $stmt->bindValue($index + 1, $value);
    }

    if ($stmt->execute()) {
        jsonSuccess(null, "Passenger data updated successfully with encryption");
    } else {
        jsonError("Failed to update passenger data");
    }

} catch (PDOException $e) {
    jsonError("Database error: " . $e->getMessage());
}
?>

File: auth/captin/sendOtpMessageDriver.php

<?php
require_once __DIR__ . '/../../connect.php';

// استرجاع البيانات من الطلب
$phone_number     = filterRequest("phone_number");
$driverId         = filterRequest("driverId");
$email            = filterRequest("email");
$expiration_time  = filterRequest("expiration_time"); // اختياري للمستقبل

// تحقق من وجود رقم الهاتف
if (empty($phone_number)) {
    jsonError("Phone number is required");
    exit;
}

// توليد رمز تحقق مكوّن من 5 أرقام
$token_code = str_pad(random_int(0, 99999), 5, '0', STR_PAD_LEFT);

// تشفير البيانات الحساسة
$encryptedPhone = $encryptionHelper->encryptData($phone_number);
$encryptedToken = $encryptionHelper->encryptData($token_code);
$encryptedEmail = $encryptionHelper->encryptData($email); // اختياري إذا بتحب تشفيره

// التحقق من وجود الرقم مسبقاً في قاعدة البيانات
$sqlCheck = "SELECT * FROM `phone_verification` WHERE `phone_number` = :phone";
$stmtCheck = $con->prepare($sqlCheck);
$stmtCheck->bindParam(":phone", $encryptedPhone);
$stmtCheck->execute();

$success = false;

// إذا كان الرقم موجود → تحديث
if ($stmtCheck->rowCount() > 0) {
    $sqlUpdate = "UPDATE `phone_verification` 
                  SET `token_code` = :token, 
                      `expiration_time` = DATE_ADD(NOW(), INTERVAL 5 MINUTE) 
                  WHERE `phone_number` = :phone";
    $stmt = $con->prepare($sqlUpdate);
    $stmt->bindParam(":token", $encryptedToken);
    $stmt->bindParam(":phone", $encryptedPhone);
    $stmt->execute();
    $success = $stmt->rowCount() > 0;
} else {
    // إذا الرقم غير موجود → إدخال جديد
    $sqlInsert = "INSERT INTO `phone_verification` 
                  (`phone_number`, `driverId`, `email`, `token_code`, `expiration_time`, `is_verified`, `created_at`) 
                  VALUES 
                  (:phone, :driverId, :email, :token, DATE_ADD(NOW(), INTERVAL 5 MINUTE), 0, NOW())";
    $stmt = $con->prepare($sqlInsert);
    $stmt->bindParam(":phone", $encryptedPhone);
    $stmt->bindParam(":driverId", $driverId);
    $stmt->bindParam(":email", $encryptedEmail);
    $stmt->bindParam(":token", $encryptedToken);
    $stmt->execute();
    $success = $stmt->rowCount() > 0;
}

// إذا تم الحفظ بنجاح → أرسل الرمز عبر SMS
if ($success) {
    // تحميل بيانات الاتصال بالـ SMS API من المتغيرات البيئية
    $username = getenv('SMS_USERNAME');
    $password = getenv('SMS_PASSWORD_EGYPT');
    $sender   = getenv('SMS_SENDER');

    if (!$username || !$password || !$sender) {
        jsonError("SMS credentials are missing");
        exit;
    }

    $message  = "Tripz app code is " . $token_code;
    $receiver = $phone_number;

    $apiUrl = 'https://sms.kazumi.me/api/sms/send-sms';
    $payload = [
        'username' => $username,
        'password' => $password,
        'language' => 'e',
        'sender'   => $sender,
        'receiver' => $receiver,
        'message'  => $message
    ];

    $jsonPayload = json_encode($payload);
    $smsResponse = callAPI("POST", $apiUrl, $jsonPayload);

    if ($smsResponse) {
        jsonSuccess(null, "Verification code sent and saved successfully");
    } else {
        jsonError("Code saved, but SMS sending failed");
    }
} else {
    jsonError("Failed to save verification data");
}

// دالة الاتصال بالـ API
function callAPI($method, $url, $data) {
    $curl = curl_init();
    curl_setopt_array($curl, [
        CURLOPT_URL => $url,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_CUSTOMREQUEST => $method,
        CURLOPT_POSTFIELDS => $data,
        CURLOPT_HTTPHEADER => [
            "Content-Type: application/json",
            "Accept: application/json"
        ],
        CURLOPT_TIMEOUT => 30,
        CURLOPT_CONNECTTIMEOUT => 10
    ]);

    $api_raw_response = curl_exec($curl);

    if (curl_errno($curl)) {
        error_log("cURL Error [".curl_errno($curl)."]: " . curl_error($curl));
        curl_close($curl);
        return false;
    }

    curl_close($curl);
    $decoded_response = json_decode($api_raw_response, true);

    if (json_last_error() !== JSON_ERROR_NONE) {
        error_log("Invalid JSON response from SMS API.");
        return false;
    }

    error_log("SMS API response: " . print_r($decoded_response, true));
    return $decoded_response;
}
?>

File: auth/captin/login.php

<?php

require_once __DIR__ . '/../../connect.php';

$email = filterRequest('email');
$phone = filterRequest('phone');
$password = filterRequest('password');

// تشفير الحقول المطلوبة قبل الاستعلام
$email = $encryptionHelper->encryptData($email);
$phone = $encryptionHelper->encryptData($phone);

$sql = "SELECT
    driver.id,
    driver.phone,
    driver.email,
    driver.password,
    driver.gender,
    driver.birthdate,
    driver.site,
    driver.first_name,
    driver.last_name,
    driver.education,
    driver.employmentType,
    driver.maritalStatus,
    driver.created_at,
    driver.updated_at,
    email_verifications.verified
FROM
    driver
LEFT JOIN email_verifications ON email_verifications.email = driver.email
WHERE
    driver.phone = :phone AND driver.email = :email";

$stmt = $con->prepare($sql);
$stmt->bindParam(':email', $email);
$stmt->bindParam(':phone', $phone);
$stmt->execute();
$data = $stmt->fetchAll(PDO::FETCH_ASSOC);
$count = $stmt->rowCount();

if ($count > 0) {
    $stored_password = $data[0]['password'];
    if (password_verify($password, $stored_password)) {

        // فك التشفير للحقول الحساسة
        $data[0]['phone']           = $encryptionHelper->decryptData($data[0]['phone']);
        $data[0]['email']           = $encryptionHelper->decryptData($data[0]['email']);
        $data[0]['gender']          = $encryptionHelper->decryptData($data[0]['gender']);
        $data[0]['birthdate']       = $encryptionHelper->decryptData($data[0]['birthdate']);
        $data[0]['site']            = $encryptionHelper->decryptData($data[0]['site']);
        $data[0]['first_name']      = $encryptionHelper->decryptData($data[0]['first_name']);
        $data[0]['last_name']       = $encryptionHelper->decryptData($data[0]['last_name']);
        $data[0]['education']       = $encryptionHelper->decryptData($data[0]['education']);
        $data[0]['employmentType']  = $encryptionHelper->decryptData($data[0]['employmentType']);
        $data[0]['maritalStatus']   = $encryptionHelper->decryptData($data[0]['maritalStatus']);

        unset($data[0]['password']); // لا نرجّع الباسورد
        jsonSuccess($data);
    } else {
        jsonError("Incorrect password.");
    }
} else {
    jsonError("User does not exist.");
}
?>

File: auth/captin/updateAccountBank.php

<?php
require_once __DIR__ . '/../../connect.php';

$id = filterRequest("id");
$columnValues = [];

// الحقول التي تحتاج تشفير
$fieldsToEncrypt = [
  "phone", "email", "gender", "birthdate", "site",
  "first_name", "last_name", "accountBank", "education",
  "employmentType", "maritalStatus"
];

// الحقول غير المشفرة
$plainFields = ["status", "bankCode", "updated_at"];

foreach ($_POST as $key => $value) {
    $filtered = filterRequest($key);

    if ($key === "password") {
        // هاش لكلمة المرور
        $hashed = password_hash($filtered, PASSWORD_DEFAULT);
        $columnValues[] = "`password` = '$hashed'";
    } elseif (in_array($key, $fieldsToEncrypt)) {
        $encrypted = $encryptionHelper->encryptData($filtered);
        $columnValues[] = "`$key` = '$encrypted'";
    } elseif (in_array($key, $plainFields)) {
        $columnValues[] = "`$key` = '$filtered'";
    }
}

// بناء جملة التحديث
$setClause = implode(", ", $columnValues);
$sql = "UPDATE `driver` SET $setClause WHERE `id` = '$id'";

$stmt = $con->prepare($sql);
$stmt->execute();

if ($stmt->rowCount() > 0) {
    jsonSuccess(null, "Driver data updated successfully");
} else {
    jsonError("Failed to update driver data");
}
?>

File: auth/captin/verifyOtpDriver.php

<?php
require_once __DIR__ . '/../../connect.php';

$phone_number = filterRequest("phone_number");
$token_code = filterRequest("token_code");

$encryptedPhone = $encryptionHelper->encryptData($phone_number);
$encryptedToken = $encryptionHelper->encryptData($token_code);

// Check if the phone number and token code match
$sql = "SELECT
    `id`,
    `phone_number`,
    `token_code`,
    `expiration_time`,
    `is_verified`,
    `created_at`
FROM
    `phone_verification`
WHERE
    `phone_number` = :phone_number AND `token_code` = :token_code -- AND `expiration_time` > NOW()";
$stmt = $con->prepare($sql);
$stmt->bindParam(':phone_number', $encryptedPhone, PDO::PARAM_STR);
$stmt->bindParam(':token_code', $encryptedToken, PDO::PARAM_STR);
$stmt->execute();
$result = $stmt->fetch();

if ($result) {
    // $id = $result["id"];
    $sql = "UPDATE `phone_verification` SET `is_verified` = 1 WHERE `phone_number` = :phone_number";
    $stmt = $con->prepare($sql);
    $stmt->bindParam(':phone_number', $phone_number, PDO::PARAM_STR);
    $stmt->execute();

    jsonSuccess($message = "Your phone number has been verified.");
} else {
    jsonError($message = "Your phone number could not be verified. Please try again.");
}
?>

File: auth/captin/loginUsingCredentialsWithoutGoogle.php

<?php

require_once __DIR__ . '/../../connect.php';

$email = filterRequest('email');
$password = filterRequest('password');

// تشفير الإيميل لاستخدامه في الاستعلام
$encryptedEmail = $encryptionHelper->encryptData($email);

// SQL لاسترجاع المستخدم بناءً على البريد الإلكتروني المشفر
$sql = "SELECT
    driver.id,
    driver.phone,
    driver.email,
    driver.gender,
    driver.birthdate,
    driver.site,
    driver.first_name,
    driver.last_name,
    driver.bankCode,
    driver.accountBank,
    driver.education,
    driver.employmentType,
    driver.maritalStatus,
    driver.created_at,
    driver.updated_at,
    driver.password,
    phone_verification.is_verified,
    CarRegistration.make,
    CarRegistration.model,
    CarRegistration.year
FROM
    driver
LEFT JOIN phone_verification ON phone_verification.phone_number = driver.phone
LEFT JOIN CarRegistration ON CarRegistration.driverID = driver.id
WHERE
    driver.email = :email AND phone_verification.is_verified = '1'
LIMIT 1";

$stmt = $con->prepare($sql);
$stmt->bindParam(':email', $encryptedEmail);
$stmt->execute();

$data = $stmt->fetch(PDO::FETCH_ASSOC);

if ($data) {
    if (password_verify($password, $data['password'])) {
        unset($data['password']);

        // فك تشفير الحقول الحساسة
        $data['phone'] = $encryptionHelper->decryptData($data['phone']);
        $data['email'] = $encryptionHelper->decryptData($data['email']);
        $data['gender'] = $encryptionHelper->decryptData($data['gender']);
        $data['birthdate'] = $encryptionHelper->decryptData($data['birthdate']);
        $data['site'] = $encryptionHelper->decryptData($data['site']);
        $data['first_name'] = $encryptionHelper->decryptData($data['first_name']);
        $data['last_name'] = $encryptionHelper->decryptData($data['last_name']);
        $data['education'] = $encryptionHelper->decryptData($data['education']);
        $data['employmentType'] = $encryptionHelper->decryptData($data['employmentType']);
        $data['maritalStatus'] = $encryptionHelper->decryptData($data['maritalStatus']);

        echo json_encode([
            "status" => "success",
            "data" => $data
        ]);
    } else {
        jsonError("Incorrect password.");
    }
} else {
    jsonError("User does not exist or phone number not verified.");
}

$stmt = null;
$con = null;
exit();
?>

File: auth/captin/updateDriverClaim.php

<?php
require_once __DIR__ . '/../../connect.php';

// Sanitize and validate input
$driverId = filterRequest("driverId");

// SQL query to check if a gift already exists for the driver (unclaimed)
$checkSql = "SELECT COUNT(*) FROM driver_gifts WHERE driver_id = :driverId -- AND is_claimed = 0";

try {
    $checkStmt = $con->prepare($checkSql);
    $checkStmt->bindParam(':driverId', $driverId, PDO::PARAM_INT);
    $checkStmt->execute();
    $giftExists = $checkStmt->fetchColumn();

    if ($giftExists > 0) {
        jsonError("Gift already exists for this driver");
        exit;
    }

    // Insert a new claimed gift
    $sql = "INSERT INTO driver_gifts (driver_id, gift_description, is_claimed) 
            VALUES (:driverId, 'new account 300 le', 1)";
    $stmt = $con->prepare($sql);
    $stmt->bindParam(':driverId', $driverId, PDO::PARAM_INT);
    $stmt->execute();

    if ($stmt->rowCount() > 0) {
        jsonSuccess(null, "Gift data saved successfully");
    } else {
        jsonError("Failed to save gift data");
    }

} catch (PDOException $e) {
    error_log("Database Error: " . $e->getMessage());
    jsonError("An error occurred while saving the data");
}
?>

File: auth/captin/register.php

<?php
$allowRegistration = true;
require_once __DIR__ . '/../../connect.php';



try {
    /* =========== 1) الحقول الواردة من الـ POST =========== */
    $required = ["phone", "password", "first_name", "last_name"];
    $optional = [
        "id", "email", "gender", "license_type", "national_number",
        "name_arabic", "issue_date", "expiry_date", "license_categories",
        "address", "licenseIssueDate", "status", "birthdate", "site",
        "accountBank", "bankCode", "employmentType",
        "maritalStatus", "fullNameMaritial", "expirationDate"
    ];

    $data = [];

    // التحقق من الحقول المطلوبة
    foreach ($required as $f) {
        $val = filterRequest($f);
        if ($val === null || $val === '') {
            jsonError("Missing required field: $f");
            exit;
        }
        $data[$f] = $val;
    }

    // قراءة الحقول الاختيارية
    foreach ($optional as $f) {
        $v = filterRequest($f);
        $data[$f] = ($v === null || $v === '' || $v === 'Not specified') ? null : $v;
    }

  if ($data['email'] === null) {
    // phone هنا ما زال خامًا (غير مُشفَّر)
    $data['email'] = $data['phone'] . '@intaleqapp.com';
		}
    /* =========== 2) تشفير الحقول الحسّاسة =========== */
    $encryptThese = ["phone", "email", "first_name", "last_name", "name_arabic","gender", "national_number",
                     "address", "site", "fullNameMaritial"];

    foreach ($encryptThese as $f) {
        if ($data[$f] !== null) {
            $data[$f] = $encryptionHelper->encryptData($data[$f]);
        }
    }

    /* =========== 3) توليد driver ID (id) إذا لم يُرسَل =========== */
    

    /* =========== 4) هَش كلمة المرور =========== */
    $data['password_hashed'] = password_hash($data['password'], PASSWORD_DEFAULT);

    /* =========== 5) منع التكرار في الهاتف / الإيميل =========== */
    $dup = $con->prepare(
        "SELECT id FROM driver WHERE phone = :phone OR email = :email"
    );
    $dup->execute([
        ':phone' => $data['phone'],
        ':email' => $data['email']
    ]);
    if ($dup->rowCount() > 0) {
        jsonError("Phone or email already registered.");
        exit;
    }

    /* =========== 6) إدخال السجل الجديد =========== */
    $sql = "
      INSERT INTO driver (
        id, phone, email, password, gender, license_type, national_number,
        name_arabic, issue_date, expiry_date, license_categories,
        address, licenseIssueDate, status, birthdate, site,
        first_name, last_name, accountBank, bankCode,
        employmentType, maritalStatus, fullNameMaritial, expirationDate,
        created_at, updated_at
      ) VALUES (
        :id, :phone, :email, :pwd, :gender, :license_type, :national_number,
        :name_arabic, :issue_date, :expiry_date, :license_categories,
        :address, :licenseIssueDate, :status, :birthdate, :site,
        :first_name, :last_name, :accountBank, :bankCode,
        :employmentType, :maritalStatus, :fullNameMaritial, :expirationDate,
        NOW(), NOW()
      )
    ";

    $ins = $con->prepare($sql);

    // خريطة الربط (تطابق تمامًا أسماء الـ placeholders في الـ SQL أعلاه)
    $bind = [
        'id'               => $data['id'],
        'phone'            => $data['phone'],
        'email'            => $data['email'],
        'pwd'              => $data['password_hashed'],
        'gender'           => $data['gender'],
        'license_type'     => $data['license_type'],
        'national_number'  => $data['national_number'],
        'name_arabic'      => $data['name_arabic'],
        'issue_date'       => $data['issue_date'],
        'expiry_date'      => $data['expiry_date'],
        'license_categories'=> $data['license_categories']?? 'B',
        'address'          => $data['address'],
        'licenseIssueDate' => $data['licenseIssueDate'],
        'status'           => $data['status'] ?? 'yet',
        'birthdate'        => $data['birthdate'],
        'site'             => $data['site'],
        'first_name'       => $data['first_name'],
        'last_name'        => $data['last_name'],
        'accountBank'      => 'yet',
        'bankCode'         => 'yet',
        'employmentType'   => $data['employmentType']?? 'yet',
        'maritalStatus'    => $data['maritalStatus']?? 'yet',
        'fullNameMaritial' => $data['fullNameMaritial']?? 'yet',
        'expirationDate'   => $data['expirationDate']?? 'yet',
    ];

    foreach ($bind as $key => $value) {
        $ins->bindValue(":$key", $value);
    }

    if ($ins->execute()) {
        jsonSuccess($data['id']);   // ترجع driver ID
    } else {
        jsonError("Failed to insert driver record.");
    }

} catch (PDOException $e) {
    error_log("DriverInsert PDO: " . $e->getMessage());
    jsonError("Database error.");
}
?>

File: auth/captin/loginFromGoogle.php

<?php
// loginFromGoogle.php
require_once __DIR__ . '/../../connect.php';

try {
    /* ────────────────────────────────
       1) قراءة القيم الأولية
    ───────────────────────────────── */
   // $emailRaw = filterRequest('email');   // البريد القادم من التطبيق (غير مشفَّر)
    $driverID = filterRequest('id');      // DriverID المُرسل

   // error_log("[Debug] Email (raw): $emailRaw");
    error_log("[Debug] DriverID: $driverID");

    /* ────────────────────────────────
       2) تشفير الإيميل
    ───────────────────────────────── */
   // $emailEnc = $encryptionHelper->encryptData($emailRaw);
   // error_log("[Debug] Email (encrypted): $emailEnc");

    /* ────────────────────────────────
       3) إعداد الاستعلام الموحَّد
    ───────────────────────────────── */
    $sql = "
      SELECT
        driver.id, driver.phone, driver.email, driver.gender, driver.birthdate,
        driver.site, driver.first_name, driver.last_name, driver.bankCode,
        driver.accountBank, driver.employmentType,driver.status, driver.maritalStatus,
        driver.created_at, driver.updated_at,
        phone_verification.is_verified,
        CarRegistration.make, CarRegistration.model, CarRegistration.year,
        df.is_claimed, inv.isInstall, inv.isGiftToken
      FROM driver
      LEFT JOIN phone_verification ON phone_verification.phone_number = driver.phone
      LEFT JOIN driver_gifts        df  ON df.driver_id  = driver.id
      LEFT JOIN CarRegistration         ON CarRegistration.driverID = driver.id
      LEFT JOIN invites             inv ON inv.driverId   = driver.id
      WHERE 
      
        driver.id    = :id
      --  AND phone_verification.is_verified = '1'
      LIMIT 1
    ";

  // error_log("[Debug] queryString:\n$sql");

    $stmt = $con->prepare($sql);

    // باراميترات الربط
    $params = [
        //':email' => $emailEnc,
        ':id'    => $driverID,
    ];
    foreach ($params as $k => $v) {
        $stmt->bindValue($k, $v);
    }

    /* ───────── dumpParams (اختياري) ───────── */
    ob_start();
    $stmt->debugDumpParams();
    error_log("[Debug] dumpParams:\n" . ob_get_clean());

    /* ────────────────────────────────
       4) تنفيذ الاستعلام
    ───────────────────────────────── */
    $stmt->execute();
    error_log("[Debug] stmt->rowCount(): " . $stmt->rowCount());

    $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
  // error_log("[Debug] Raw fetched JSON: " . json_encode($rows, JSON_UNESCAPED_UNICODE));

    if (!$rows) {
        jsonError("User does not exist or phone not verified.");
        exit;
    }

    /* ────────────────────────────────
       5) فك التشفير للحقول الحسّاسة
    ───────────────────────────────── */
    $data = &$rows[0];   // مرجع لتوفير الذاكرة

    $decryptIfNotNull = function($field) use (&$data, $encryptionHelper) {
        if (isset($data[$field]) && $data[$field] !== null) {
            $data[$field] = $encryptionHelper->decryptData($data[$field]);
        }
    };

    foreach ([
        'phone', 'email', 'gender', 'birthdate', 'site',
        'first_name', 'last_name'
    ] as $field) {
        $decryptIfNotNull($field);
    }
error_log("[Debug] Raw fetched JSON: " . json_encode($rows, JSON_UNESCAPED_UNICODE));

    echo json_encode([
        "status" => "success",
        "count"  => 1,
        "data"   => $rows        // نتيجة واحدة فقط
    ], JSON_UNESCAPED_UNICODE);
} catch (PDOException $e) {
    error_log("[PDO ERROR] " . $e->getMessage());
    jsonError("Database error: ".$e->getCode());
} catch (Exception $e) {
    error_log("[GENERAL ERROR] " . $e->getMessage());
    jsonError("Error occurred.");
} finally {
    $stmt = null;
    $con  = null;
}
?>

File: auth/captin/updateShamCashDriver.php

<?php
require_once __DIR__ . '/../../connect.php';

// استقبال معرف السائق
$id = filterRequest("id");

// استقبال بيانات شام كاش من التطبيق
$accountBank = filterRequest("accountBank"); // الاسم (مثال: siro)
$bankCode    = filterRequest("bankCode");    // الكود الطويل (مثال: 80f23afe...)

// التحقق من وصول البيانات المطلوبة
if ($id && $accountBank && $bankCode) {

    try {
        // 1. تشفير اسم الحساب (حسب القواعد في السكربت السابق accountBank مشفر)
        $encryptedAccountBank = $encryptionHelper->encryptData($accountBank);

        // 2. كود المحفظة يبقى كما هو (حسب القواعد bankCode غير مشفر)
        $plainBankCode = $encryptionHelper->encryptData($bankCode); 

        // 3. جملة التحديث
        $stmt = $con->prepare("UPDATE `driver` SET `accountBank` = ?, `bankCode` = ? WHERE `id` = ?");
        
        $stmt->execute(array($encryptedAccountBank, $plainBankCode, $id));

        // التحقق من نجاح العملية
        // rowCount > 0 يعني تم التحديث، أحياناً يعطي 0 إذا كانت البيانات هي نفسها لم تتغير
        // لذا نرسل نجاح في كلتا الحالتين طالما لم يحدث Error
        jsonSuccess(null, "ShamCash info updated successfully");

    } catch (PDOException $e) {
        // في حال وجود خطأ في قاعدة البيانات
        jsonError("Database Error: " . $e->getMessage());
    }

} else {
    jsonError("Missing required fields: id, accountBank, or bankCode");
}
?>

File: auth/captin/forgetPassword.php


File: auth/captin/removeAccount.php

<?php
require_once __DIR__ . '/../../connect.php';

$id = filterRequest("id");

$sql = "DELETE FROM `passengers` WHERE `id` = :id";
$stmt = $con->prepare($sql);
$stmt->bindParam(':id', $id, PDO::PARAM_INT);
$stmt->execute();

if ($stmt->rowCount() > 0) {
    jsonSuccess(null, "Passenger deleted successfully.");
} else {
    jsonError("Failed to delete passenger.");
}
?>

File: auth/captin/addCriminalDocuments.php

<?php
require_once __DIR__ . '/../../connect.php';

// Sanitize and validate input
$driverId = filterRequest("driverId");
$issueDate = filterRequest("IssueDate");
$inspectionResult = filterRequest("InspectionResult");

// Prepare SQL statement
$sql = "INSERT INTO criminalDocuments (driverId, IssueDate, InspectionResult) 
        VALUES (:driverId, :issueDate, :inspectionResult)";

try {
    $stmt = $con->prepare($sql);
    
    // Bind parameters
    $stmt->bindParam(':driverId', $driverId, PDO::PARAM_INT);
    $stmt->bindParam(':issueDate', $issueDate, PDO::PARAM_STR);
    $stmt->bindParam(':inspectionResult', $inspectionResult, PDO::PARAM_STR);
    
    // Execute the statement
    $stmt->execute();
    
    // Check if the insertion was successful
    if ($stmt->rowCount() > 0) {
        jsonSuccess(null, "Criminal document data saved successfully");
    } else {
        jsonError("Failed to save criminal document data");
    }
} catch (PDOException $e) {
    // Log the error and print a generic failure message
    error_log("Database Error: " . $e->getMessage());
    jsonError("An error occurred while saving the data");
}
?>

File: auth/captin/deletecaptainAccounr.php

<?php

require_once __DIR__ . '/../../connect.php';

$id = filterRequest("id");
// يمكن استقبال سبب الحظر من التطبيق أو وضعه كقيمة افتراضية
$reason = "Driver requested deletion (deleteFromHimself)"; 

// تأكد أن المعرف رقم صحيح
if (!is_numeric($id)) {
    jsonError("Invalid ID");
    exit();
}

try {
    // 1. جلب رقم الهاتف الخاص بالسائق قبل التحديث
    // نحتاج الهاتف لإضافته في القائمة السوداء
    $stmtPhone = $con->prepare("SELECT phone FROM `driver` WHERE `id` = :id");
    $stmtPhone->bindParam(':id', $id, PDO::PARAM_INT);
    $stmtPhone->execute();
    $driverData = $stmtPhone->fetch(PDO::FETCH_ASSOC);

    // التحقق من وجود السائق
    if (!$driverData) {
        jsonError("Driver not found");
        exit();
    }

    $phone = $driverData['phone'];

    // 2. تحديث حالة السائق
    $sql = "UPDATE `driver` SET `status` = 'deleteFromHimself' WHERE `id` = :id";
    $stmt = $con->prepare($sql);
    $stmt->bindParam(':id', $id, PDO::PARAM_INT);
    $stmt->execute();

    if ($stmt->rowCount() > 0) {
        // 3. الإضافة إلى القائمة السوداء (blacklist_driver)
        // نستخدم NOW() لتسجيل الوقت الحالي تلقائياً
        // لا نمرر id العمود الأول لأنه غالباً Auto Increment في قاعدة البيانات
        $insertSql = "INSERT INTO `blacklist_driver` (`driver_id`, `phone`, `reason`, `created_at`) 
                      VALUES (:driver_id, :phone, :reason, NOW())";
        
        $insertStmt = $con->prepare($insertSql);
        $insertStmt->execute([
            ':driver_id' => $id,
            ':phone'     => $phone,
            ':reason'    => $reason
        ]);

        jsonSuccess(null, "Record marked as deleted and added to blacklist successfully");
    } else {
        jsonError("Failed to update record or no change made");
    }

} catch (PDOException $e) {
    // في حال حدوث خطأ في قاعدة البيانات (مثلاً تكرار الإضافة)
    jsonError("Database Error: " . $e->getMessage());
}
?>

File: auth/captin/getAccount.php

<?php
require_once __DIR__ . '/../../connect.php';

$driverID = filterRequest("id");

// تحقق أن المعرف رقم صحيح
if (!is_numeric($driverID)) {
    jsonError("Invalid driver ID");
    exit();
}

// استخدم bindParam لتفادي حقن SQL
$sql = "SELECT `accountBank` FROM `driver` WHERE `id` = :id";
$stmt = $con->prepare($sql);
$stmt->bindParam(':id', $driverID, PDO::PARAM_INT);
$stmt->execute();

if ($stmt->rowCount() > 0) {
    $row = $stmt->fetchAll(PDO::FETCH_ASSOC);
    jsonSuccess($row);
} else {
    jsonError("No account bank record found");
}
?>

File: auth/captin/getAllDriverSecure.php

<?php
require_once __DIR__ . '/../../connect.php';

$sql = "
SELECT
    `id`,
    `phone`,
    `email`,
    `gender`,
    `birthdate`,
    `first_name`,
    `last_name`,
    `sosPhone`
FROM
    `passengers`
";

$stmt = $con->prepare($sql);
$stmt->execute();

if ($stmt->rowCount() > 0) {
    $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);

    // فك تشفير الحقول الحساسة
    foreach ($rows as &$row) {
        $row['phone'] = $encryptionHelper->decryptData($row['phone']);
        $row['email'] = $encryptionHelper->decryptData($row['email']);
        $row['gender'] = $encryptionHelper->decryptData($row['gender']);
        $row['birthdate'] = $encryptionHelper->decryptData($row['birthdate']);
        $row['first_name'] = $encryptionHelper->decryptData($row['first_name']);
        $row['last_name'] = $encryptionHelper->decryptData($row['last_name']);
        $row['sosPhone'] = $encryptionHelper->decryptData($row['sosPhone']);
    }

    jsonSuccess($rows);
} else {
    jsonError("No wallet record found");
}
?>

File: auth/captin/verifyEmail.php


File: auth/captin/getPromptDriverDocumentsEgypt.php

<?php
require_once __DIR__ . '/../../connect.php';

// $driverID = filterRequest("id");

$sql = "
SELECT * FROM `promptDriverIDEgypt`";

$stmt = $con->prepare($sql);
$stmt->execute();

if ($stmt->rowCount() > 0) {
    // Fetch the record
    $row = $stmt->fetchAll(PDO::FETCH_ASSOC);

    jsonSuccess($row);
    
}
    else{
    // Print a failure message
    jsonError($message = "No wallet record found");
}
?>

File: auth/sms/sms_to_user_change_fingerprint.php

<?php
require_once __DIR__ . '/../../connect.php';

// استقبال رقم الهاتف
$phone = filterRequest('phone');
$language = filterRequest('lang') ?? 'r';

// 1⃣ جلب بيانات API من البيئة
$username     = "Sefer";
$password     = getenv("SMS_PASSWORD_EGYPT");
$apiEndpoint  = getenv("SMS_API_ENDPOINT");
$sender       = "SEFER";
$appName      = "Tripz";

if (!$password || !$apiEndpoint) {
    jsonError("API configuration is missing");
    exit;
}

// 2⃣ توليد كود OTP من السيرفر
$otp = rand(100000, 999999);

// 3⃣ تشفير البيانات قبل تخزينها
$phoneEncrypted = $encryptionHelper->encryptData($phone);
$otpEncrypted   = $encryptionHelper->encryptData($otp);

// 4⃣ تخزين OTP في قاعدة البيانات
try {
    $insertOtp = "INSERT INTO otp_verification_fingerPrint (phone, otp) VALUES (?, ?)";
    $stmt = $con->prepare($insertOtp);
    $stmt->execute([$phoneEncrypted, $otpEncrypted]);
} catch (PDOException $e) {
    error_log("DB Insert Error: " . $e->getMessage());
    jsonError("Failed to save OTP to the database");
    exit;
}

// 5⃣ إرسال الرسالة عبر API
$message = "$appName app code is $otp\ncopy it to app";

$payload = json_encode([
    "username" => $username,
    "password" => $password,
    "message"  => $message,
    "language" => $language,
    "sender"   => $sender,
    "receiver" => $phone
]);

$ch = curl_init($apiEndpoint);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

// 6⃣ التحقق من نجاح الإرسال
if ($httpCode != 200) {
    error_log("SMS API Failed. HTTP Code: $httpCode. Response: " . $response);
    jsonError("Failed to send OTP SMS");
    exit;
}

// 7⃣ إرجاع النتيجة
jsonSuccess(["message" => "OTP sent successfully"]);
?>

File: auth/sms/updatePhoneInvalidSMS.php

<?php

// Include the database connection file
require_once __DIR__ . '/../../connect.php';

// Filter and encrypt the phone number input
$phone_number = filterRequest("phone_number");
$phone_number = $encryptionHelper->encryptData($phone_number);

// Prepare the SQL query to verify the phone
$sql = "UPDATE phone_verification SET is_verified = 1 WHERE phone_number = :phone_number";

// Prepare the statement
$stmt = $con->prepare($sql);
$stmt->bindParam(":phone_number", $phone_number);

// Execute the query
$stmt->execute();
$affectedRows = $stmt->rowCount();

// Check if the update was successful
if ($affectedRows > 0) {
    jsonSuccess(["message" => "Phone number verified successfully"]);
} else {
    jsonError("No phone number found or verification failed");
}
?>

File: auth/sms/updatePhoneInvalidSMSPassenger.php

<?php

require_once __DIR__ . '/../../connect.php';

// استقبال وتشفير رقم الهاتف
$phone_number = filterRequest("phone_number");
$phone_number = $encryptionHelper->encryptData($phone_number);

// تنفيذ الاستعلام
$sql = "UPDATE phone_verification_passenger SET verified = 1 WHERE phone_number = :phone_number";
$stmt = $con->prepare($sql);
$stmt->bindParam(":phone_number", $phone_number);
$stmt->execute();

$affectedRows = $stmt->rowCount();

// إرجاع النتيجة
if ($affectedRows > 0) {
    jsonSuccess(["message" => "Phone number verified successfully"]);
} else {
    jsonError("No phone number found or verification failed");
}
?>

File: auth/sms/getSender.php

<?php

require_once __DIR__ . '/../../connect.php';



    $sql = "SELECT
    *
FROM
    `smsSender`
WHERE
    id = '1'";


$stmt = $con->prepare($sql);
$stmt->execute();
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);

if ($stmt->rowCount() > 0) {
   
     jsonSuccess($data = $result);
} else {
   
    
     jsonError($message = "No driver order data found");
}

?>

File: auth/google_auth/check_status.php

<?php
// File: check_status.php
// هذا الملف الذي سيقوم التطبيق بالاتصال به بشكل دوري.
// يتحقق من حالة الجلسة ويرجع البيانات عند نجاحها.

header('Content-Type: application/json');

// 1. استقبال الـ loginToken من التطبيق
$input = json_decode(file_get_contents('php://input'), true);
if (!isset($input['loginToken'])) {
    http_response_code(400);
    echo json_encode(['status' => 'error', 'message' => 'Login token is missing.']);
    exit();
}
$loginToken = basename($input['loginToken']); // حماية

// 2. التحقق من ملف الجلسة
$pollDir = __DIR__ . '/polls';
$sessionFile = $pollDir . '/' . $loginToken . '.json';

if (file_exists($sessionFile)) {
    $sessionData = json_decode(file_get_contents($sessionFile), true);
    
    // إذا نجحت العملية، أرجع البيانات واحذف الملف
    if ($sessionData['status'] === 'success') {
        echo json_encode($sessionData);
        unlink($sessionFile); // حذف الملف بعد النجاح
    } else {
        // إذا كانت لا تزال معلقة
        echo json_encode(['status' => 'pending']);
    }
} else {
    // إذا انتهت المهلة أو حدث خطأ
    http_response_code(404);
    echo json_encode(['status' => 'expired', 'message' => 'Session not found or expired.']);
}
exit();
?>

File: auth/google_auth/google_auth.php

<?php
$redirectUri = 'https://api.tripz-egypt.com/tripz/auth/google_auth/callback.php';

// google_auth.php

require_once __DIR__ . '/../vendor/autoload.php';

use Google\Client;

header('Content-Type: application/json');

$response = [
    'success' => false,
    'error' => null,
    'data' => null,
];

try {
    if (!isset($_POST['code'])) {
        throw new Exception("Missing authorization code.");
    }

    $code = $_POST['code'];

    $client = new Client();
    $client->setClientId('1086900987150-j8brn0i5s97315kh1ej9jr72grkfqgh5.apps.googleusercontent.com');
    $client->setClientSecret('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');
    $client->setRedirectUri('postmessage');
    $client->addScope('email');
    $client->addScope('profile');

    $token = $client->fetchAccessTokenWithAuthCode($code);

    if (isset($token['error'])) {
        throw new Exception("Access token error: " . $token['error']);
    }

    $client->setAccessToken($token['access_token']);

    $oauth2 = new Google_Service_Oauth2($client);
    $userinfo = $oauth2->userinfo->get();

    $response['success'] = true;
    $response['data'] = [
        'id' => $userinfo->id,
        'email' => $userinfo->email,
        'name' => $userinfo->name,
        'picture' => $userinfo->picture,
    ];

} catch (Exception $e) {
    $response['error'] = $e->getMessage();
}

echo json_encode($response);

File: auth/google_auth/login.php

<?php
// File: start_login.php
// هذا الملف يبدأ عملية تسجيل الدخول.
// يقوم بإنشاء معرف فريد ورابط تسجيل الدخول وإرسالهم للتطبيق.

// 1. الإعدادات
$clientID = '1086900987150-j8brn0i5s97315kh1ej9jr72grkfqgh5.apps.googleusercontent.com';
$redirectUri = 'https://api.tripz-egypt.com/tripz/auth/google_auth/callback.php';
$scopes = 'email profile';

// 2. إنشاء معرف فريد للجلسة (login token)
$loginToken = bin2hex(random_bytes(24));

// 3. إنشاء مجلد لتخزين الجلسات المؤقتة إذا لم يكن موجوداً
$pollDir = __DIR__ . '/polls';
if (!is_dir($pollDir)) {
    mkdir($pollDir, 0775, true);
}

// 4. إنشاء ملف مؤقت لهذه الجلسة
$sessionFile = $pollDir . '/' . $loginToken . '.json';
file_put_contents($sessionFile, json_encode(['status' => 'pending']));

// 5. بناء رابط جوجل مع تمرير المعرف الفريد في متغير 'state'
$authUrl = 'https://accounts.google.com/o/oauth2/v2/auth?' . http_build_query([
    'client_id' => $clientID,
    'redirect_uri' => $redirectUri,
    'response_type' => 'code',
    'scope' => $scopes,
    'access_type' => 'offline',
    'state' => $loginToken // مهم جداً
]);

// 6. إرجاع الرابط والمعرف للتطبيق
header('Content-Type: application/json');
echo json_encode([
    'authUrl' => $authUrl,
    'loginToken' => $loginToken
]);
exit();
?>

File: auth/google_auth/callback.php

<?php
// File: callback.php
// هذا الملف يستقبل الرد من جوجل بعد تسجيل المستخدم دخوله.
// يقوم بتحديث حالة الجلسة بالبيانات الصحيحة.

// 1. الإعدادات
$clientID = '1086900987150-j8brn0i5s97315kh1ej9jr72grkfqgh5.apps.googleusercontent.com';
$clientSecret = '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';
$redirectUri = 'https://api.tripz-egypt.com/tripz/auth/google_auth/callback.php';

// 2. التحقق من وجود 'code' و 'state' من جوجل
if (!isset($_GET['code']) || !isset($_GET['state'])) {
    die('Invalid callback request.');
}
$authCode = $_GET['code'];
$loginToken = basename($_GET['state']); // الحماية من Path Traversal

$pollDir = __DIR__ . '/polls';
$sessionFile = $pollDir . '/' . $loginToken . '.json';

// التحقق من أن ملف الجلسة موجود
if (!file_exists($sessionFile)) {
    die('Invalid or expired session.');
}

// 3. تبديل الـ code بـ access token
$tokenUrl = 'https://oauth2.googleapis.com/token';
$postData = [
    'code' => $authCode,
    'client_id' => $clientID,
    'client_secret' => $clientSecret,
    'redirect_uri' => $redirectUri,
    'grant_type' => 'authorization_code'
];

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $tokenUrl);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
$tokenData = json_decode($response, true);

if (isset($tokenData['access_token'])) {
    // 4. جلب بيانات المستخدم
    $userInfoUrl = 'https://www.googleapis.com/oauth2/v2/userinfo?access_token=' . $tokenData['access_token'];
    $userInfoResponse = file_get_contents($userInfoUrl);
    $userData = json_decode($userInfoResponse, true);

    if (isset($userData['id'])) {
        // 5. تحديث ملف الجلسة بالبيانات الجديدة
        $finalData = [
            'status' => 'success',
            'userData' => $userData
        ];
        file_put_contents($sessionFile, json_encode($finalData));
    }
}

// 6. عرض صفحة نجاح للمستخدم في المتصفح
echo '<!DOCTYPE html><html><head><title>Success</title><meta name="viewport" content="width=device-width, initial-scale=1.0"></head><body style="font-family: sans-serif; text-align: center; padding-top: 50px;"><h1>Authentication Successful</h1><p>You can now return to the Tripz app.</p></body></html>';
exit();
?>

File: auth/token_passenger/send_otp.php

<?php
// File: send_otp.php  (بديل عن النسخة المعتمدة على RaseelPlus)
require_once __DIR__ . '/../../connect.php';

/* 1) توليد رمز التحقق */
$otp      = rand(10000, 99999);
$receiver = filterRequest("receiver");

if (empty($receiver)) {
    jsonError('Phone number is required.');
    exit();
}

/* 2) نصّ الرسالة وإرسالها عبر دالتك الجديدة */
$messageBody = "Your verification code for Siro is: " . $otp;

$raw      = sendWhatsAppFromServer($receiver, $messageBody);
$response = is_string($raw) ? json_decode($raw, true) : (array) $raw;

/*
 * نتوقع بنية مثل:
 *   [
 *     'success' => true,
 *     'details' => ['status' => 'PENDING' | 'SENT' | …]
 *   ]
 */
$sentOK   = $response['success'] ?? false;
$statusOK = in_array($response['details']['status'] ?? '', ['PENDING', 'SENT', 'DELIVERED'], true);

if ($sentOK ) {

    /* 3) تشفير البيانات وحفظ الرمز في قاعدة البيانات */
    $receiver_enc = $encryptionHelper->encryptData($receiver);
    $otp_enc      = $encryptionHelper->encryptData($otp);

    $exp = date('Y-m-d H:i:s', strtotime('+5 minutes'));
    $now = date('Y-m-d H:i:s');

    try {
        $con->prepare("DELETE FROM token_verification WHERE phone_number = ?")
            ->execute([$receiver_enc]);

        $stmt = $con->prepare("
            INSERT INTO token_verification
              (phone_number, token, expiration_time, verified, created_at)
            VALUES (?, ?, ?, 0, ?)
        ");
        $stmt->execute([$receiver_enc, $otp_enc, $exp, $now]);

        jsonSuccess(null, 'OTP sent and saved successfully');

    } catch (PDOException $e) {
        jsonError('OTP sent but failed to save to database');
    }

} else {
    $errMsg = $response['message'] ?? 'Unknown error';
    jsonError('Failed to send OTP: ' . $errMsg);
}

/* -----------------------------------------------------------------
 * يمكن حذف callAPI() تمامًا إن لم يعد مستخدمًا في أي ملف آخر.
 * ---------------------------------------------------------------- */
function callAPI($method, $url, $data) { /* … (أبقِها أو احذفها) */ }
?>

File: auth/token_passenger/verify_otp.php

<?php
// File: verify_otp.php (with enhanced logging)
// siro_v1/auth/token_passenger
require_once __DIR__ . '/../../connect.php';

// --- Start of Script Execution ---
 error_log("--- [verify_otp.php] Script execution started. ---");

$phoneNumber = filterRequest("phone_number");
$otp = filterRequest("otp");

// Log received data for debugging. Be mindful of logging sensitive data in production.
 error_log("[verify_otp.php] Received phone_number: $phoneNumber | Received otp: $otp");

if (empty($phoneNumber) || empty($otp)) {
     error_log("[verify_otp.php] Error: Phone number or OTP is empty.");
    jsonError("Phone number and OTP are required.");
    exit();
}

$phoneNumber_encrypted = $encryptionHelper->encryptData($phoneNumber);
$otp_encrypted = $encryptionHelper->encryptData($otp);

try {
    // 1. التحقق من Redis بدلاً من MySQL
    if (!$redis) {
        jsonError("Security service unavailable");
        exit;
    }

    $cachedOtp = $redis->get("otp:passenger:$phoneNumber");

    if ($cachedOtp && $cachedOtp == $otp) {
        // ننجح في التحقق ونحذف المفتاح من Redis لمنع استخدامه مرة أخرى (One-time use)
        $redis->del("otp:passenger:$phoneNumber");
        
        error_log("[verify_otp.php] OTP verified via Redis for phone: $phoneNumber");

        // 2. التحقق من وجود الراكب في قاعدة البيانات
        $passengerStmt = $con->prepare("SELECT id FROM passengers WHERE phone = ?");
        $passengerStmt->execute([$phoneNumber_encrypted]);
        $passenger = $passengerStmt->fetch(PDO::FETCH_ASSOC);

        if ($passenger) {
            $passengerID = $passenger['id'];
            
            // تحديث التوكن والبصمة إن وجدا
            $newToken = filterRequest("token");
            $fingerPrint = filterRequest("fingerPrint");

            if ($newToken && $fingerPrint) {
                $tokenEncrypted = $encryptionHelper->encryptData($newToken);
                $updateTokenStmt = $con->prepare("UPDATE tokens SET token = ?, fingerPrint = ? WHERE passengerID = ?");
                $updateTokenStmt->execute([$tokenEncrypted, $fingerPrint, $passengerID]);
            }
            
            printSuccess([
                "message" => "Token verified and updated.",
                "isRegistered" => true,
                "passengerID" => $passengerID
            ]);

        } else {
            printSuccess([
                "message" => "Phone verified, passenger not found.",
                "isRegistered" => false
            ]);
        }

    } else {
        error_log("[verify_otp.php] Invalid or expired OTP for phone: $phoneNumber");
        jsonError("Invalid or expired OTP.");
    }

} catch (Exception $e) {
    // Log the detailed database error message for debugging.
     error_log("[verify_otp.php] FATAL DATABASE ERROR: " . $e->getMessage());
    jsonError("Database error: " . $e->getMessage());
}
?>

File: auth/token_passenger/driver/verify_otp_driver.php

<?php
require_once __DIR__ . '/../../../connect.php';

$phoneNumber = filterRequest("phone_number");
$otp = filterRequest("otp");

if (empty($phoneNumber) || empty($otp)) {
    jsonError("Phone number and OTP are required.");
    exit();
}

$phoneNumber_encrypted = $encryptionHelper->encryptData($phoneNumber);
$otp_encrypted = $encryptionHelper->encryptData($otp);

try {
    $stmt = $con->prepare("
        SELECT * FROM token_verification_driver 
        WHERE phone_number = ? AND token = ?
    ");
    $stmt->execute([$phoneNumber_encrypted, $otp_encrypted]);
    $result = $stmt->fetch(PDO::FETCH_ASSOC);

    if ($result) {
        $expiration_time = strtotime($result['expiration_time']);

        if (time() <= $expiration_time) {
            $con->prepare("UPDATE token_verification_driver SET verified = 1 WHERE id = ?")
                ->execute([$result['id']]);

            $driverStmt = $con->prepare("SELECT id FROM driver WHERE phone = ?");
            $driverStmt->execute([$phoneNumber_encrypted]);
            $driver = $driverStmt->fetch(PDO::FETCH_ASSOC);

            if ($driver) {
                $driverID = $driver['id'];
                $newToken = filterRequest("token");
                $fingerPrint = filterRequest("fingerPrint");

                if ($newToken && $fingerPrint) {
                    $tokenEncrypted = $encryptionHelper->encryptData($newToken);

                    $checkTokenStmt = $con->prepare("SELECT id FROM driverToken WHERE captain_id = ?");
                    $checkTokenStmt->execute([$driverID]);

                    if ($checkTokenStmt->rowCount() > 0) {
                        $con->prepare("UPDATE driverToken SET token = ?, fingerPrint = ? WHERE captain_id = ?")
                            ->execute([$tokenEncrypted, $fingerPrint, $driverID]);
                    } else {
                        $con->prepare("INSERT INTO driverToken (token, fingerPrint, captain_id, created_at) VALUES (?, ?, ?, NOW())")
                            ->execute([$tokenEncrypted, $fingerPrint, $driverID]);
                    }

                    $response = [
                        "message" => "Driver token verified and updated.",
                        "isRegistered" => true,
                        "driverID" => $driverID
                    ];
                    jsonSuccess($response);

                } else {
                    jsonError("Token or fingerprint missing.");
                }

            } else {
                printSuccess([
                    "message" => "Phone verified, but driver not found.",
                    "isRegistered" => false
                ]);
            }

        } else {
            jsonError("OTP expired. Request a new one.");
        }

    } else {
        jsonError("Invalid OTP.");
    }

} catch (PDOException $e) {
    jsonError("Database error occurred.");
}

File: auth/token_passenger/driver/send_otp_driver.php

<?php
// File: send_otp_driver.php   (إصدار بدون RaseelPlus)
require_once __DIR__ . '/../../../connect.php';

/* 1) توليد رمز التحقق --------------------------------------------------- */
$otp      = rand(10000, 99999);
$receiver = filterRequest("receiver");

if (empty($receiver)) {
    jsonError('Phone number is required.');
    exit();
}

/* 2) نص الرسالة وإرسالها عبر دالتك الجديدة ------------------------------ */
$messageBody = "رمز التحقق الخاص بك لتطبيق سيرو درايفر هو: " . $otp;

/**
 * نفترض أن sendWhatsAppFromServer() تُرجع:
 *   [
 *      'success' => true/false,
 *      'message' => 'Message sent successfully!',
 *      'details' => ['status' => 'PENDING' | 'SENT' | …]
 *   ]
 */
$raw       = sendWhatsAppFromServer($receiver, $messageBody);
$response  = is_string($raw) ? json_decode($raw, true) : (array) $raw;

$sentOK    = $response['success'] ?? false;
$waStatus  = $response['details']['status'] ?? '';

if ($sentOK ) {

    /* 3) تشفير البيانات وحفظها في DB ----------------------------------- */
    $receiver_enc = $encryptionHelper->encryptData($receiver);
    $otp_enc      = $encryptionHelper->encryptData($otp);

    $exp = date('Y-m-d H:i:s', strtotime('+5 minutes'));
    $now = date('Y-m-d H:i:s');

    try {
        // حذف رموز قديمة
        $con->prepare("DELETE FROM token_verification_driver WHERE phone_number = ?")
            ->execute([$receiver_enc]);

        $stmt = $con->prepare("
            INSERT INTO token_verification_driver
                (phone_number, token, expiration_time, verified, created_at)
            VALUES (?, ?, ?, 0, ?)
        ");
        $stmt->execute([$receiver_enc, $otp_enc, $exp, $now]);

        jsonSuccess(null, 'OTP sent and saved successfully');

    } catch (PDOException $e) {
        jsonError('OTP sent but failed to save to database');
    }

} else {
    $errMsg = $response['message'] ?? 'Unknown error';
    jsonError('Failed to send OTP: ' . $errMsg);
}

/* -----------------------------------------------------------------------
 * أبقينا callAPI() فقط إذا كان يُستخدم في ملفات أخرى  احذفه إن شئت.
 * --------------------------------------------------------------------- */
function callAPI($method, $url, $data) { /* … */ }
?>

File: auth/document_syria/ai_document.php

<?php
require_once __DIR__ . '/../../connect.php';

$driverId = filterRequest("driver_id");
$type     = filterRequest("type");

// 🔒 Validate image
if (!isset($_FILES['image']) || $_FILES['image']['error'] !== UPLOAD_ERR_OK) {
    error_log("Upload error: Image not provided or upload failed.");
    jsonError("Image upload failed");
    exit;
}

$file      = $_FILES['image'];
$extension = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
$allowed   = ['jpg', 'jpeg', 'png'];

if (!in_array($extension, $allowed)) {
    error_log("Unsupported file type: $extension");
    jsonError("Unsupported file type");
    exit;
}

$uniqueName  = "driver_" . $type . "_" . $driverId . ".$extension";
$uploadDir   = "../uploads/documents/";
$uploadPath  = $uploadDir . $uniqueName;

if (!is_dir($uploadDir)) {
    mkdir($uploadDir, 0755, true);
}

if (!move_uploaded_file($file['tmp_name'], $uploadPath)) {
    error_log("Failed to move uploaded file.");
    jsonError("Failed to move uploaded image");
    exit;
}

$imageUrl    = "https://intaleq.xyz/siro/auth/uploads/documents/" . $uniqueName ;
$imageData   = file_get_contents($uploadPath);
$imageBase64 = base64_encode($imageData);

$mimeType = match ($extension) {
    'jpg', 'jpeg' => 'image/jpeg',
    'png'         => 'image/png',
    default       => 'application/octet-stream',
};

$prompts = [
    "id_front_sy" => <<<EOT
You are an OCR expert for Syrian national ID cards (green card).

### TASK
Analyse the **front side** of the ID and return **raw JSON only** with exactly these keys:

{
  "full_name": "",          // الاسم الثلاثي أو الرباعي
  "national_number": "",    // الرقم الوطني (LATIN digits only)
  "dob": "YYYY-MM-DD",      // تاريخ الميلاد
  "address": ""             // العنوان
}

### RULES
* Read the red number on the bottom of the card.
* Convert any Eastern-Arabic digits (٠١٢٣٤٥٦٧٨٩) to Western-Arabic digits (0-9).
* `national_number` must contain **Latin digits only, no spaces or other characters**.
* If a field is missing, set it to **null**.
* Convert the birth date to ISO `YYYY-MM-DD`.
* Return valid JSON only — no extra keys, no markdown.
EOT,
    "id_back_sy" => <<<EOT
أنت خبير OCR مختص ببطاقات الهوية السورية (الوجه الخلفي).

### المطلوب
حلّل صورة الوجه الخلفي للهوية السورية وأعد **JSON صِرف** يحتوي المفاتيح التالية فقط:

{
  "governorate": "",        // المحافظة (مثال: دمشق)
  "address": "",            // العنوان التفصيلي (حيّ، بلدة …)
  "gender": "",         //Male or Female
  "issue_date": "YYYY-MM-DD"// تاريخ الإصدار بصيغة ISO
}

### القواعد
1. حوّل أي أرقام عربية شرقية (٠١٢٣٤٥٦٧٨٩) إلى أرقام لاتينية (0-9).
2. أعدّ تاريخ الإصدار بالتقويم الميلادي بصيغة `YYYY-MM-DD`.
3. استخدم أحرف لاتينية كبيرة لزمرة الدم مع رمز `+` أو `-` فقط.
4. إذا كان أحد الحقول غير موجود مطلقًا، أعد قيمته **null**.
5. لا تُرجع أي مفاتيح إضافية أو شروح أو Markdown — JSON صالح فقط.
EOT,
    "driving_license_sy_front" => <<<EOT
You are an OCR expert for Syrian documents.

### TASK
Analyse the **front side of a Syrian driving licence** and return **clean JSON only** with the following keys (no extra keys, no markdown):

{
  "name_arabic": "",        // الاسم الثلاثي أو الرباعي بالعربية
  "birth_place": "",        // المحافظة أو المنطقة المكتوبة بعد كلمة الولادة
  "birth_year": "",         // سنة الميلاد فقط (أربعة أرقام)
  "national_number": ""
  "civil_registry": "",     // سطر "القيد" (مثال: سهوة 3)
  "blood_type": ""          // زمرة الدم بالشكل: A+ , A- , B+ , B- , AB+ , AB- , O+ , O-
}

### RULES
* إذا كانت القيمة مفقودة تمامًا اكتب **null**.
* لا تُغيّر ترتيب المفاتيح.
* لا تُرسل أى شرح أو أسطر إضافية  JSON خالص فقط.
EOT,
  
    "driving_license_sy_back" => <<<EOT
You are an OCR expert for Syrian driving licences.

### TASK
Analyse the **back side** of a Syrian  driving licence and return **raw JSON only** with exactly these keys:

{
  "issue_date": "YYYY-MM-DD",    // تاريخ المنح
  "expiry_date": "YYYY-MM-DD",   // صالحة لغاية
  "license_number": "",          // رقم الإجازة
  "license_category": ""         // D1, D2, D3 … (as printed after "UNIVERSAL DRIVING LICENCE")
}

### RULES
* If a value is totally absent, set it to **null**.
* Convert all dates to ISO `YYYY-MM-DD` (Gregorian).
* Do **NOT** add extra keys, comments, or markdown — return valid JSON only.
EOT,
    "vehicle_license_sy_front" => <<<EOT
You are an OCR expert specialized in analyzing Syrian vehicle registration cards (الرخصة البرتقالية).

Your task is to extract structured data from the **front side** of the Syrian orange vehicle card and return **raw JSON only** with the following exact fields:

{
  "car_plate": "",          // رقم المركبة الكامل مع اسم المحافظة، مأخوذ من الجهة اليسرى في السطر الأول (مثال: "155186 درعا")
  "owner": "",              // اسم المالك الكامل
  "vin": "",                // رقم الهيكل
  "color": "",              // اللون بالعربية أو الإنجليزية (مثال: "أبيض" أو "White")
  "color_hex": "",          // كود اللون بصيغة Hex (مثال: "#FFFFFF") أو #27332F إن تعذّر
  "issue_date": "YYYY-MM-DD",        // تاريخ المنح بصيغة ISO
  "inspection_date": "YYYY-MM-DD"    // تاريخ الفحص القادم بصيغة ISO
}

### Instructions & Rules:

1. Do **not** extract the "رمز المركبة" (on the right side of the first line) — use only the **left side** of the first line for `car_plate`.
2. Convert any Arabic dates (like `2024/05/13`) into ISO format `YYYY-MM-DD`.
3. If any value is missing or unreadable, return `null` for it.
4. Maintain Arabic encoding (e.g., owner name, city name, color).
5. Never guess — extract only what's visually found on the card.
6. Never include any explanation or extra output — return the JSON only.

Example of valid `car_plate`:
- "155186 درعا"
- "45291 دمشق"
- "122334 حمص"
EOT,
  "vehicle_license_sy_back" => <<<EOT
You are an OCR expert for Syrian vehicle registration cards (orange card).

### TASK
Analyse the **back side** of the card and return **raw JSON only** with exactly these keys (no more, no less):

{
  "make": "",         // الصانع (Hyundai …)
  "model": "",        // الطراز (H1 …)
  "year": "",         // سنة الصنع بالأرقام اللاتينية (e.g. "2019")
  "fuel": "",         // نوع الوقود (بنزين، ديزل …) أو بالإنجليزية (Petrol, Diesel,electric)
  "chassis": ""       // رقم الهيكل (VIN)
}

### RULES
* Convert any Eastern-Arabic digits (٠١٢٣٤٥٦٧٨٩) to Western digits (0-9).
* Normalise color names to standard English if possible, then map to a common Hex code  
  • "أبيض / White" → **#FFFFFF**  
  • "أسود / Black" → **#000000**  
  • "أحمر / Red"   → **#FF0000**  
  • "أزرق / Blue"  → **#0000FF**  
  • … (use the closest basic colour); if no match, set **color_hex = null**.
* If any field is unreadable or absent, set its value to **null**.
* Do **NOT** include extra keys, comments, or markdown — output valid JSON only.
EOT
];

$prompt = $prompts[$type] ?? $prompts["id_front_sy"];

$apiKey = getenv("GEMINI_API_KEY");
$apiURL = "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash-lite:generateContent?key=$apiKey";

$headers = ["Content-Type: application/json"];
$payload = [
    "contents" => [
        ["role" => "user", "parts" => [["text" => $prompt]]],
        ["role" => "user", "parts" => [["inlineData" => ["mimeType" => $mimeType, "data" => $imageBase64]]]]
    ]
];

$ch = curl_init($apiURL);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));

$response = curl_exec($ch);

if (curl_errno($ch)) {
    $error_msg = curl_error($ch);
    error_log("CURL error: $error_msg");
    jsonError("AI Error: $error_msg");
    curl_close($ch);
    exit;
}

curl_close($ch);
error_log("AI raw response: $response");

$data = json_decode($response, true);
if (json_last_error() !== JSON_ERROR_NONE) {
    error_log("JSON decode error: " . json_last_error_msg());
    jsonError("Failed to parse AI response");
    exit;
}

$textRaw = $data['candidates'][0]['content']['parts'][0]['text'] ?? '';
$textRaw = trim(preg_replace('/```json|```/', '', $textRaw));
$json = json_decode($textRaw, true);

$requiredKey = match ($type) {
    'id_front_sy' => 'national_number',
    'id_back_sy' => 'gender',
    'driving_license_sy' => 'license_type',
    'vehicle_license_sy' => 'chassis',
    default => null,
};

if (!$json || ($requiredKey && !isset($json[$requiredKey]))) {
    error_log("AI response missing required key '$requiredKey': $textRaw");
    jsonError("AI failed to extract required information");
    exit;
}

printSuccess([
    "image_url" => $imageUrl,
    "data"      => $json
]);

File: auth/document_syria/uploadDocSyria.php

<?php
/**
 * upload_document.php
 * الغرض: رفع صورة وثيقة فقط وإرجاع رابطها (بدون ذكاء صناعي)
 */

require_once __DIR__ . '/../../connect.php';

$driverId = trim((string) filterRequest("driver_id"));
$type     = trim((string) filterRequest("type"));

// ✅ التحقق من الحقول الاختيارية
if ($driverId === "") { $driverId = "unknown"; }
if ($type === "")     { $type     = "generic"; }

// ✅ التحقق من ملف الصورة
if (!isset($_FILES['image']) || $_FILES['image']['error'] !== UPLOAD_ERR_OK) {
    error_log("Upload error: Image not provided or upload failed.");
    jsonError("Image upload failed");
    exit;
}

$file = $_FILES['image'];

// ✅ السماح بالامتدادات الشائعة + فحص MIME الحقيقي
$allowedExt  = ['jpg', 'jpeg', 'png'];
$extension   = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
if (!in_array($extension, $allowedExt, true)) {
    error_log("Unsupported file extension: $extension");
    jsonError("Unsupported file type");
    exit;
}

// فحص نوع المحتوى الفعلي (أكثر أماناً)
$finfo = new finfo(FILEINFO_MIME_TYPE);
$mime  = $finfo->file($file['tmp_name']) ?: 'application/octet-stream';
$allowedMime = ['image/jpeg', 'image/png'];
if (!in_array($mime, $allowedMime, true)) {
    error_log("Unsupported MIME type: $mime");
    jsonError("Unsupported image MIME type");
    exit;
}

// (اختياري) حد أقصى للحجم 10MB
$maxBytes = 10 * 1024 * 1024;
if ($file['size'] > $maxBytes) {
    error_log("Image too large: {$file['size']} bytes");
    jsonError("Image too large (max 10MB)");
    exit;
}

// 📁 مسارات الحفظ
$uploadDir  = "../uploads/documents/";
if (!is_dir($uploadDir)) {
    if (!mkdir($uploadDir, 0755, true) && !is_dir($uploadDir)) {
        error_log("Failed to create upload directory: $uploadDir");
        jsonError("Server error: cannot create upload directory");
        exit;
    }
}


$baseName   = "driver_{$type}_{$driverId}";
$uniqueName = $baseName . "." . $extension;
$uploadPath = $uploadDir . $uniqueName;

// ⬆️ نقل الملف
if (!move_uploaded_file($file['tmp_name'], $uploadPath)) {
    error_log("Failed to move uploaded file to $uploadPath");
    jsonError("Failed to move uploaded image");
    exit;
}

// 🔒 منع التنفيذ لو رُفع PHP بالخطأ
@chmod($uploadPath, 0644);

// 🌐 توليد BASE_URL آمن (يدعم ENV أو يعتمد على المضيف الحالي)
if (!defined('BASE_URL')) {
    $APP_BASE_URL = rtrim(getenv('APP_BASE_URL') ?: '', '/');
    if ($APP_BASE_URL === '') {
        $scheme = isset($_SERVER['REQUEST_SCHEME']) ? $_SERVER['REQUEST_SCHEME'] : ((isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https' : 'http');
        $host   = $_SERVER['HTTP_HOST'] ?? 'localhost';
        define('BASE_URL', $scheme . '://' . $host);
    } else {
        define('BASE_URL', $APP_BASE_URL);
    }
}

// ⚙️ مسار الرابط العام (عدّل المسار حسب نشر مشروعك)
$publicPath = "/siro/auth/uploads/documents/" . $uniqueName;
$imageUrl   = rtrim(BASE_URL, '/') . $publicPath;

// ✅ نتيجة نهائية: فقط رابط الصورة وبعض البيانات المفيدة
printSuccess([
    $imageUrl,
   
]);

File: auth/Tester/getTesterApp.php

<?php

require_once __DIR__ . '/../../connect.php';

$appPlatform = filterRequest("appPlatform");


    $sql = "SELECT
    *
FROM
    `testApp`
WHERE
    appPlatform = '$appPlatform'--  AND isTest = 0;";

$stmt = $con->prepare($sql);
$stmt->execute();
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);

if ($stmt->rowCount() > 0) {
    // Print the retrieved data
    // echo json_encode($result);
     jsonSuccess($data = $result);
} else {
    // Print a failure message
    
     jsonError($message = "No driver order data found");
}

?>

File: auth/Tester/updateTesterApp.php

<?php
require_once __DIR__ . '/../../connect.php';

$appPlatform = filterRequest("appPlatform");

$sql = "UPDATE
    `testApp`
SET
    `isTest` = '1'
WHERE
    `testApp`.appPlatform = '$appPlatform';";

$stmt = $con->prepare($sql);
$stmt->execute();

if ($stmt->rowCount() > 0) {
    // Print a success message
    jsonSuccess($message = "Test data updated successfully");
} else {
    // Print a failure message
    jsonError($message = "Failed to update driver order data");
}
?>

File: auth/passengerOTP/sendOtpPassenger.php

<?php
require_once __DIR__ . '/../../connect.php';

$phone_number = filterRequest("phone_number");
$token_code = filterRequest("token_code");
$expiration_time = filterRequest("expiration_time"); // Assuming this is a timestamp

// Check if the phone number already exists
$sql = "SELECT * FROM `phone_verification_passenger` WHERE `phone_number` = '$phone_number'";
$stmt = $con->prepare($sql);
$stmt->execute();

$rowCount = $stmt->rowCount();

if ($rowCount > 0) {
    // The phone number already exists, so update the data
    $sql = "UPDATE `phone_verification_passenger` SET `token_code` = '$token_code', `expiration_time` = DATE_ADD(NOW(), INTERVAL 5 MINUTE) WHERE `phone_number` = '$phone_number'";
    $stmt = $con->prepare($sql);
    $stmt->execute();

    if ($stmt->rowCount() > 0) {
        // The update was successful
        jsonSuccess($message = "Phone verification data updated successfully");
    } else {
        // The update was unsuccessful
        jsonError($message = "Failed to update phone verification data");
    }
} else {
    // The phone number does not exist, so insert the data
   $sql = "INSERT INTO `phone_verification_passenger` (`phone_number`, `token_code`, `expiration_time`, `is_verified`, `created_at`) VALUES ('$phone_number', '$token_code', DATE_ADD(NOW(), INTERVAL 5 MINUTE), 0, NOW())";
    $stmt = $con->prepare($sql);
    $stmt->execute();

    if ($stmt->rowCount() > 0) {
        // The insertion was successful
        jsonSuccess($message = "Phone verification data saved successfully");
    } else {
        // The insertion was unsuccessful
        jsonError($message = "Failed to save phone verification data");
    }
}
?>

File: auth/passengerOTP/verifyOtpPassenger.php

<?php
require_once __DIR__ . '/../../connect.php';

$phone_number = $encryptionHelper->encryptData(filterRequest("phone_number"));
$token_code = $encryptionHelper->encryptData(filterRequest("token"));

//  error_log("phone=$phone_number, token=$token_code");

// Check if the phone number and token code match
$sql = "SELECT * FROM `phone_verification_passenger` WHERE `phone_number` = '$phone_number' AND `token` = '$token_code' 
AND `verified` = 0 ";
// error_log("sql is =$sql");

$stmt = $con->prepare($sql);
$stmt->execute();
$result = $stmt->fetch();

if ($result) {
    // $id = $result["id"];
    $sql = "UPDATE `phone_verification_passenger` SET `verified` = 1 WHERE `phone_number` = '$phone_number'";
    $stmt = $con->prepare($sql);
    $stmt->execute();

    jsonSuccess($message = "Your phone number has been verified.");
} else {
    jsonError($message = "Your phone number could not be verified. Please try again.");
}
?>

File: serviceapp/getDriversPhoneNotComplete.php

<?php
require_once __DIR__ . '/../connect.php';

/*
    المطلوب:
    - جلب كل أرقام الهاتف من phone_verification
      والتي غير موجودة في جدول driver
    - فك تشفير الهاتف والإيميل
    - فقط السجلات خلال آخر 5 أيام
*/

$sql = "
  SELECT 
    pv.id, 
    pv.phone_number, 
    pv.created_at
FROM 
    phone_verification pv
LEFT JOIN driver d 
    ON pv.phone_number = d.phone
LEFT JOIN notesForDriverService n 
    ON pv.phone_number = n.phone
WHERE 
    d.phone IS NULL        -- لم يقم بالتسجيل كسائق بعد
    AND n.phone IS NULL    -- لم يتم التواصل معه سابقاً (لا يوجد ملاحظات)
    AND pv.created_at >= (NOW() - INTERVAL 6 DAY) -- تم الإنشاء خلال آخر 3 أيام
ORDER BY RAND() 
LIMIT 1;

";

$stmt = $con->prepare($sql);
$stmt->execute();

if ($stmt->rowCount() > 0) {

    $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);

    // فك تشفير أرقام الهاتف والإيميل
    foreach ($rows as &$r) {

        if (isset($r['phone_number']) && $r['phone_number'] != null) {
            $r['phone_number'] = $encryptionHelper->decryptData($r['phone_number']);
        }

        if (isset($r['email']) && $r['email'] != null) {
            $r['email'] = $encryptionHelper->decryptData($r['email']);
        }
    }

    jsonSuccess($rows);

} else {
    jsonError("No phone numbers found in the last 5 days");
}
?>

File: serviceapp/getCarPlateNotEdit.php

<?php
require_once __DIR__ . '/../connect.php';

$phoneNumber = filterRequest("phone_number");

$sql = "SELECT
    CR.`id`,
    CR.`driverID`,
    CR.`vin`,
    CR.`car_plate`,
    CR.`make`,
    CR.`model`,
    CR.`year`,
    CR.`expiration_date`,
    CR.`color`,
    CR.`owner`,
    CR.`color_hex`,
    CR.`address`,
    CR.`displacement`,
    CR.`fuel`,
    CR.`registration_date`,
    CR.`created_at`,
    d.phone
FROM
    `CarRegistration` CR
LEFT JOIN driver d ON d.id = CR.driverID
WHERE
    CR.`driverID` NOT IN (
        SELECT DISTINCT CPE.`driverId`
        FROM `carPlateEdit` CPE
    )
ORDER BY RAND()
LIMIT 10;
";

$stmt = $con->prepare($sql);
$stmt->execute();

if ($stmt->rowCount() > 0) {
    $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);

    foreach ($rows as &$row) {
        $row['vin'] = $encryptionHelper->decryptData($row['vin']);
        $row['car_plate'] = $encryptionHelper->decryptData($row['car_plate']);
        $row['owner'] = $encryptionHelper->decryptData($row['owner']);
        $row['address'] = $encryptionHelper->decryptData($row['address']);
        $row['phone'] = $encryptionHelper->decryptData($row['phone']);
    }

    jsonSuccess($rows);
} else {
    jsonError($message = "No Car verified yet found");
}
?>

File: serviceapp/getDriverByPhone.php

<?php
require_once __DIR__ . '/../connect.php';

$phone = filterRequest("phone");
$encryptedPhone = $encryptionHelper->encryptData($phone); // تشفير الهاتف

$sql = "SELECT
    COALESCE(
        (
        SELECT COUNT(*) FROM `ride` WHERE `ride`.`driver_id` = d.id
        ),
    0) AS countRide,
    
    COALESCE(
        (
        SELECT AVG(`ratingDriver`.`rating`)
        FROM ratingDriver
        WHERE `ratingDriver`.`driver_id` = d.id
        ),
    0) AS rating,
    
    COALESCE(
        (
        SELECT SUM(pd.amount)
        FROM `payments` pd
        WHERE pd.driverID = d.id
        ),
    0) AS totalPayment,

    COALESCE(
        (
        SELECT SUM(dw.amount)
        FROM `driverWallet` dw
        WHERE dw.driverID = d.id
        ),
    0) AS totalDriverWallet,

    COALESCE(
        (
        SELECT COUNT(*)
        FROM complaint
        WHERE complaint.driver_id = d.id
        ),
    0) AS countComplaint,

    COALESCE(
        (
        SELECT COUNT(*)
        FROM driver_ride_scam scam
        WHERE scam.driverID = d.id
        ),
    0) AS countScam,

    COALESCE(
        (
        SELECT complaint.description
        FROM complaint
        WHERE complaint.driver_id = d.id
        ORDER BY complaint.date_resolved DESC
        LIMIT 1
        ),
    ''
    ) AS complaint,

    COALESCE(
        (
        SELECT COUNT(*)
        FROM ratingPassenger
        WHERE ratingPassenger.driverID = d.id
        ),
    0) AS DRatingPassengersCount,

    COALESCE(
        (
        SELECT AVG(ratingPassenger.rating)
        FROM ratingPassenger
        WHERE ratingPassenger.driverID = d.id
        ),
    0) AS avgDRatingPassenger,

    cr.*,
    d.*
FROM driver d
LEFT JOIN CarRegistration cr ON cr.driverID = d.id
WHERE d.phone = :phone;
";

$stmt = $con->prepare($sql);
$stmt->bindParam(':phone', $encryptedPhone);
$stmt->execute();

if ($stmt->rowCount() > 0) {
    $row = $stmt->fetchAll(PDO::FETCH_ASSOC);

    // فك تشفير الحقول المهمة
    foreach ($row as &$r) {
        if (isset($r['phone'])) $r['phone'] = $encryptionHelper->decryptData($r['phone']);
        if (isset($r['email'])) $r['email'] = $encryptionHelper->decryptData($r['email']);
        if (isset($r['first_name'])) $r['first_name'] = $encryptionHelper->decryptData($r['first_name']);
        if (isset($r['last_name'])) $r['last_name'] = $encryptionHelper->decryptData($r['last_name']);
        if (isset($r['gender'])) $r['gender'] = $encryptionHelper->decryptData($r['gender']);
        if (isset($r['birthdate'])) $r['birthdate'] = $encryptionHelper->decryptData($r['birthdate']);
        if (isset($r['site'])) $r['site'] = $encryptionHelper->decryptData($r['site']);
        if (isset($r['name_arabic'])) $r['name_arabic'] = $encryptionHelper->decryptData($r['name_arabic']);
      if (isset($r['national_number'])) $r['national_number'] = $encryptionHelper->decryptData($r['national_number']);
        if (isset($r['maritalStatus'])) $r['maritalStatus'] = $encryptionHelper->decryptData($r['maritalStatus']);
        if (isset($r['sosPhone'])) $r['sosPhone'] = $encryptionHelper->decryptData($r['sosPhone']);
        if (isset($r['car_plate'])) $r['car_plate'] = $encryptionHelper->decryptData($r['car_plate']);
        if (isset($r['owner'])) $r['owner'] = $encryptionHelper->decryptData($r['owner']);
        if (isset($r['address'])) $r['address'] = $encryptionHelper->decryptData($r['address']);
        if (isset($r['vin'])) $r['vin'] = $encryptionHelper->decryptData($r['vin']);
       unset($r['password']);
    }

    jsonSuccess($row);
} else {
    jsonError("No wallet record found");
}
?>

File: serviceapp/driverWhoregisterFfterCall.php

<?php
require_once __DIR__ . '/../connect.php';

// استعلام للحصول على السائقين الذين لديهم ملاحظات في نفس الشهر الحالي
$sql = "
SELECT
    d.id AS driver_id,
    d.first_name,
    d.last_name,
    d.phone,
    d.created_at,
    n.note,
    n.editor,
    n.created_at AS note_created_at
FROM
    driver d
LEFT JOIN notesForDriverService n ON n.phone = d.phone
WHERE
    MONTH(d.created_at) = MONTH(CURRENT_DATE())
    AND n.phone IS NOT NULL
ORDER BY
    d.created_at DESC
";

$stmt = $con->prepare($sql);
$stmt->execute();

if ($stmt->rowCount() > 0) {
    $row = $stmt->fetchAll(PDO::FETCH_ASSOC);
    jsonSuccess($row);
} else {
    jsonError("No driver records found with notes this month.");
}
?>

File: serviceapp/getdriverWithoutCar.php

<?php

require_once __DIR__ . '/../connect.php';
$phoneNumber = filterRequest("phone_number");

$sql = "SELECT
    d.id, d.name_arabic, d.phone, d.created_at
FROM
    `driver` d
WHERE
    d.id NOT IN (SELECT driverID FROM CarRegistration)  
ORDER BY `d`.`created_at` DESC
";

$stmt = $con->prepare($sql);
$stmt->execute();

if ($stmt->rowCount() > 0) {
    $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);

    // فك التشفير للحقول الحساسة
    foreach ($rows as &$row) {
        $row['phone'] = $encryptionHelper->decryptData($row['phone']);
        $row['name_arabic'] = $encryptionHelper->decryptData($row['name_arabic']);
    }

    jsonSuccess($rows);
} else {
    jsonError("No Car verified yet found");
}

File: serviceapp/login.php

<?php
require_once __DIR__ . '/../connect.php';

// Get email and password from the request
$email = filterRequest('email');
$password = filterRequest('password');

// Check if email and password are provided
if (empty($email) || empty($password)) {
    echo json_encode([
        "status" => "failure",
        "message" => "Email and password are required."
    ]);
    exit();
}

// SQL to check for user with provided email
$sql = "SELECT * FROM `users` WHERE `email` = :email";

$stmt = $con->prepare($sql);
$stmt->bindParam(':email', $email);
$stmt->execute();

$user = $stmt->fetch(PDO::FETCH_ASSOC);

header('Content-Type: application/json'); // Ensure the response is JSON

if ($user) {
    // Verify the password
    if ($password=== $user['password']) {
        // Password is correct
        unset($user['password']); // Remove password from the response
        echo json_encode([
            "status" => "success",
            "message" => "Login successful",
            "data" => $user
        ]);
    } else {
        // Password is incorrect
        echo json_encode([
            "status" => "failure",
            "message" => "Incorrect password",
            "password"=>$password,
            "password1"=>$user['password'],
        ]);
    }
} else {
    // User not found
    echo json_encode([
        "status" => "failure",
        "message" => "User not found"
    ]);
}

$stmt = null; // Close the statement
$con = null;  // Close the connection
exit();       // Ensure no further output

File: serviceapp/getComplaintAllData.php

<?php
require_once __DIR__ . '/../connect.php';
// $driverID = filterRequest("driverID");

$sql = "SELECT
    cm.`id`,
    cm.`ride_id`,
    cm.`passenger_id`,
    cm.`driver_id`,
    cm.`complaint_type`,
    cm.`description`,
    cm.`date_filed`,
    cm.`statusComplaint`,
    cm.`resolution`,
    cm.`date_resolved`,
    p.first_name AS passengerName,
    d.name_arabic AS driverName,
    d.gender,
    ride.price AS priceOfRide,
    ride.status AS rideStatus,
    ride.carType ascarType,
    ride.paymentMethod AS ridePaymentMethod,
    ride.rideTimeFinish AS rideTimeFinish,
    payments.amount as paymentFromPaymentTable,
    payments.created_at as timeFromPaymentTable,
    (
    SELECT
        AVG(rd.rating)
    FROM
        ratingDriver rd
    WHERE
        rd.driver_id = cm.driver_id
) AS avgRatingDriverFromPassengers,
(
    SELECT
        COUNT(*)
    FROM
        ratingDriver rd
    WHERE
        rd.driver_id = cm.driver_id
) AS countratingDriverFromPassengers,
(
    SELECT
        AVG(rp.rating)
    FROM
        ratingPassenger rp
    WHERE
        rp.passenger_id = cm.passenger_id
) AS avgRatingPassengerFromDrivers,
(
    SELECT
        COUNT(*)
    FROM
        ratingPassenger rp
    WHERE
        rp.passenger_id = cm.passenger_id
) AS countRatingPassengerFromDrivers,
(
    SELECT
        COUNT(*)
    FROM
        ride
    WHERE
        ride.driver_id = cm.driver_id
) countDriverRide,
(
    SELECT
        COUNT(*)
    FROM
        ride
    WHERE
        ride.passenger_id = cm.passenger_id
) countPassengerRide,
(
    SELECT
        COALESCE(SUM(amount),
        0) AS visaDriver
    FROM
        payments
    WHERE
        isGiven = 'waiting' AND `payment_method` IN(
            'visa-in',
            'visa',
            'visaRide',
            'TransferFrom',
            'payout',
            'TransferTo'
        ) AND payments.`driverID` = cm.driver_id
) AS driverVisa,
(
    SELECT
        COALESCE(SUM(amount),
        0) AS pointDriver
    FROM
        driverWallet dw
    WHERE
        dw.paymentMethod IN(
            'visa-in',
            'visa',
            'visaRide',
            'TransferFrom',
            'payout',
            'TransferTo'
        ) AND dw.`driverID` = cm.driver_id
) AS driverWallet,
(
    SELECT
        COALESCE(SUM(pw.balance),
        0)
    FROM
        passengerWallet pw
    WHERE
        pw.passenger_id = cm.passenger_id
) AS passengerWallet,
(
    SELECT
        token
    FROM
        driverToken
    WHERE
        driverToken.captain_id = cm.driver_id
) AS driverToken,
(
    SELECT
        token
    FROM
        tokens
    WHERE
        tokens.passengerID = cm.passenger_id
) AS passengerToken,
(
    SELECT
        COUNT(*)
    FROM
        complaint
    WHERE
        complaint.passenger_id = cm.passenger_id AND cm.complaint_type = 'Passenger'
) AS countOfComplaintFromPassenger,
(
    SELECT
        COUNT(*)
    FROM
        complaint
    WHERE
        complaint.driver_id = cm.driver_id AND cm.complaint_type = 'Driver'
) AS countOfComplaintFromDriver
FROM
    `complaint` cm
LEFT JOIN passengers p ON
    p.id = cm.`passenger_id`
LEFT JOIN driver d ON
    d.id = cm.driver_id
LEFT JOIN ride ON ride.id = cm.ride_id
left join payments on payments.rideId=cm.ride_id";
$stmt = $con->prepare($sql);
$stmt->execute();

if ($stmt->rowCount() > 0) {
    $row = $stmt->fetchAll(PDO::FETCH_ASSOC);

    foreach ($row as &$item) {
        if (isset($item['passengerName'])) {
            $item['passengerName'] = $encryptionHelper->decryptData($item['passengerName']);
        }
        if (isset($item['driverName'])) {
            $item['driverName'] = $encryptionHelper->decryptData($item['driverName']);
        }
        if (isset($item['gender'])) {
            $item['gender'] = $encryptionHelper->decryptData($item['gender']);
        }
        if (isset($item['driverToken'])) {
            $item['driverToken'] = $encryptionHelper->decryptData($item['driverToken']);
        }
        if (isset($item['passengerToken'])) {
            $item['passengerToken'] = $encryptionHelper->decryptData($item['passengerToken']);
        }
    }

    jsonSuccess($row);
} else {
    jsonError("No wallet record found");
}
?>

File: serviceapp/getDriverNotCompleteRegistration.php

<?php

require_once __DIR__ . '/../connect.php';

$sql = "SELECT 
    phone_verification.*,
    notesForDriverService.note
FROM 
    phone_verification
INNER JOIN -- نستخدم INNER JOIN لضمان جلب من لديهم ملاحظات فقط
    `notesForDriverService` 
ON 
    `notesForDriverService`.`phone` = `phone_verification`.`phone_number`
WHERE 
    `notesForDriverService`.`note` != 'delete'
ORDER BY 
    `phone_verification`.`created_at` DESC -- الترتيب حسب تاريخ التحقق لأنه العمود الموجود
LIMIT 400;
";

$stmt = $con->prepare($sql);
$stmt->execute();

if ($stmt->rowCount() > 0) {
    $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);

    // فك تشفير أرقام الهواتف فقط للإخراج
   foreach ($rows as &$row) {
        if (!empty($row['phone'])) {
            $row['phone'] = $encryptionHelper->decryptData($row['phone']);
        }
        if (!empty($row['email'])) {
            $row['email'] = $encryptionHelper->decryptData($row['email']);
        }
       if (isset($row['phone_number'])) {
        $row['phone_number'] = $encryptionHelper->decryptData($row['phone_number']);
    }
    }
 

    jsonSuccess($rows);
} else {
    jsonError("No Phone verified yet found");
}
?>

File: serviceapp/getPackages.php

<?php
require_once __DIR__ . '/../connect.php';
$sql = "
SELECT * FROM `packageInfo`
";

$stmt = $con->prepare($sql);
$stmt->execute();
$passenger_data = $stmt->fetchAll(PDO::FETCH_ASSOC);

if ($passenger_data) {
    // Print the passenger data as JSON
    jsonSuccess($data = $passenger_data);
} else {
    // Print a failure message
    jsonError($message = "No passenger data found");
}
?>

File: serviceapp/updateDriver.php

<?php
require_once __DIR__ . '/../connect.php';

// Retrieve driverID (allow 'id' or 'driverID')
$driverID = filterRequest("id") ?? filterRequest("driverID");
if (!$driverID) {
    jsonError("Driver ID is required");
    exit;
}

/* ---------------------------------------------------------
    DRIVER TABLE
--------------------------------------------------------- */
$driverFieldsAllowed = [
    "idn", "phone", "email", "password", "gender", "license_type",
    "national_number", "name_arabic", "issue_date", "expiry_date",
    "license_categories", "address", "licenseIssueDate", "status",
    "birthdate", "site", "first_name", "last_name", "accountBank",
    "bankCode", "employmentType", "maritalStatus", "fullNameMaritial",
    "expirationDate", "created_at", "updated_at"
];

// Fields that must be encrypted
$encryptedDriverFields = [
    "phone", "email", "password", "national_number","gender", "name_arabic", "first_name",
    "last_name", "birthdate", "site", "maritalStatus", "employmentType"
];

$driverSet = [];
$driverParams = [":id" => $driverID];

foreach ($driverFieldsAllowed as $field) {
    if (isset($_POST[$field]) && $_POST[$field] !== "") {
        $value = filterRequest($field);

        if (in_array($field, $encryptedDriverFields)) {
            $value = $encryptionHelper->encryptData($value);
        }

        $driverSet[] = "`$field` = :$field";
        $driverParams[":$field"] = $value;
    }
}

// Execute Driver Update
$driverUpdated = false;
if (!empty($driverSet)) {
    $driverSql = "UPDATE `driver` SET " . implode(", ", $driverSet) . " WHERE `id` = :id";
    $stmt = $con->prepare($driverSql);
    $stmt->execute($driverParams);
    $driverUpdated = $stmt->rowCount() > 0;
}

/* ---------------------------------------------------------
    CAR REGISTRATION TABLE
--------------------------------------------------------- */
$carFieldsAllowed = [
    "id", "vin", "car_plate", "make", "model", "year",
    "expiration_date", "color", "owner", "color_hex", "fuel",
    "isDefault", "created_at", "status"
];

$carSet = [];
$carParams = [":driverID" => $driverID];

foreach ($carFieldsAllowed as $field) {
    if ($field === "id") continue; // skip primary key in SET
    if (isset($_POST[$field]) && $_POST[$field] !== "") {
        $value = filterRequest($field);
        $carSet[] = "`$field` = :$field";
        $carParams[":$field"] = $value;
    }
}

// Execute Car Update
$carUpdated = false;
if (!empty($carSet)) {
    $carSql = "UPDATE `CarRegistration` SET " . implode(", ", $carSet) . " WHERE `driverID` = :driverID";
    $stmtCar = $con->prepare($carSql);
    $stmtCar->execute($carParams);
    $carUpdated = $stmtCar->rowCount() > 0;
}

/* ---------------------------------------------------------
    RESPONSE
--------------------------------------------------------- */
if ($driverUpdated || $carUpdated) {
    jsonSuccess(null, "Driver & Car updated successfully");
} else {
    jsonError("No changes were applied");
}
?>

File: serviceapp/getDriverByNational.php

<?php
require_once __DIR__ . '/../connect.php';

// 1. استقبال الرقم الوطني بدلاً من الهاتف
$national_number = filterRequest("national_number");

// 2. تشفير الرقم الوطني للمقارنة مع القيمة المشفرة في قاعدة البيانات
$encryptedNationalNumber = $encryptionHelper->encryptData($national_number); 

$sql = "SELECT
    COALESCE(
        (
        SELECT COUNT(*) FROM `ride` WHERE `ride`.`driver_id` = d.id
        ),
    0) AS countRide,
    
    COALESCE(
        (
        SELECT AVG(`ratingDriver`.`rating`)
        FROM ratingDriver
        WHERE `ratingDriver`.`driver_id` = d.id
        ),
    0) AS rating,
    
    COALESCE(
        (
        SELECT SUM(pd.amount)
        FROM `payments` pd
        WHERE pd.driverID = d.id
        ),
    0) AS totalPayment,

    COALESCE(
        (
        SELECT SUM(dw.amount)
        FROM `driverWallet` dw
        WHERE dw.driverID = d.id
        ),
    0) AS totalDriverWallet,

    COALESCE(
        (
        SELECT COUNT(*)
        FROM complaint
        WHERE complaint.driver_id = d.id
        ),
    0) AS countComplaint,

    COALESCE(
        (
        SELECT COUNT(*)
        FROM driver_ride_scam scam
        WHERE scam.driverID = d.id
        ),
    0) AS countScam,

    COALESCE(
        (
        SELECT complaint.description
        FROM complaint
        WHERE complaint.driver_id = d.id
        ORDER BY complaint.date_resolved DESC
        LIMIT 1
        ),
    ''
    ) AS complaint,

    COALESCE(
        (
        SELECT COUNT(*)
        FROM ratingPassenger
        WHERE ratingPassenger.driverID = d.id
        ),
    0) AS DRatingPassengersCount,

    COALESCE(
        (
        SELECT AVG(ratingPassenger.rating)
        FROM ratingPassenger
        WHERE ratingPassenger.driverID = d.id
        ),
    0) AS avgDRatingPassenger,

    cr.*,
    d.*
FROM driver d
LEFT JOIN CarRegistration cr ON cr.driverID = d.id
WHERE d.national_number = :national_number; 
"; 
// 3. تم تعديل الشرط أعلاه للبحث بالرقم الوطني

$stmt = $con->prepare($sql);
// 4. ربط الباراميتر الجديد
$stmt->bindParam(':national_number', $encryptedNationalNumber);
$stmt->execute();

if ($stmt->rowCount() > 0) {
    $row = $stmt->fetchAll(PDO::FETCH_ASSOC);

    // فك تشفير الحقول المهمة
    foreach ($row as &$r) {
        if (isset($r['phone'])) $r['phone'] = $encryptionHelper->decryptData($r['phone']);
        if (isset($r['email'])) $r['email'] = $encryptionHelper->decryptData($r['email']);
        if (isset($r['first_name'])) $r['first_name'] = $encryptionHelper->decryptData($r['first_name']);
        if (isset($r['last_name'])) $r['last_name'] = $encryptionHelper->decryptData($r['last_name']);
        if (isset($r['gender'])) $r['gender'] = $encryptionHelper->decryptData($r['gender']);
        if (isset($r['birthdate'])) $r['birthdate'] = $encryptionHelper->decryptData($r['birthdate']);
        if (isset($r['site'])) $r['site'] = $encryptionHelper->decryptData($r['site']);
        if (isset($r['name_arabic'])) $r['name_arabic'] = $encryptionHelper->decryptData($r['name_arabic']);
        if (isset($r['national_number'])) $r['national_number'] = $encryptionHelper->decryptData($r['national_number']);
        if (isset($r['maritalStatus'])) $r['maritalStatus'] = $encryptionHelper->decryptData($r['maritalStatus']);
        if (isset($r['sosPhone'])) $r['sosPhone'] = $encryptionHelper->decryptData($r['sosPhone']);
        if (isset($r['car_plate'])) $r['car_plate'] = $encryptionHelper->decryptData($r['car_plate']);
        if (isset($r['owner'])) $r['owner'] = $encryptionHelper->decryptData($r['owner']);
        if (isset($r['address'])) $r['address'] = $encryptionHelper->decryptData($r['address']);
        if (isset($r['vin'])) $r['vin'] = $encryptionHelper->decryptData($r['vin']);
        unset($r['password']);
    }

    jsonSuccess($row);
} else {
    // يمكنك تعديل الرسالة لتكون "No driver found" بدلاً من wallet record
    jsonError("No record found for this national number");
}
?>

File: serviceapp/getEditorStatsCalls.php

<?php
require_once __DIR__ . '/../connect.php';

error_reporting(0);
header('Content-Type: application/json');

// 1. استقبال التواريخ
if (isset($_POST['start_date']) && isset($_POST['end_date'])) {
    $start_date = $_POST['start_date'];
    $end_date   = $_POST['end_date'];
} else {
    // Fallback: الافتراضي هو الشهر الحالي
    $current_month = isset($_POST['month']) ? str_pad($_POST['month'], 2, "0", STR_PAD_LEFT) : date('m');
    $current_year  = isset($_POST['year'])  ? $_POST['year']  : date('Y');
    
    $start_date = date('Y-m-d', strtotime($current_year . '-' . $current_month . '-01'));
    $end_date   = date('Y-m-t', strtotime($start_date));
}

// 2. الاستعلام: تجميع عدد الملاحظات لكل موظف في كل يوم
// نستخدم DATE(createdAt) لتوحيد التوقيت لليوم فقط
$sql = "
    SELECT 
        DATE(createdAt) as date, 
        editor as NAME, 
        COUNT(*) as count 
    FROM 
        notesForDriverService 
    WHERE 
        createdAt BETWEEN '$start_date' AND '$end_date 23:59:59'
    GROUP BY 
        DATE(createdAt), editor
    ORDER BY 
        date ASC
";

try {
    $stmt = $con->prepare($sql);
    $stmt->execute();
    $data = $stmt->fetchAll(PDO::FETCH_ASSOC);

    if ($data) {
        echo json_encode(array("status" => "success", "message" => $data));
    } else {
        echo json_encode(array("status" => "success", "message" => []));
    }
} catch (PDOException $e) {
    echo json_encode(array("status" => "failure", "message" => $e->getMessage()));
}
?>

File: serviceapp/editCarPlate.php

<?php
require_once __DIR__ . '/../connect.php';

// استرجاع وتصفية البيانات
$driverId = filterRequest("driverId");
$carPlate = $encryptionHelper->encryptData(filterRequest("carPlate"));
$color = filterRequest("color");
$color_hex = filterRequest("color_hex");
$make = filterRequest("make");
$model = filterRequest("model");
$expiration_date = filterRequest("expiration_date");
$owner = $encryptionHelper->encryptData(filterRequest("owner"));
$year = filterRequest("year");
$employee = filterRequest("employee");

// تحديث CarRegistration
$sqlUpdate = "
    UPDATE `CarRegistration`
    SET
        `car_plate` = :carPlate,
        `color` = :color,
        `color_hex` = :color_hex,
        `make` = :make,
        `model` = :model,
        `year` = :year,
        `expiration_date` = :expiration_date,
        `owner` = :owner
    WHERE `driverID` = :driverId";

$stmtUpdate = $con->prepare($sqlUpdate);
$stmtUpdate->execute([
    ':carPlate' => $carPlate,
    ':color' => $color,
    ':color_hex' => $color_hex,
    ':make' => $make,
    ':model' => $model,
    ':year' => $year,
    ':expiration_date' => $expiration_date,
    ':owner' => $owner,
    ':driverId' => $driverId
]);

if ($stmtUpdate->rowCount() > 0) {
    // تسجيل التعديل
    $sqlInsert = "INSERT INTO `carPlateEdit`
        (`driverId`, `carPlate`, `color`, `make`, `model`, `expiration_date`, `owner`, `year`, `employee`, `isEdit`)
        VALUES (:driverId, :carPlate, :color, :make, :model, :expiration_date, :owner, :year, :employee, 1)";
    $stmtInsert = $con->prepare($sqlInsert);
    $stmtInsert->execute([
        ':driverId' => $driverId,
        ':carPlate' => $carPlate,
        ':color' => $color,
        ':make' => $make,
        ':model' => $model,
        ':expiration_date' => $expiration_date,
        ':owner' => $owner,
        ':year' => $year,
        ':employee' => $employee
    ]);

    jsonSuccess(null, "Car data updated and edit logged successfully.");
} else {
    jsonError("No changes were made to the car data.");
}

File: serviceapp/getPassengersByPhone.php

<?php
require_once __DIR__ . '/../connect.php';

// استلام الرقم وتشفيره
$phone = filterRequest("phone");
$phoneEncrypted = $encryptionHelper->encryptData($phone);

$sql = "SELECT 
    p.*,
    COALESCE(r.id, 0) AS ride_id,
    COALESCE(r.start_location, '') AS start_location,
    COALESCE(r.end_location, '') AS end_location,
    COALESCE(r.date, '1970-01-01') AS ride_date,
    COALESCE(r.time, '00:00:00') AS ride_time,
    COALESCE(r.endtime, '00:00:00') AS ride_endtime,
    COALESCE(r.price, 0) AS price,
    COALESCE(r.passenger_id, 0) AS ride_passenger_id,
    COALESCE(r.driver_id, 0) AS driver_id,
    COALESCE(r.status, '') AS ride_status,
    COALESCE(r.paymentMethod, '') AS ride_payment_method,
    COALESCE(r.carType, '') AS car_type,
    COALESCE(r.created_at, '1970-01-01 00:00:00') AS ride_created_at,
    COALESCE(r.updated_at, '1970-01-01 00:00:00') AS ride_updated_at,
    COALESCE(r.DriverIsGoingToPassenger, 0) AS driver_is_going_to_passenger,
    COALESCE(r.rideTimeStart, '1970-01-01 00:00:00') AS ride_time_start,
    COALESCE(r.rideTimeFinish, '1970-01-01 00:00:00') AS ride_time_finish,
    COALESCE(r.price_for_driver, 0) AS price_for_driver,
    COALESCE(r.price_for_passenger, 0) AS price_for_passenger,
    COALESCE(r.distance, 0) AS distance,
    COALESCE(pw.balance, 0) AS passenger_wallet_balance,
    COALESCE(pay.amount, 0) AS passenger_payment_amount,
    COALESCE(pay.payment_method, '') AS passenger_payment_method,
    COALESCE(dw.amount, 0) AS driver_payment_amount,
    COALESCE(dw.paymentMethod, '') AS driver_payment_method
FROM 
    passengers p
LEFT JOIN 
    ride r ON p.id = r.passenger_id
LEFT JOIN 
    passengerWallet pw ON p.id = pw.passenger_id
LEFT JOIN 
    payments pay ON r.id = pay.rideId
LEFT JOIN 
    driverWallet dw ON r.driver_id = dw.driverID AND pay.id = dw.paymentID
WHERE 
    p.phone = :phone
    AND r.id = (
        SELECT id 
        FROM ride 
        WHERE passenger_id = p.id 
        ORDER BY date DESC, time DESC 
        LIMIT 1
    )";

$stmt = $con->prepare($sql);
$stmt->bindParam(':phone', $phoneEncrypted);
$stmt->execute();

if ($stmt->rowCount() > 0) {
    $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);

    // فك التشفير للحقول الحساسة
    foreach ($rows as &$row) {
        if (isset($row['phone']))         $row['phone'] = $encryptionHelper->decryptData($row['phone']);
        if (isset($row['email']))         $row['email'] = $encryptionHelper->decryptData($row['email']);
        if (isset($row['gender']))        $row['gender'] = $encryptionHelper->decryptData($row['gender']);
        if (isset($row['birthdate']))     $row['birthdate'] = $encryptionHelper->decryptData($row['birthdate']);
        if (isset($row['site']))          $row['site'] = $encryptionHelper->decryptData($row['site']);
        if (isset($row['first_name']))    $row['first_name'] = $encryptionHelper->decryptData($row['first_name']);
        if (isset($row['last_name']))     $row['last_name'] = $encryptionHelper->decryptData($row['last_name']);
        if (isset($row['employmentType']))$row['employmentType'] = $encryptionHelper->decryptData($row['employmentType']);
        if (isset($row['maritalStatus'])) $row['maritalStatus'] = $encryptionHelper->decryptData($row['maritalStatus']);
       unset($r['password']);
    }

    jsonSuccess($rows);
} else {
    jsonError("No wallet record found");
}
?>

File: serviceapp/addNotesPassenger.php

<?php

require_once __DIR__ . '/../connect.php';

// Retrieve and sanitize input parameters
$phone = filterRequest("phone");
$note = filterRequest("note");
$editor = filterRequest("editor");

// Encrypt phone before storing
$encryptedPhone = $encryptionHelper->encryptData($phone);

// SQL query to insert into notesForPassengerService
$sql = "INSERT INTO `notesForPassengerService` (`phone`, `note`, `editor`) 
        VALUES (:phone, :note, :editor)";

// Prepare the statement
$stmt = $con->prepare($sql);
$stmt->bindParam(':phone', $encryptedPhone);
$stmt->bindParam(':note', $note);
$stmt->bindParam(':editor', $editor);

// Execute and respond
$stmt->execute();

if ($stmt->rowCount() > 0) {
    jsonSuccess(null, "Note inserted successfully");
} else {
    jsonError("Failed to insert note");
}
?>

File: serviceapp/updateDriverToActive.php

<?php

// --- تضمين الملفات الأساسية ---
require_once __DIR__ . '/../connect.php'; // يفترض أن يحتوي على الاتصال ومساعد التشفير

// --- استقبال البيانات من التطبيق ---
$driverId = filterRequest("driverId");
$phone = filterRequest("phone"); // استقبال رقم الهاتف مباشرة

// --- بيانات جدول السائق (driver) ---
$firstName = filterRequest("first_name");
$lastName = filterRequest("last_name");
$site = filterRequest("site"); // مكان القيد/الولادة
$nationalNumber = filterRequest("national_number");
$licenseCategories = filterRequest("license_categories"); // فئة الرخصة
$expiryDate = filterRequest("expiry_date"); // تاريخ انتهاء رخصة السائق
$licenseIssueDate = filterRequest("license_issue_date");
$gender = filterRequest("gender"); // الحقل الجديد
$birthdate = filterRequest("birthdate"); // الحقل الجديد
$maritalStatus=filterRequest("maritalStatus");

// --- بيانات جدول السيارة (CarRegistration) ---
$owner = filterRequest("owner");
$color = filterRequest("color");
$colorHex = filterRequest("color_hex");
$model = filterRequest("model"); // الموديل
$carPlate = filterRequest("car_plate");
$make = filterRequest("make"); // الصانع
$fuel = filterRequest("fuel");
$year = filterRequest("year");
$carExpirationDate = filterRequest("expiration_date"); // تاريخ انتهاء رخصة السيارة

// --- بدء المعاملة لضمان سلامة البيانات ---
$con->beginTransaction();

try {
    // --- 1. معالجة وتشفير البيانات ---
    $nameArabic = $firstName . ' ' . $lastName;
    $address = $site;

    // تشفير الحقول الحساسة
    $encryptedFirstName = $encryptionHelper->encryptData($firstName);
    $encryptedLastName = $encryptionHelper->encryptData($lastName);
    $encryptedSite = $encryptionHelper->encryptData($site);
    $encryptedAddress = $encryptionHelper->encryptData($address);
    $encryptedNameArabic = $encryptionHelper->encryptData($nameArabic);
    $encryptedNationalNumber = $encryptionHelper->encryptData($nationalNumber);
    $encryptedOwner = $encryptionHelper->encryptData($owner);
    $encryptedCarPlate = $encryptionHelper->encryptData($carPlate);
    $encryptedBirthdate = $encryptionHelper->encryptData($birthdate);
    $encryptedGender = $encryptionHelper->encryptData($gender);

    // --- 2. تحديث جدول السائق ---
    $sqlDriver = "UPDATE `driver` SET
                    `first_name` = :first_name,
                    `last_name` = :last_name,
                    `site` = :site,
                    `address` = :address,
                    `national_number` = :national_number,
                    `license_categories` = :license_categories,
                    `expiry_date` = :expiry_date,
                    `issue_date` = :issue_date,
                    `gender` = :gender,
                    `birthdate` = :birthdate,
                    `name_arabic` = :name_arabic,
                    `maritalStatus` = :maritalStatus,
                    `status` = 'actives'
                  WHERE `id` = :driverId";

    $stmtDriver = $con->prepare($sqlDriver);
    $stmtDriver->execute([
        ':first_name' => $encryptedFirstName,
        ':last_name' => $encryptedLastName,
        ':site' => $encryptedSite,
        ':address' => $encryptedAddress,
        ':national_number' => $encryptedNationalNumber,
        ':license_categories' => $licenseCategories,
        ':expiry_date' => $expiryDate,
        ':issue_date' => $licenseIssueDate,
        ':gender' => $encryptedGender,
        ':birthdate' => $encryptedBirthdate,
        ':name_arabic' => $encryptedNameArabic,
        ':driverId' => $driverId,
        ':maritalStatus' =>$maritalStatus
    ]);

    // --- 3. تحديث جدول السيارة ---
    $sqlCar = "UPDATE `CarRegistration` SET
                   `owner` = :owner,
                   `color` = :color,
                   `color_hex` = :color_hex,
                   `model` = :model,
                   `car_plate` = :car_plate,
                   `make` = :make,
                   `fuel` = :fuel,
                   `year` = :year,
                   `expiration_date` = :expiration_date
                 WHERE `driverID` = :driverId";

    $stmtCar = $con->prepare($sqlCar);
    $stmtCar->execute([
        ':owner' => $encryptedOwner,
        ':color' => $color,
        ':color_hex' => $colorHex,
        ':model' => $model,
        ':car_plate' => $encryptedCarPlate,
        ':make' => $make,
        ':fuel' => $fuel,
        ':year' => $year,
        ':expiration_date' => $carExpirationDate,
        ':driverId' => $driverId
    ]);

    // --- 4. تأكيد المعاملة ---
    $con->commit();
    jsonSuccess(["message" => "Driver and car data updated successfully."]);

    // --- 5. إرسال رسالة واتساب مبسطة وآمنة (باختيار رقم عشوائي) ---
    
    // 5.1. تعريف الأرقام
    $supportPhones = ['0952475740', '0952475742']; // يمكنك إضافة المزيد من الأرقام هنا
    
    // 5.2. اختيار رقم عشوائي من القائمة
    $randomIndex = array_rand($supportPhones); // يختار "مفتاح" عشوائي (index)
    $phoneToUse = $supportPhones[$randomIndex]; // يحصل على الرقم من المفتاح

    
    // --- !!! التعديل: إضافة رقم عشوائي ---
    // هذا يضيف رقم عشوائي (4-6 خانات) لجعل الرسالة فريدة
    $randomNumber = rand(1000, 999999); 

    // 5.5. إعداد نص الرسالة بالرقم المتغير
    $messageBody = "أهلاً وسهلاً كابتن $firstName 👋\n"
                 . "تم تفعيل حسابك على تطبيق *سيرو*.\n"
                 . "يمكنك الآن تسجيل الدخول والبدء بالعمل مباشرة.\n"
                 . "للمساعدة تواصل معنا على الرقم: $phoneToUse\n" // <-- تم استخدام المتغير العشوائي هنا
                 . "نتمنى لك عمل موفق 🚖\n\n"
                 . "معرف الرسالة: $randomNumber"; // <-- إضافة الرقم العشوائي

    // 5.6. إرسال الرسالة
    sendWhatsAppFromServer($phone, $messageBody);

} catch (Exception $e) {
    // --- 6. التراجع في حال الخطأ ---
    $con->rollBack();
    jsonError("An error occurred: " . $e->getMessage());
}

?>


File: serviceapp/getNewDriverRegister.php

<?php

require_once __DIR__ . '/../connect.php';

$sql = "SELECT
    d.id,
    d.phone,
    d.email,
    d.gender,
    d.license_type,
    d.national_number,
    d.name_arabic,
    d.issue_date,
    d.expiry_date,
    d.license_categories,
    d.address,
    d.status,
    d.birthdate,
    d.site,
    d.first_name,
    d.last_name,
    d.accountBank,
    d.bankCode,
    d.employmentType,
    d.maritalStatus,
    d.fullNameMaritial,
    d.expirationDate,
    d.created_at,
    d.updated_at,
    wdc.id AS welcomId,
    wdc.isCall,
    wdc.notes,
    wdc.createdAt AS welcomeCreatedAt
FROM
    driver d
LEFT JOIN welcomeDriverCall wdc ON
    wdc.driverId = d.id
WHERE
	d.status='actives' and
    d.created_at BETWEEN DATE_SUB(CURDATE(), INTERVAL 2 DAY) AND CURDATE() + INTERVAL 2 DAY
ORDER BY
    d.created_at DESC;


";
$stmt = $con->prepare($sql);
$stmt->execute();

if ($stmt->rowCount() > 0) {
  // Fetch the records
  $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);

// فك التشفير للحقول الحساسة
foreach ($rows as &$row) {
    $row['phone']           = $encryptionHelper->decryptData($row['phone']);
    $row['email']           = $encryptionHelper->decryptData($row['email']);
    $row['gender']          = $encryptionHelper->decryptData($row['gender']);
    $row['birthdate']       = $encryptionHelper->decryptData($row['birthdate']);
  	$row['national_number'] = $encryptionHelper->decryptData($row['national_number']);
    $row['site']            = $encryptionHelper->decryptData($row['site']);
    $row['first_name']      = $encryptionHelper->decryptData($row['first_name']);
    $row['last_name']       = $encryptionHelper->decryptData($row['last_name']);
   // $row['employmentType']  = $encryptionHelper->decryptData($row['employmentType']);
   // $row['maritalStatus']   = $encryptionHelper->decryptData($row['maritalStatus']);
}

jsonSuccess($rows);
} else {
  // Print a failure message
  jsonError($message = "No Phone verified yet found");
}

?>

File: serviceapp/getPassengersNotCompleteRegistration.php

<?php
require_once __DIR__ . '/../connect.php';

// استعلام رئيسي مع ربط صحيح وتشفير رقم الهاتف
$sql = "SELECT
    phone_verification_passenger.*,
    notesForPassengerService.note,
    notesForPassengerService.editor,
    notesForPassengerService.createdAt AS note_created_at
FROM
    phone_verification_passenger
LEFT JOIN notesForPassengerService 
    ON notesForPassengerService.phone = phone_verification_passenger.phone_number
WHERE
    phone_verification_passenger.phone_number NOT IN (
        SELECT phone FROM passengers WHERE phone IS NOT NULL
    )
    AND phone_verification_passenger.created_at >= DATE_SUB(CURDATE(), INTERVAL 4 DAY)
ORDER BY
    phone_verification_passenger.created_at DESC
LIMIT 25;
";

$stmt = $con->prepare($sql);
$stmt->execute();

$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);

// فك التشفير إذا كان مطلوباً (مثلاً إذا phone_number مشفّر)
foreach ($rows as &$row) {
    if (isset($row['phone_number'])) {
        $row['phone_number'] = $encryptionHelper->decryptData($row['phone_number']);
    }
    if (isset($row['note'])) {
        $row['note'] = $encryptionHelper->decryptData($row['note']); // إذا كانت مضافة مشفّرة
    }
}

if ($rows) {
    jsonSuccess($rows);
} else {
    jsonError("No phone verified passengers found");
}
?>

File: serviceapp/updatePackages.php

<?php
require_once __DIR__ . '/../connect.php';

// Get 'id' and 'version' from the request
$id = filterRequest("id");
$version = filterRequest("version");



$sql = "UPDATE `packageInfo` SET `version` ='$version'  WHERE `id` = '$id'";

// Prepare and execute the statement
$stmt = $con->prepare($sql);
$stmt->execute();
error_log("Updating package: ID = $sql, Version = $version");


// Debugging: Check if the query affected any rows
if ($stmt->rowCount() > 0) {
    // If rows were affected, print success
    echo json_encode(['status' => 'success', 'message' => "Package version updated successfully for ID $id"]);
} else {
    // If no rows were affected, print failure and debug the query
    echo json_encode(['status' => 'failure', 'message' => "Failed to update package version. No rows affected. ID: $id, Version: $version"]);
}
?>

File: serviceapp/addCartoDriver.php

<?php

require_once __DIR__ . '/../connect.php';

// Fetch and validate each parameter
$driverID = filterRequest("driverID");
$vin = $encryptionHelper->encryptData(filterRequest("vin"));
$carPlate = $encryptionHelper->encryptData(filterRequest("car_plate"));
$make = filterRequest("make");
$model = filterRequest("model");
$year = filterRequest("year");
$expirationDate = filterRequest("expiration_date");
$color = filterRequest("color");
$owner = $encryptionHelper->encryptData(filterRequest("owner"));
$colorHex = filterRequest("color_hex");
$address = $encryptionHelper->encryptData(filterRequest("address"));
$displacement = filterRequest("displacement");
$fuel = filterRequest("fuel");
$registrationDate = filterRequest("registration_date");

// تحقق من الحقول المطلوبة
if (
    is_null($driverID) || is_null($vin) || is_null($carPlate) ||
    is_null($make) || is_null($model) || is_null($year) ||
    is_null($expirationDate) || is_null($color) || is_null($owner) ||
    is_null($colorHex) || is_null($address) || is_null($displacement) ||
    is_null($fuel) || is_null($registrationDate)
) {
    jsonError("One or more required parameters are missing.");
    exit();
}

$con->beginTransaction();

try {
    $checkSql = "SELECT * FROM `CarRegistration` WHERE `driverID` = :driverID";
    $checkStmt = $con->prepare($checkSql);
    $checkStmt->bindParam(':driverID', $driverID);
    $checkStmt->execute();

    if ($checkStmt->rowCount() > 0) {
        jsonError("Car has already been registered for this driver.");
        exit();
    }

    // إدخال السيارة
    $sqlInsert = "INSERT INTO `CarRegistration` (
        `driverID`, `vin`, `car_plate`, `make`, `model`, `year`, `expiration_date`, 
        `color`, `owner`, `color_hex`, `address`, `displacement`, `fuel`, `registration_date`
    ) VALUES (
        :driverID, :vin, :carPlate, :make, :model, :year, :expirationDate,
        :color, :owner, :colorHex, :address, :displacement, :fuel, :registrationDate
    )";

    $stmtInsert = $con->prepare($sqlInsert);
    $stmtInsert->bindParam(':driverID', $driverID);
    $stmtInsert->bindParam(':vin', $vin);
    $stmtInsert->bindParam(':carPlate', $carPlate);
    $stmtInsert->bindParam(':make', $make);
    $stmtInsert->bindParam(':model', $model);
    $stmtInsert->bindParam(':year', $year);
    $stmtInsert->bindParam(':expirationDate', $expirationDate);
    $stmtInsert->bindParam(':color', $color);
    $stmtInsert->bindParam(':owner', $owner);
    $stmtInsert->bindParam(':colorHex', $colorHex);
    $stmtInsert->bindParam(':address', $address);
    $stmtInsert->bindParam(':displacement', $displacement);
    $stmtInsert->bindParam(':fuel', $fuel);
    $stmtInsert->bindParam(':registrationDate', $registrationDate);

    $stmtInsert->execute();

    if ($stmtInsert->rowCount() > 0) {
        // سجل في carPlateEdit
        $sqlLog = "INSERT INTO `carPlateEdit` 
            (`driverId`, `carPlate`, `color`, `make`, `model`, `expiration_date`, `owner`, `year`, `isEdit`)
            VALUES (:driverID, :carPlate, :color, :make, :model, :expirationDate, :owner, :year, 0)";
        
        $stmtLog = $con->prepare($sqlLog);
        $stmtLog->bindParam(':driverID', $driverID);
        $stmtLog->bindParam(':carPlate', $carPlate);
        $stmtLog->bindParam(':color', $color);
        $stmtLog->bindParam(':make', $make);
        $stmtLog->bindParam(':model', $model);
        $stmtLog->bindParam(':expirationDate', $expirationDate);
        $stmtLog->bindParam(':owner', $owner);
        $stmtLog->bindParam(':year', $year);

        $stmtLog->execute();

        $con->commit();
        jsonSuccess(null, "Car registration data saved and logged successfully");
    } else {
        $con->rollBack();
        jsonError("Failed to save car registration data");
    }
} catch (Exception $e) {
    $con->rollBack();
    jsonError("An error occurred: " . $e->getMessage());
}
?>

File: serviceapp/addWelcomeDriverNote.php

<?php

require_once __DIR__ . '/../connect.php';

// Sanitize and retrieve input parameters
$driverId = filterRequest("driverId");
$notes = filterRequest("notes");

// SQL: Insert or Update if already exists
$sql = "INSERT INTO `welcomeDriverCall` (`driverId`, `isCall`, `notes`) 
        VALUES (:driverId, '1', :notes)
        ON DUPLICATE KEY UPDATE 
            `isCall` = '1',
            `notes` = VALUES(`notes`),
            `createdAt` = NOW()";

// Prepare the statement
$stmt = $con->prepare($sql);

// Bind parameters
$stmt->bindParam(':driverId', $driverId);
$stmt->bindParam(':notes', $notes);

// Execute the statement
$success = $stmt->execute();

if ($success) {
    jsonSuccess(null, "Record inserted/updated successfully");
} else {
    jsonError("Failed to insert or update record");
}

?>

File: serviceapp/drivers_list.txt

Phone: 963995473295 | Note: No Note
Phone: 963932997741 | Note: No Note
Phone: 963946792550 | Note: No Note
Phone:  | Note: لا يوجد رقم
Phone: 963930124895 | Note: No Note
Phone: 963932845375 | Note: No Note
Phone: 9630937563437 | Note: No Note
Phone: 963937563437 | Note: No Note
Phone: 963933014381 | Note: No Note
Phone: 963940740211 | Note: No Note
Phone: 963997731147 | Note: No Note
Phone: 9630982494498 | Note: No Note
Phone: 963982494498 | Note: No Note
Phone: 963936780435 | Note: No Note
Phone: 963932894042 | Note: No Note
Phone: 963955609157 | Note: No Note
Phone: 963943433943 | Note: No Note
Phone: 963934020587 | Note: No Note
Phone: 963991486923 | Note: No Note
Phone: 963930246282 | Note: No Note
Phone: 963936388893 | Note: No Note
Phone: 963965444917 | Note: No Note
Phone: 963968622928 | Note: No Note
Phone: 963941588818 | Note: No Note
Phone: 9630941588818 | Note: No Note
Phone: 963998557963 | Note: No Note
Phone: 963995737121 | Note: ماعندو واتس وخطو مسكر
Phone: 963996673522 | Note: No Note
Phone: 963992159193 | Note: No Note
Phone: 963933231038 | Note: No Note
Phone: 963990320212 | Note: تم
Phone: 963991918177 | Note: No Note
Phone: 963962293692 | Note: No Note
Phone: 963980043065 | Note: No Note
Phone: 963933665775 | Note: No Note
Phone: 963997678811 | Note: No Note
Phone: 963935541277 | Note: No Note
Phone: 963937173449 | Note: تم
Phone: 963998235145 | Note: No Note
Phone: 963991514602 | Note: No Note
Phone: 963993725589 | Note: No Note
Phone: 963939761870 | Note: No Note
Phone: 963956825657 | Note: No Note
Phone: 963933642491 | Note: No Note
Phone: 963956906783 | Note: No Note
Phone: 9630956906783 | Note: No Note
Phone: 9630936984029 | Note: No Note
Phone: 963941418151 | Note: No Note
Phone: 9630941418151 | Note: No Note
Phone: 963981237272 | Note: No Note
Phone: 963933897890 | Note: No Note
Phone: 963944344937 | Note: No Note
Phone: 963993828902 | Note: No Note
Phone: 963933659200 | Note: No Note
Phone: 963955414963 | Note: No Note
Phone: 963942024560 | Note: No Note
Phone: 9639494022840 | Note: No Note
Phone: 9639639362485 | Note: No Note
Phone: 963965833448 | Note: مشغول
Phone: 9630930291349 | Note: بدو يفعل
Phone: 963945267161 | Note: تم
Phone: 9630934627741 | Note: No Note
Phone: 963934627741 | Note: No Note
Phone: 963935777840 | Note: No Note
Phone: 963994436621 | Note: No Note
Phone: 963940031237 | Note: No Note
Phone: 963957833531 | Note: No Note
Phone: 963943949925 | Note: No Note
Phone: 963953263161 | Note: ما برن
Phone: 963980486635 | Note: No Note
Phone: 963٩٩٢٩٩٩٠٨٣ | Note: No Note
Phone: 963950505715 | Note: No Note
Phone: 963934443912 | Note: كان بدو يشتري سيارة وفقست بس يكفي رح يسجل
Phone: 963945452222 | Note: رح يكفي تسجيل
Phone: 963948899644 | Note: No Note
Phone: 963937525133 | Note: رح يكفي تسجيل
Phone: 963934441423 | Note: No Note
Phone: 963968044972 | Note: تم التواصل
Phone: 963984137014 | Note: مابدو
Phone: 963796377987 | Note: No Note
Phone: 963988455623 | Note: No Note
Phone: 9630939386057 | Note: No Note
Phone: 963939386057 | Note: No Note
Phone: 963966880940 | Note: تم
Phone: 963932928765 | Note: تم
Phone: 963993641405 | Note: تم
Phone: 963933027735 | Note: No Note
Phone: 963933433725 | Note: تم
Phone: 963988870417 | Note: تم
Phone: 963951670237 | Note: تم
Phone: 963930795196 | Note: تم
Phone: 963991960766 | Note: تم
Phone: 963935998441 | Note: تم
Phone: 963947938918 | Note: تم
Phone: 963992435599 | Note: تم
Phone: 963954364865 | Note: تم
Phone: 963995438666 | Note: تم
Phone: 963991420279 | Note: تم
Phone: 963933969836 | Note: تم
Phone: 963095874505 | Note: الرقم خطأ
Phone: 963933586167 | Note: تم
Phone: 963997791974 | Note: تم
Phone: 963938092584 | Note: تم
Phone: 963936412209 | Note: تم
Phone: 963993998201 | Note: تم
Phone: 963954845028 | Note: No Note
Phone: 963985472276 | Note: No Note
Phone: 963983727779 | Note: تم
Phone: 963935005982 | Note: تم
Phone: 963996095507 | Note: No Note
Phone: 963993952009 | Note: تم
Phone: 9630993952009 | Note: No Note
Phone: 963940056304 | Note: تم
Phone: 963995797246 | Note: تم
Phone: 963993492062 | Note: No Note
Phone: 963988493310 | Note: تم
Phone: 971567312720 | Note: No Note
Phone: 963991748590 | Note: تم
Phone: 963996807389 | Note: تم
Phone: 963933624099 | Note: تم
Phone: 963981997355 | Note: تم
Phone: 9630983758855 | Note: تم
Phone: 963986198636 | Note: No Note
Phone: 963932392061 | Note: No Note
Phone: 963944087759 | Note: No Note
Phone: 9630944087759 | Note: No Note
Phone: 963996489269 | Note: No Note
Phone: 963956465908 | Note: No Note
Phone: 963937829076 | Note: No Note
Phone: 963952398851 | Note: No Note
Phone: 963947785627 | Note: No Note
Phone: 963944725825 | Note: No Note
Phone: 963985041549 | Note: No Note
Phone: 963992485425 | Note: No Note
Phone: 963990462939 | Note: No Note
Phone: 963997451873 | Note: No Note
Phone: 9630992952235 | Note: No Note
Phone: 963991543059 | Note: No Note
Phone: 963938800414 | Note: No Note
Phone: 963955915110 | Note: No Note
Phone: 963933436896 | Note: No Note
Phone: 963962203899 | Note: No Note
Phone: 963980561370 | Note: No Note
Phone: 963938449446 | Note: No Note
Phone: 963933989564 | Note: No Note
Phone: 963952726606 | Note: No Note
Phone: 963954152143 | Note: No Note
Phone: 963095272660 | Note: No Note
Phone: 963985131776 | Note: No Note
Phone: 963093184436 | Note: No Note
Phone: 963933751093 | Note: No Note
Phone: 963937475542 | Note: No Note
Phone: 963944619801 | Note: No Note
Phone: 963994776559 | Note: No Note
Phone: 963931802363 | Note: No Note
Phone: 963986312807 | Note: No Note
Phone: 963933502898 | Note: No Note
Phone: 963992667679 | Note: No Note
Phone: 963988514496 | Note: No Note
Phone: 963954251613 | Note: No Note
Phone: 963955630089 | Note: No Note
Phone: 963096491319 | Note: رقم غلط
Phone: 963999352010 | Note: تم
Phone: 963997823542 | Note: No Note
Phone: 963935561540 | Note: No Note
Phone: 963991907984 | Note: تم التواصل
Phone: 963963992952 | Note: غير موضوع بالخدمة
Phone: 919154792561 | Note: غلط
Phone: 963095371707 | Note: غير صحيح
Phone: 963964701914 | Note: تم
Phone: 963991175918 | Note: No Note
Phone: 963962215103 | Note: تم
Phone: 963099295223 | Note: خطأ
Phone: 963990368364 | Note: تم التواصل
Phone: 963931447359 | Note: No Note
Phone: 963994875810 | Note: تم التواصل
Phone: 963998047263 | Note: تم التواصل
Phone: 963988892598 | Note: تم التواصل
Phone: 963996136343 | Note: تم التواصل
Phone: 963934245841 | Note: تم التواصل
Phone: 963933944881 | Note: تم التواصل
Phone: 963993484762 | Note: تم التواصل
Phone: 963997386925 | Note: تم التواصل
Phone: 963955300562 | Note: تم التواصل
Phone: 963099123427 | Note: الرقم خطأ
Phone: 963998752835 | Note: تم التواصل
Phone: 963986164501 | Note: تم التواصل
Phone: 963994221981 | Note: تم
Phone: 963985111107 | Note: تم
Phone: 963965665584 | Note: تم
Phone: 963093309389 | Note: الرقم خطأ
Phone: 963933009411 | Note: تم التواصل
Phone: 963997226674 | Note: تم التواصل
Phone: 963985322261 | Note: تم التواصل
Phone: 963944585751 | Note: تم
Phone: 963936520446 | Note: تم
Phone: 963942272548 | Note: تم
Phone: 963932784840 | Note: تم
Phone: 963966337233 | Note: تم
Phone: 963982498933 | Note: تم
Phone: 963934792333 | Note: تم
Phone: 963992323421 | Note: No Note
Phone: 963937512107 | Note: تم
Phone: 963095247574 | Note: No Note
Phone: 963994800068 | Note: تم
Phone: 963955809725 | Note: No Note
Phone: 963933823485 | Note: No Note
Phone: 963949204755 | Note: تم
Phone: 963983691808 | Note: No Note
Phone: 963983626721 | Note: No Note
Phone: 963981610336 | Note: No Note
Phone: 963937927500 | Note: No Note
Phone: 963959853846 | Note: No Note
Phone: 963997073925 | Note: تم
Phone: 963956732767 | Note: غلط
Phone: 963947021104 | Note: تم
Phone: 963940052998 | Note: تم
Phone: 963944662446 | Note: تم
Phone: 963982678522 | Note: تم
Phone: 963962135909 | Note: تم
Phone: 963936610855 | Note: تم التواصل
Phone: 963994299736 | Note: تم التواصل
Phone: 963994202784 | Note: تم التواصل
Phone: 963938506392 | Note: تم التواصل
Phone: 963996355773 | Note: تم التواصل
Phone: 963993211641 | Note: تم التواصل
Phone: 963958885#01 | Note: خطأ
Phone: 963993214588 | Note: تم التواصل
Phone: 963930690439 | Note: تم التواصل
Phone: 963981320471 | Note: No Note
Phone: 963958749567 | Note: No Note
Phone: 963955399707 | Note: السيارة بالتصليح
Phone: 963981661357 | Note: تم
Phone: 963935151385 | Note: تم
Phone: 963933524019 | Note: تم
Phone: 963969079332 | Note: تم
Phone: 963982380563 | Note: تم
Phone: 963998817414 | Note: تم
Phone: 963962864640 | Note: تم
Phone: 963954932302 | Note: تم
Phone: 963951628380 | Note: No Note
Phone: 963956742311 | Note: تم
Phone: 963988605516 | Note: No Note
Phone: 963933122432 | Note: No Note
Phone: 963943562177 | Note: No Note
Phone: 963936700433 | Note: No Note
Phone: 963991539595 | Note: No Note
Phone: 963997634135 | Note: No Note
Phone: 963954512319 | Note: No Note
Phone: 963991392595 | Note: No Note
Phone: 963930053897 | Note: No Note
Phone: 963941494393 | Note: No Note
Phone: 963938963278 | Note: No Note
Phone: 963996725663 | Note: No Note
Phone: 963932998203 | Note: No Note
Phone: 963984743097 | Note: No Note
Phone: 963+20952653 | Note: No Note
Phone: 963933263408 | Note: No Note
Phone: 963992603003 | Note: No Note
Phone: 963999186608 | Note: No Note
Phone: 963093319092 | Note: No Note
Phone: 963992200572 | Note: No Note
Phone: 963935860379 | Note: تم التواصل
Phone: 963932612511 | Note: No Note
Phone: 963955665828 | Note: No Note
Phone: 963958748659 | Note: No Note
Phone: 963948956757 | Note: No Note
Phone: 963991527216 | Note: No Note
Phone: 963967434852 | Note: No Note
Phone: 963933473946 | Note: No Note
Phone: 963959281303 | Note: No Note
Phone: 963937506427 | Note: No Note
Phone: 963945017743 | Note: No Note
Phone: 963941973355 | Note: No Note
Phone: 963969369322 | Note: No Note
Phone: 963935221144 | Note: No Note
Phone: 963991933762 | Note: No Note
Phone: 963991331539 | Note: No Note
Phone: 963995940170 | Note: No Note
Phone: 963996450146 | Note: No Note
Phone: 963942283959 | Note: No Note
Phone: 963936825881 | Note: No Note
Phone: 963994058290 | Note: تم التواصل
Phone: 963980387211 | Note: No Note
Phone: 963960003815 | Note: No Note
Phone: 963938705215 | Note: No Note
Phone: 963930097924 | Note: No Note
Phone: 963982872652 | Note: تم التواصل
Phone: 963985327571 | Note: No Note
Phone: 963958786360 | Note: No Note
Phone: 963968840086 | Note: No Note
Phone: 963937536957 | Note: No Note
Phone: 963953925409 | Note: No Note
Phone: 963947157325 | Note: No Note
Phone: 963981489190 | Note: No Note
Phone: 963937583931 | Note: No Note
Phone: 963949631384 | Note: No Note
Phone: 963953344805 | Note: No Note
Phone: 963930104547 | Note: No Note
Phone: 963952300665 | Note: No Note
Phone: 963095230066 | Note: No Note
Phone: 963988510023 | Note: No Note
Phone: 963992274229 | Note: No Note
Phone: 963991506951 | Note: تم التواصل
Phone: 963954894895 | Note: تم التواصل
Phone: 963955585012 | Note: خارج الخدمة
Phone: 963996307122 | Note: تم التواصل
Phone: 963991610683 | Note: تم التواصل
Phone: 963991355714 | Note: تم التواصل
Phone: 963937557764 | Note: تم التواصل
Phone: 963988514321 | Note: تم التواصل
Phone: 963944077035 | Note: تم التواصل
Phone: 963938129427 | Note: تم التواصل
Phone: 963990444099 | Note: تم التواصل
Phone: 963956786668 | Note: تم التواصل
Phone: 963940728564 | Note: تم التواصل
Phone: 963954402659 | Note: خارج الخدمة وتس واتصال
Phone: 963936765364 | Note: تم التواصل
Phone: 963933078901 | Note: تم التواصل
Phone: 963934417178 | Note: تم التواصل
Phone: 963930447695 | Note: تم التواصل
Phone: 963094051564 | Note: الرقم خطأ
Phone: 963992417040 | Note: تم التواصل
Phone: 963958922780 | Note: تم الاتصال سكودا
Phone: 963951379303 | Note: تم التواصل
Phone: 963953858808 | Note: تم التواصل
Phone: 963964646415 | Note: تم التواصل
Phone: 963960098818 | Note: تم التواصل
Phone: 963933899771 | Note: تم التواصل
Phone: 963096949698 | Note: الرقم خطأ
Phone: 963982861634 | Note: No Note
Phone: 963938252876 | Note: No Note
Phone: 963986561347 | Note: No Note
Phone: 963933700937 | Note: No Note
Phone: 963960078368 | Note: No Note
Phone: 963933737355 | Note: No Note
Phone: 963983755054 | Note: hvta
Phone: 963940907547 | Note: No Note
Phone: 963949757956 | Note: No Note
Phone: 963938938514 | Note: No Note
Phone: 963980457705 | Note: No Note
Phone: 963944404002 | Note: No Note
Phone: 963965410313 | Note: No Note
Phone: 963982325766 | Note: No Note
Phone: 963981289181 | Note: No Note
Phone: 963993462192 | Note: No Note
Phone: 963968504915 | Note: No Note
Phone: 963936628380 | Note: No Note
Phone: 963951366246 | Note: No Note
Phone: 963998727408 | Note: No Note
Phone: 963953877512 | Note: No Note
Phone: 963940478435 | Note: No Note
Phone: 963984625505 | Note: No Note
Phone: 963954659494 | Note: No Note
Phone: 963947653804 | Note: No Note
Phone: 963959218092 | Note: No Note
Phone: 963994511053 | Note: No Note
Phone: 963938341514 | Note: No Note
Phone: 963982672582 | Note: No Note
Phone: 963992495126 | Note: No Note
Phone: 963993163487 | Note: No Note
Phone: 963966516151 | Note: No Note
Phone: 963958472195 | Note: No Note
Phone: 963954611914 | Note: No Note
Phone: 963940865211 | Note: No Note
Phone: 963955875120 | Note: No Note
Phone: 963985347924 | Note: No Note
Phone: 963951450015 | Note: No Note
Phone: 963991449908 | Note: No Note
Phone: 963939715983 | Note: No Note
Phone: 963932166786 | Note: No Note
Phone: 963932334792 | Note: No Note
Phone: 963998615843 | Note: No Note
Phone: 963995232226 | Note: No Note
Phone: 963983772298 | Note: No Note
Phone: 963988736467 | Note: No Note
Phone: 963959109269 | Note: No Note
Phone: 963934770200 | Note: No Note
Phone: 963995149210 | Note: No Note
Phone: 963985665216 | Note: No Note
Phone: 963962423870 | Note: No Note
Phone: 963939894588 | Note: No Note
Phone: 963930018143 | Note: No Note
Phone: 963944940930 | Note: No Note
Phone: 963930354266 | Note: No Note
Phone: 963952380026 | Note: No Note
Phone: 963932838183 | Note: No Note
Phone: 963988131966 | Note: No Note
Phone: 963993300063 | Note: No Note
Phone: 963949754561 | Note: No Note
Phone: 963935927218 | Note: No Note
Phone: 963935595928 | Note: No Note
Phone: 963949282497 | Note: No Note
Phone: 963934392382 | Note: No Note
Phone: 963937593945 | Note: No Note
Phone: 963938883892 | Note: No Note
Phone: 963093727926 | Note: No Note
Phone: 963999062031 | Note: No Note
Phone: 963938059209 | Note: No Note
Phone: 963964685561 | Note: No Note
Phone: 963944344299 | Note: No Note
Phone: 963955355766 | Note: No Note
Phone: 963999823383 | Note: No Note
Phone: 963944439897 | Note: No Note
Phone: 963995127821 | Note: No Note
Phone: 963994257265 | Note: No Note
Phone: 963936490987 | Note: No Note
Phone: 963993530236 | Note: No Note
Phone: 963 959 503 | Note: No Note
Phone: 963986797797 | Note: No Note
Phone: 963933529331 | Note: No Note
Phone: 963951343947 | Note: No Note
Phone: 963997585651 | Note: No Note
Phone: 963991907052 | Note: No Note
Phone: 963988964744 | Note: No Note
Phone: 963099161662 | Note: No Note
Phone: 963933175809 | Note: No Note
Phone: 963937590105 | Note: No Note
Phone: 963984222103 | Note: No Note
Phone: 963099467874 | Note: No Note
Phone: 963930301422 | Note: No Note
Phone: 963988561330 | Note: No Note
Phone: 963986769366 | Note: No Note
Phone: 963940554896 | Note: No Note
Phone: 963934825832 | Note: No Note
Phone: 963980823984 | Note: No Note
Phone: 963993761215 | Note: No Note
Phone: 963+96399339 | Note: No Note
Phone: 963992811392 | Note: No Note
Phone: 963993292569 | Note: No Note
Phone: 963985774901 | Note: No Note
Phone: 963992475789 | Note: No Note
Phone: 963995953364 | Note: No Note
Phone: 96385166225 | Note: No Note
Phone: 96398516622 | Note: No Note
Phone: 963935689658 | Note: No Note
Phone: 963933572705 | Note: No Note
Phone: 963935722215 | Note: No Note
Phone: 963981140916 | Note: No Note
Phone: 963985215116 | Note: No Note
Phone: 963932762035 | Note: No Note
Phone: 963946120103 | Note: No Note
Phone: 963933818455 | Note: No Note
Phone: 963964858616 | Note: No Note
Phone: 963944390916 | Note: No Note
Phone: 963945739489 | Note: No Note
Phone: 963932776772 | Note: No Note
Phone: 963933333813 | Note: No Note
Phone: 963980874584 | Note: No Note
Phone: 963980294990 | Note: No Note
Phone: 963934185580 | Note: No Note
Phone: 963936921204 | Note: No Note
Phone: 963093554127 | Note: No Note
Phone: 963095965191 | Note: No Note
Phone: 963093352887 | Note: No Note
Phone: 963988128853 | Note: No Note
Phone: 963094729812 | Note: No Note
Phone: 963998748039 | Note: No Note
Phone: 963955374066 | Note: تم
Phone: 963095537406 | Note: No Note
Phone: 963949005027 | Note: تم
Phone: 963959651915 | Note: لاااااا
Phone: 963094906005 | Note: No Note
Phone: 963988617564 | Note: No Note
Phone: 963992652773 | Note: No Note
Phone: 963996727211 | Note: No Note
Phone: 963991363270 | Note: No Note
Phone: 963946790074 | Note: No Note
Phone: 963939297072 | Note: No Note
Phone: 963991197416 | Note: No Note
Phone: 963980362067 | Note: No Note
Phone: 963987076781 | Note: No Note
Phone: 963945458695 | Note: No Note
Phone: 963936408390 | Note: No Note
Phone: 963991431763 | Note: No Note
Phone: 963964795089 | Note: No Note
Phone: 963965800050 | Note: No Note
Phone: 963953677959 | Note: No Note
Phone: 963099310584 | Note: No Note
Phone: 963934108410 | Note: No Note
Phone: 963944498647 | Note: No Note
Phone: 963943569855 | Note: No Note
Phone: 963992000214 | Note: No Note
Phone: 963988733184 | Note: No Note
Phone: 963997357928 | Note: No Note
Phone: 963968217127 | Note: No Note
Phone: 963984213886 | Note: No Note
Phone: 963969955380 | Note: No Note
Phone: 963093039426 | Note: No Note
Phone: 963993067534 | Note: No Note
Phone: 963996882906 | Note: No Note
Phone: 963930981086 | Note: No Note
Phone: 2979639929 | Note: No Note
Phone: 963948320564 | Note: No Note
Phone: 963933236526 | Note: No Note
Phone: 963935731025 | Note: No Note
Phone: 963940005693 | Note: No Note
Phone: 963093435196 | Note: No Note
Phone: 963933147140 | Note: رح يكمل تسجيل
Phone: 963982950096 | Note: عم يصلح سيارتو بس تجهز رح يكمل تسجيل
Phone: 963992304426 | Note: سيارتو جيب مصروفات  كبير
Phone: 963093412182 | Note: رقمو غلط
Phone: 963944707024 | Note: راح النت من عندو واليوم رح يرجع يسجل
Phone: 963997952574 | Note: No Note
Phone: 963932863040 | Note: سيارتو بالتصليح
Phone: 963942074619 | Note: مابدو
Phone: 963934146486 | Note: تم التواصل
Phone: 963992566299 | Note: تم التواصل
Phone: 9634894573 | Note: رقم غلط
Phone: 963933383373 | Note: تم التواصل
Phone: 963962419880 | Note: تم التواصل
Phone: 963938105556 | Note: تم التواصل
Phone: 963981347112 | Note: تم التواصل
Phone: 963959052791 | Note: تم التواصل
Phone: 963949608050 | Note: تم التواصل
Phone: 963998977934 | Note: تم التواصل
Phone: 963931839232 | Note: تم التواصل
Phone: 963935140176 | Note: تم التواصل
Phone: 963932033543 | Note: تم التواصل
Phone: 963991172711 | Note: تم التواصل
Phone: 963959164134 | Note: تم التواصل
Phone: 963943919419 | Note: ماعندو واتس رقمو مسكر
Phone: 963994000556 | Note: تم التواصل
Phone: 963098084512 | Note: رقم غلط
Phone: 963932254575 | Note: تم التواصل
Phone: 963945117692 | Note: تم التواصل
Phone: 963932119678 | Note: تم التواصل
Phone: 963993034046 | Note: تم التواصل
Phone: 963954183741 | Note: تم التواصل
Phone: 963951433826 | Note: ماعندو واتس خطو مسكر
Phone: 963093661085 | Note: رقم غلط
Phone: 963998287801 | Note: تم التواصل
Phone: 963988912182 | Note: ماعندو واتس
Phone: 963996024113 | Note: تم التواصل
Phone: 963931677655 | Note: تم التواصل
Phone: 963933921336 | Note: تم التواصل
Phone: 963936374163 | Note: تم التواصل
Phone: 963942047365 | Note: تم التواصل
Phone: 963981360800 | Note: تم التواصل
Phone: 963956396223 | Note: تم التواصل
Phone: 963963899416 | Note: رقم غلط
Phone: 963934493911 | Note: تم التواصل
Phone: 963934950868 | Note: تم التواصل
Phone: 963936659081 | Note: تم التواصل
Phone: 963945973939 | Note: تم التواصل
Phone: 963983444102 | Note: تم التواصل
Phone: 963951844719 | Note: تم التواصل
Phone: 963932663633 | Note: تم التواصل
Phone: 963093266363 | Note: رقم غلط
Phone: 963937271849 | Note: تم التواصل معو بيك اب
Phone: 963938728361 | Note: تم التواصل
Phone: 963947640146 | Note: تم التواصل
Phone: 963992439500 | Note: No Note
Phone: 963997489672 | Note: تم التواصل
Phone: 963094850489 | Note: رقم غلط
Phone: 963990115156 | Note: تم التواصل
Phone: 963962311317 | Note: ماعندو واتس وخطو مسكر
Phone: 963093172947 | Note: الرقم غلط
Phone: 963993762515 | Note: تم التواصل
Phone: 963931799545 | Note: تم التواصل
Phone: 963945187714 | Note: تم التواصل
Phone: 963968911015 | Note: ماعندو واتس رقمو مسكر
Phone: 963944750715 | Note: تم التواصل
Phone: 963998134492 | Note: تم التواصل
Phone: 963099813449 | Note: رقمو غلط
Phone: 963932727476 | Note: تم التواصل
Phone: 963933518336 | Note: تم التواصل
Phone: 963998885309 | Note: تم التواصل
Phone: 963988248185 | Note: تم التواصل
Phone: 963093067938 | Note: No Note
Phone: 963981383714 | Note: تم التواصل
Phone: 963939362191 | Note: رقمو مغلق  وماعندو واتس
Phone: 963933440323 | Note: تم التواصل
Phone: 963982143227 | Note: تم التواصل
Phone: 963938145916 | Note: تم التواصل
Phone: 963933718454 | Note: تم التواصل
Phone: 963931800533 | Note: تم التواصل
Phone: 963934294133 | Note: تم التواصل
Phone: 963939808314 | Note: رقم غلط ومسكر خطو
Phone: 963935745914 | Note: تم التواصل
Phone: 963969902667 | Note: تم التواصل
Phone: 963933735326 | Note: ماعندو واتس رقمو غلط
Phone: 963998699541 | Note: تم التواصل
Phone: 963093333839 | Note: رقم غلط
Phone: 963966313126 | Note: تم التواصل
Phone: 963956451887 | Note: تم التواصل
Phone: 963967415296 | Note: تم التواصل
Phone: 963997766064 | Note: تم التواصل
Phone: 963962854801 | Note: تم التواصل
Phone: 963998190089 | Note: تم التواصل
Phone: 963981634358 | Note: تم التواصل
Phone: 963938289156 | Note: تم التواصل
Phone: 963095645188 | Note: رقم غلط
Phone: 963936908818 | Note: تم التواصل
Phone: 963941385190 | Note: تم التواصل
Phone: 963009639885 | Note: رقم غلط
Phone: 963935777750 | Note: تم التواصل
Phone: 963985578199 | Note: تم التواصل
Phone: 963099317895 | Note: رقم غلط
Phone: 963990417834 | Note: تم التواصل
Phone: 963093727184 | Note: رقم غلط
Phone: 963968750666 | Note: ماعندو واتس ورقمو مسكر
Phone: 963998668125 | Note: تم التواصل
Phone: 963991833068 | Note: تم التواصل
Phone: 963940740151 | Note: ماعندي  واتس ورقمو مسكر
Phone: 963955544813 | Note: تم التواصل
Phone: 963933202022 | Note: ماعندو واتساب ورخطو مسكر
Phone: 963933221881 | Note: ماعندو  واتس وخطو مسكر
Phone: 963943358179 | Note: تم التواصل
Phone: 963+96393349 | Note: رقم غلط
Phone: 963933804760 | Note: تم التواصل
Phone: 963988214321 | Note: تم التواصل
Phone: 963991903251 | Note: تم التواصل
Phone: 963933400489 | Note: تم التواصل
Phone: 963940340848 | Note: تم التواصل
Phone: 963992458425 | Note: تم التواصل
Phone: 963932555452 | Note: تم التواصل
Phone: 963965218471 | Note: تم التواصل
Phone: 963933292470 | Note: تم التواصل
Phone: 963943889236 | Note: تم التواصل وكمل تسجيلو
Phone: 963988133863 | Note: تم التواصل
Phone: 963094444810 | Note: رقمو غلط
Phone: 963930946809 | Note: تم التواصل
Phone: 963968191496 | Note: تم التواصل
Phone: 963935090886 | Note: تم التواصل
Phone: 963991922952 | Note: تم التواصل
Phone: 963991112991 | Note: تم التواصل
Phone: 963986170776 | Note: تم التواصل
Phone: 963999743765 | Note: تم التواصل
Phone: 963932111786 | Note: تم التواصل
Phone: 963933681672 | Note: تم التواصل
Phone: 963938552167 | Note: تم التواصل
Phone: 963933206306 | Note: تم التواصل
Phone: 963957346118 | Note: تم التواصل
Phone: 963997392413 | Note: تم التواصل
Phone: 963988227272 | Note: تم التواصل
Phone: 963988029059 | Note: تم التواصل
Phone: 963945832988 | Note: تم التواصل
Phone: 963997944590 | Note: تم التواصل
Phone: 963980363715 | Note: تم التواصل
Phone: 963935102639 | Note: تم التواصل
Phone: 963954438781 | Note: تم التواصل
Phone: 963945223878 | Note: تم التواصل
Phone: 963980581094 | Note: تم التواصل
Phone: 963939164164 | Note: تم التواصل
Phone: 963938124006 | Note: تم التواصل
Phone: 963944349036 | Note: تم التواصل
Phone: 963992057768 | Note: غير مهتم
Phone: 963988177909 | Note: تم التواصل
Phone: 963932049144 | Note: No Note
Phone: 963992393038 | Note: No Note
Phone: 963952391236 | Note: No Note
Phone: 963935039644 | Note: No Note
Phone: 963985924850 | Note: No Note
Phone: 963932377014 | Note: No Note
Phone: 963993235215 | Note: No Note
Phone: 963980541950 | Note: No Note
Phone: 963945957334 | Note: No Note
Phone: 963981355144 | Note: No Note
Phone: 963938139830 | Note: No Note
Phone: 963932562745 | Note: No Note
Phone: 963994661362 | Note: No Note
Phone: 963988342603 | Note: No Note
Phone: 963994011134 | Note: No Note
Phone: 963936104080 | Note: No Note
Phone: 963992788749 | Note: No Note
Phone: 963998892720 | Note: No Note
Phone: 963996682748 | Note: No Note
Phone: 963938570002 | Note: No Note
Phone: 963931745699 | Note: No Note
Phone: 963992165521 | Note: No Note
Phone: 963993595631 | Note: No Note
Phone: 963933949753 | Note: No Note
Phone: 963934629935 | Note: No Note
Phone: 963965778887 | Note: اجدب
Phone: 963980212534 | Note: No Note
Phone: 963956784191 | Note: No Note
Phone: 963935443899 | Note: No Note
Phone: 963958642713 | Note: No Note
Phone: 963999138915 | Note: No Note
Phone: 963948941187 | Note: No Note
Phone: 963953459606 | Note: تم
Phone: 963934146288 | Note: تم
Phone: 963933256528 | Note: تم
Phone: 963998883027 | Note: تم
Phone: 963968481449 | Note: تم
Phone: 963965247307 | Note: ما معو سيارة
Phone: 963956761624 | Note: تم
Phone: 963939724962 | Note: تم
Phone: 963936030548 | Note: تم
Phone: 962781821306 | Note: خطأ
Phone: 963960040775 | Note: No Note
Phone: 963996642236 | Note: No Note
Phone: 963934293954 | Note: تم
Phone: 963934928537 | Note: تم
Phone: 963941440312 | Note: No Note
Phone: 963937214172 | Note: No Note
Phone: 963933824331 | Note: No Note
Phone: 963945555043 | Note: No Note
Phone: 963938676742 | Note: تم
Phone: 963933306898 | Note: تم
Phone: 963933708476 | Note: No Note
Phone: 963994795950 | Note: No Note
Phone: 963990329520 | Note: تم
Phone: 963960977309 | Note: تم
Phone: 963933267955 | Note: تم
Phone: 963996186195 | Note: تم
Phone: 916364908545 | Note: تم
Phone: 919154792575 | Note: تم
Phone: 963998119558 | Note: تم
Phone: 919606970074 | Note: خطأ
Phone: 916364908621 | Note: خطأ
Phone: 962772735902 | Note: No Note
Phone: 916366356713 | Note: No Note
Phone: 16693334444 | Note: No Note
Phone: 962782700835 | Note: No Note
Phone: 962782070515 | Note: No Note
Phone: 963984429412 | Note: No Note
Phone: 963966673673 | Note: No Note
Phone: 962796377987 | Note: No Note
Phone: 963947222548 | Note: No Note
Phone: 639276036618 | Note: No Note
Phone: 963798583052 | Note: No Note

File: serviceapp/deleteDriverNotCompleteRegistration.php

<?php

require_once __DIR__ . '/../connect.php';

// 1. استقبال رقم الهاتف القادم من التطبيق
$phone = filterRequest("phone");

// التحقق من أن الهاتف ليس فارغاً
if ($phone == null) {
    jsonError("Phone number is empty");
    exit();
}

   $phone = $encryptionHelper->encryptData($phone);


// 2. تنفيذ الحذف بشرط تطابق الهاتف وأن الحالة 'yet'
$sql = "DELETE FROM driver 
        WHERE phone = ? 
        AND employmentType = 'yet'";

$stmt = $con->prepare($sql);
$stmt->execute(array($phone));

$count = $stmt->rowCount();

if ($count > 0) {
    // 3. إرسال رد النجاح ليتم عرضه في التطبيق (Get.snackbar)
    jsonSuccess(null, "Driver deleted successfully");
} else {
    // إرسال رد فشل (إذا لم يتم العثور على الرقم أو كان السائق مكتملاً)
    jsonError("Driver not found or already active");
}

?>

File: serviceapp/getDriversWaitingActive.php

<?php

require_once __DIR__ . '/../connect.php';

$sql = "SELECT id as driverId, first_name, last_name,phone as phone_number, status FROM driver WHERE status != 'actives'";


$stmt = $con->prepare($sql);
$stmt->execute();

if ($stmt->rowCount() > 0) {
    $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);

    // فك تشفير أرقام الهواتف فقط للإخراج
   foreach ($rows as &$row) {
        if (!empty($row['phone_number'])) {
            $row['phone_number'] = $encryptionHelper->decryptData($row['phone_number']);
        }
        if (!empty($row['first_name'])) {
            $row['first_name'] = $encryptionHelper->decryptData($row['first_name']);
        }
       if (isset($row['last_name'])) {
        $row['last_name'] = $encryptionHelper->decryptData($row['last_name']);
    }
    }
 

    jsonSuccess($rows);
} else {
    jsonError("No Phone verified yet found");
}
?>

File: serviceapp/getDriverDetailsForActivate.php

<?php
require_once __DIR__ . '/../connect.php'; 

$driverId = filterRequest("driverId");

$sql = "SELECT d.*, cr.* 
        FROM `driver` d 
        JOIN `CarRegistration` cr ON cr.driverID = d.id 
        WHERE d.id = :driverId ";

$stmt = $con->prepare($sql);
$stmt->execute([':driverId' => $driverId]);

if ($stmt->rowCount() > 0) {
    $row = $stmt->fetch(PDO::FETCH_ASSOC);

    // فك التشفير للحقول المطلوبة
    $fieldsToDecrypt = [
        'phone','email','gender','national_number','first_name','last_name',
        'name_arabic','address','site','vin','car_plate','owner'
    ];
    foreach ($fieldsToDecrypt as $field) {
        if (isset($row[$field]) && $row[$field] !== '') {
            try {
                $row[$field] = $encryptionHelper->decryptData($row[$field]);
            } catch (Exception $e) {
                $row[$field] = "Decryption Failed";
            }
        }
    }

    // ✅ إزالة الحقول الحسّاسة من الاستجابة
    $fieldsToRemove = ['password', 'password_hash', 'salt', 'reset_token'];
    foreach ($fieldsToRemove as $f) {
        if (array_key_exists($f, $row)) {
            unset($row[$f]);
        }
    }

    // إرسال الاستجابة
    jsonSuccess([$row]);

} else {
    jsonError("No data found for the specified driver ID");
}

File: serviceapp/getComplaintAllDataForDriver.php

<?php
require_once __DIR__ . '/../connect.php';
$driverID = filterRequest("driver_id");

$sql = "SELECT
    cm.`id`,
    cm.`ride_id`,
    cm.`passenger_id`,
    cm.`driver_id`,
    cm.`complaint_type`,
    cm.`description`,
    cm.`date_filed`,
    cm.`statusComplaint`,
    cm.`resolution`,
    cm.`date_resolved`,
    p.first_name AS passengerName,
    d.name_arabic AS driverName,
    d.gender,
    ride.price AS priceOfRide,
    ride.status AS rideStatus,
    ride.carType AS carType,
    ride.paymentMethod AS ridePaymentMethod,
    ride.rideTimeFinish AS rideTimeFinish,
    payments.amount AS paymentFromPaymentTable,
    payments.created_at AS timeFromPaymentTable,
    (
    SELECT
        AVG(rd.rating)
    FROM
        ratingDriver rd
    WHERE
        rd.driver_id = cm.driver_id
) AS avgRatingDriverFromPassengers,
(
    SELECT
        COUNT(*)
    FROM
        ratingDriver rd
    WHERE
        rd.driver_id = cm.driver_id
) AS countratingDriverFromPassengers,
(
    SELECT
        AVG(rp.rating)
    FROM
        ratingPassenger rp
    WHERE
        rp.passenger_id = cm.passenger_id
) AS avgRatingPassengerFromDrivers,
(
    SELECT
        COUNT(*)
    FROM
        ratingPassenger rp
    WHERE
        rp.passenger_id = cm.passenger_id
) AS countRatingPassengerFromDrivers,
(
    SELECT
        COUNT(*)
    FROM
        ride
    WHERE
        ride.driver_id = cm.driver_id
) countDriverRide,
(
    SELECT
        COUNT(*)
    FROM
        ride
    WHERE
        ride.passenger_id = cm.passenger_id
) countPassengerRide,
(
    SELECT
        COALESCE(SUM(amount),
        0) AS visaDriver
    FROM
        payments
    WHERE
        isGiven = 'waiting' AND `payment_method` IN(
            'visa-in',
            'visa',
            'visaRide',
            'TransferFrom',
            'payout',
            'TransferTo'
        ) AND payments.`driverID` = cm.driver_id
) AS driverVisa,
(
    SELECT
        COALESCE(SUM(amount),
        0) AS pointDriver
    FROM
        driverWallet dw
    WHERE
        dw.paymentMethod IN(
            'visa-in',
            'visa',
            'visaRide',
            'TransferFrom',
            'payout',
            'TransferTo'
        ) AND dw.`driverID` = cm.driver_id
) AS driverWallet,
(
    SELECT
        COALESCE(SUM(pw.balance),
        0)
    FROM
        passengerWallet pw
    WHERE
        pw.passenger_id = cm.passenger_id
) AS passengerWallet,
(
    SELECT
        token
    FROM
        driverToken
    WHERE
        driverToken.captain_id = cm.driver_id
) AS driverToken,
(
    SELECT
        token
    FROM
        tokens
    WHERE
        tokens.passengerID = cm.passenger_id
) AS passengerToken,
(
    SELECT
        COUNT(*)
    FROM
        complaint
    WHERE
        complaint.passenger_id = cm.passenger_id AND cm.complaint_type = 'Passenger'
) AS countOfComplaintFromPassenger,
(
    SELECT
        COUNT(*)
    FROM
        complaint
    WHERE
        complaint.driver_id = cm.driver_id AND cm.complaint_type = 'Driver'
) AS countOfComplaintFromDriver
FROM
    `complaint` cm
LEFT JOIN passengers p ON
    p.id = cm.`passenger_id`
LEFT JOIN driver d ON
    d.id = cm.driver_id
LEFT JOIN ride ON ride.id = cm.ride_id
LEFT JOIN payments ON payments.rideId = cm.ride_id
WHERE
    cm.driver_id = '$driverID'";
$stmt = $con->prepare($sql);
$stmt->execute();

if ($stmt->rowCount() > 0) {
    $row = $stmt->fetchAll(PDO::FETCH_ASSOC);

    foreach ($row as &$item) {
        if (isset($item['passengerName'])) {
            $item['passengerName'] = $encryptionHelper->decryptData($item['passengerName']);
        }
        if (isset($item['driverName'])) {
            $item['driverName'] = $encryptionHelper->decryptData($item['driverName']);
        }
        if (isset($item['gender'])) {
            $item['gender'] = $encryptionHelper->decryptData($item['gender']);
        }
        if (isset($item['driverToken'])) {
            $item['driverToken'] = $encryptionHelper->decryptData($item['driverToken']);
        }
        if (isset($item['passengerToken'])) {
            $item['passengerToken'] = $encryptionHelper->decryptData($item['passengerToken']);
        }
    }

    jsonSuccess($row);
} else {
    jsonError($message = $sql);
}
?>

File: serviceapp/getJsonFile.php

<?php
require_once __DIR__ . '/../get_connect.php';

// اسم الملف النصي الذي سيتم حفظ البيانات فيه
$filename = "drivers_list.txt";

/*
    المطلوب:
    - جلب أرقام الهاتف من phone_verification غير الموجودة في driver
    - فك تشفير الهاتف (والإيميل إن لزم)
    - حفظ النتيجة في ملف نصي (رقم الهاتف والملاحظة)
*/

$sql = "
   SELECT 
    pv.id,
    pv.phone_number,
    pv.email,
    pv.token_code,
    pv.created_at,
    n.note
FROM 
    phone_verification pv
LEFT JOIN 
    driver d ON pv.phone_number = d.phone
LEFT JOIN 
    notesForDriverService n ON pv.phone_number = n.phone
WHERE 
    d.phone IS NULL 
    AND (n.note != 'delete' OR n.note IS NULL)
    -- تمت إضافة هذا الشرط بناءً على طلبك (آخر 5 أيام)
   -- AND pv.created_at >= DATE_SUB(NOW(), INTERVAL 5 DAY)
ORDER BY 
    pv.created_at DESC;
";

$stmt = $con->prepare($sql);
$stmt->execute();

if ($stmt->rowCount() > 0) {
    $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);

    // فتح الملف للكتابة (Mode 'w' يقوم بإنشاء الملف أو مسح محتواه السابق والكتابة من جديد)
    $fileHandle = fopen($filename, 'w');

    // التحقق من أن الملف فُتح بنجاح
    if ($fileHandle) {
        
        foreach ($rows as $r) {
            $phone = "";
            $note = "No Note"; // القيمة الافتراضية إذا لم توجد ملاحظة

            // 1. فك تشفير رقم الهاتف
            if (isset($r['phone_number']) && $r['phone_number'] != null) {
                $phone = $encryptionHelper->decryptData($r['phone_number']);
            }

            // 2. تجهيز نص الملاحظة
            if (isset($r['note']) && $r['note'] != null) {
                $note = $r['note'];
            }

            // 3. تنسيق السطر الذي سيتم حفظه
            // الشكل: Phone: 0123456789 | Note: مهتم بالتسجيل
            $line = "Phone: " . $phone . " | Note: " . $note . PHP_EOL;

            // 4. الكتابة داخل الملف
            fwrite($fileHandle, $line);
        }

        // إغلاق الملف بعد الانتهاء
        fclose($fileHandle);

        // طباعة رسالة نجاح مع رابط للملف (اختياري)
        echo json_encode([
            "status" => "success", 
            "message" => "File created successfully", 
            "file" => $filename,
            "count" => count($rows)
        ]);

    } else {
        jsonError("Unable to open file for writing.");
    }

} else {
    jsonError("No phone numbers found in the last 5 days");
}
?>

File: serviceapp/registerDriverAndCarService.php

<?php

// --- 1. Dependencias y Conexión ---
require_once __DIR__ . '/../connect.php'; 

// دالة مساعدة لتسجيل الخطوات في ملف الـ LOG
function logStep($step, $message) {
    error_log("[DriverReg] Step $step: $message");
}

try {
    // --- بدء المعاملة ---
    $con->beginTransaction();
    logStep(1, "Transaction started via beginTransaction()");

    // --- 2. Recolección de Datos (Conductor + Coche) ---
    $phone     = filterRequest("phone");
    $password  = filterRequest("password");
    $firstName = filterRequest("first_name");
    $lastName  = filterRequest("last_name");

    // تسجيل البيانات المبدئية (بدون كلمات المرور) للتأكد من وصولها
    logStep(2, "Inputs received -> Phone: $phone, Name: $firstName $lastName");

    // التحقق من الحقول الإجبارية
    if (empty($phone) || empty($password) || empty($firstName) || empty($lastName)) {
        throw new Exception("Required fields missing (phone, password, first_name, last_name).");
    }

    // --- 3. Generar ID de Conductor ---
    $driverId = substr(md5($phone), 0, 20);
    logStep(3, "Driver ID generated: $driverId");

    // --- 4. Procesamiento de Datos del Conductor ---
    $password_hashed = password_hash($password, PASSWORD_DEFAULT);
    $email = filterRequest("email");
    
    if (empty($email) || $email === 'Not specified') {
        $email = $phone . '@intaleqapp.com';
    }
    
    $nameArabic = $firstName . ' ' . $lastName;
    $site       = filterRequest("site");
    $address    = $site; 

    // بيانات إضافية
    $gender             = filterRequest("gender");
    $license_type       = filterRequest("license_type");
    $nationalNumber     = filterRequest("national_number");
    $issue_date         = filterRequest("issue_date");
    $expiry_date        = filterRequest("expiry_date");
    $licenseCategories  = filterRequest("license_categories");
    $licenseIssueDate   = filterRequest("license_issue_date");
    $birthdate          = filterRequest("birthdate");
    $maritalStatus      = filterRequest("maritalStatus");

    // --- 5. Recolección de Datos del Coche ---
    $owner             = filterRequest("owner");
    $color             = filterRequest("color");
    $colorHex          = filterRequest("color_hex");
    $model             = filterRequest("model");
    $carPlate          = filterRequest("car_plate");
    $make              = filterRequest("make");
    $fuel              = filterRequest("fuel");
    $year              = filterRequest("year");
    $vin               = filterRequest("vin");
    
    if (empty($vin)) {
        $vin = 'unknown';
    }

    $carExpirationDate = filterRequest("expiration_date");
    
    logStep(4, "Data processing completed. Car Plate: $carPlate, VIN: $vin");

    // --- 6. Cifrado de Datos ---
    try {
        $encryptedPhone          = $encryptionHelper->encryptData($phone);
        $encryptedEmail          = $encryptionHelper->encryptData($email);
        $encryptedFirstName      = $encryptionHelper->encryptData($firstName);
        $encryptedLastName       = $encryptionHelper->encryptData($lastName);
        $encryptedNameArabic     = $encryptionHelper->encryptData($nameArabic);
        $encryptedGender         = $encryptionHelper->encryptData($gender);
        $encryptedNationalNumber = $encryptionHelper->encryptData($nationalNumber);
        $encryptedAddress        = $encryptionHelper->encryptData($address);
        $encryptedSite           = $encryptionHelper->encryptData($site);
        $encryptedBirthdate      = $encryptionHelper->encryptData($birthdate);
        $encryptedOwner          = $encryptionHelper->encryptData($owner);
        $encryptedCarPlate       = $encryptionHelper->encryptData($carPlate);
        
        logStep(5, "Encryption successful for sensitive fields.");
    } catch (Exception $encEx) {
        throw new Exception("Encryption Error: " . $encEx->getMessage());
    }

    // --- 7. Comprobación de Duplicados ---
    // ملاحظة: إذا كان التشفير عشوائياً، فلن يجد التكرار هنا.
    $dup = $con->prepare("SELECT id FROM driver WHERE phone = :phone OR email = :email OR national_number = :national_number");
    $dup->execute([':phone' => $encryptedPhone, ':email' => $encryptedEmail, ':national_number' =>$encryptedNationalNumber]);
    
    if ($dup->rowCount() > 0) {
        logStep(6, "Duplicate found! Phone or Email or encryptedNationalNumber already exists.");
        throw new Exception("Phone or email already registered.");
    }
    logStep(6, "No duplicates found. Proceeding.");

    // --- 8. INSERCIÓN 1: Tabla 'driver' ---
    $sqlDriver = "
      INSERT INTO driver (
        id, phone, email, password, gender, license_type, national_number,
        name_arabic, issue_date, expiry_date, license_categories,
        address, licenseIssueDate, status, birthdate, site,
        first_name, last_name, accountBank, bankCode,
        employmentType, maritalStatus, fullNameMaritial, expirationDate,
        created_at, updated_at
      ) VALUES (
        :id, :phone, :email, :pwd, :gender, :license_type, :national_number,
        :name_arabic, :issue_date, :expiry_date, :license_categories,
        :address, :licenseIssueDate, :status, :birthdate, :site,
        :first_name, :last_name, :accountBank, :bankCode,
        :employmentType, :maritalStatus, :fullNameMaritial, :expirationDate,
        NOW(), NOW()
      )
    ";

    $stmtDriver = $con->prepare($sqlDriver);
    
    // تم توحيد المفاتيح لتشمل النقطتين (:)
    $driverData = [
        ':id'                 => $driverId,
        ':phone'              => $encryptedPhone,
        ':email'              => $encryptedEmail,
        ':pwd'                => $password_hashed,
        ':gender'             => $encryptedGender,
        ':license_type'       => $license_type,
        ':national_number'    => $encryptedNationalNumber,
        ':name_arabic'        => $encryptedNameArabic,
        ':issue_date'         => $issue_date,
        ':expiry_date'        => $expiry_date,
        ':license_categories' => $licenseCategories ?? 'B',
        ':address'            => $encryptedAddress,
        ':licenseIssueDate'   => $licenseIssueDate,
        ':status'             => 'actives',
        ':birthdate'          => $encryptedBirthdate,
        ':site'               => $encryptedSite,
        ':first_name'         => $encryptedFirstName,
        ':last_name'          => $encryptedLastName,
        ':accountBank'        => 'yet',
        ':bankCode'           => 'yet',
        ':employmentType'     => $maritalStatus ?? 'yet',
        ':maritalStatus'      => $maritalStatus ?? 'yet',
        ':fullNameMaritial'   => 'yet',
        ':expirationDate'     => 'yet',
    ];

    if (!$stmtDriver->execute($driverData)) {
        // تسجيل خطأ SQL بالتفصيل
        $errInfo = $stmtDriver->errorInfo();
        throw new Exception("Driver Insert Failed: " . $errInfo[2]);
    }
    logStep(7, "Driver table insert successful.");

    // --- 9. INSERCIÓN 2: Tabla 'CarRegistration' ---
    $sqlCar = "
    INSERT INTO CarRegistration (
        driverID, vin, owner, color, color_hex, model, car_plate,
        make, fuel, `year`, expiration_date, created_at
    ) VALUES (
        :driverId, :vin, :owner, :color, :color_hex, :model, :car_plate,
        :make, :fuel, :year, :expiration_date, NOW()
    )
    ";

    $stmtCar = $con->prepare($sqlCar);
    $carData = [
        ':driverId'        => $driverId,
        ':vin'             => $vin,
        ':owner'           => $encryptedOwner,
        ':color'           => $color,
        ':color_hex'       => $colorHex,
        ':model'           => $model,
        ':car_plate'       => $encryptedCarPlate,
        ':make'            => $make,
        ':fuel'            => $fuel,
        ':year'            => $year,
        ':expiration_date' => $carExpirationDate
    ];

    if (!$stmtCar->execute($carData)) {
        $errInfo = $stmtCar->errorInfo();
        throw new Exception("Car Insert Failed: " . $errInfo[2]);
    }
    logStep(8, "CarRegistration insert successful.");

    // --- 10. Confirmar Transacción ---
    $con->commit();
    logStep(9, "COMMIT successful. Sending Success Response.");
    
    jsonSuccess(["driverId" => $driverId, "message" => "Driver and car registered successfully."]);

    // --- 11. Enviar Notificación (خارج المعاملة يفضل، ولكن هنا كما في الكود الأصلي) ---
    try {
        $supportPhones = ['0952475740', '0952475742'];
        $randomIndex   = array_rand($supportPhones);
        $phoneToUse    = $supportPhones[$randomIndex];
        $randomNumber  = rand(1000, 999999);

        $messageBody = "أهلاً وسهلاً كابتن $firstName 👋\n"
                     . "تم تفعيل حسابك على تطبيق *سيرو*.\n"
                     . "يمكنك الآن تسجيل الدخول والبدء بالعمل مباشرة.\n"
                     . "للمساعدة تواصل معنا على الرقم: $phoneToUse\n"
                     . "نتمنى لك عمل موفق 🚖\n\n"
                     . "معرف الرسالة: $randomNumber";

        sendWhatsAppFromServer($phone, $messageBody);
        logStep(10, "WhatsApp notification sent.");
    } catch (Exception $waError) {
        // لا نوقف العملية إذا فشل الواتساب، فقط نسجل الخطأ
        logStep(10, "WhatsApp Warning: " . $waError->getMessage());
    }

} catch (PDOException $e) {
    $con->rollBack();
    $errorMsg = "Database Error (PDO): " . $e->getMessage();
    logStep("ERROR-PDO", $errorMsg);
    // إظهار رسالة عامة للمستخدم، وتسجيل التفاصيل في السيرفر
    jsonError("System error during registration. Please contact support.");
} catch (Exception $e) {
    // إذا كانت المعاملة مفتوحة، قم بإلغائها
    if ($con->inTransaction()) {
        $con->rollBack();
    }
    $errorMsg = "General Error: " . $e->getMessage();
    logStep("ERROR-GEN", $errorMsg);
    jsonError($e->getMessage());
}
?>

File: serviceapp/getdriverstotalMonthly.php

<?php
require_once __DIR__ . '/../connect.php';

// منع الأخطاء النصية وضبط الترويسة
error_reporting(0);
header('Content-Type: application/json');

// 1. استقبال التواريخ
if (isset($_POST['start_date']) && isset($_POST['end_date'])) {
    $start_date = $_POST['start_date'];
    $end_date   = $_POST['end_date'];
} else {
    // Fallback
    $current_month = isset($_POST['month']) ? str_pad($_POST['month'], 2, "0", STR_PAD_LEFT) : date('m');
    $current_year  = isset($_POST['year'])  ? $_POST['year']  : date('Y');
    
    $start_date = date('Y-m-d', strtotime("$current_year-$current_month-01"));
    $end_date   = date('Y-m-t', strtotime($start_date));
}

// 2. جملة SQL المعدلة
$sql = "
WITH RECURSIVE date_series AS (
    SELECT '$start_date' AS DATE
    UNION ALL
    SELECT DATE_ADD(DATE, INTERVAL 1 DAY)
    FROM date_series
    WHERE DATE < '$end_date'
)
SELECT
    date_series.date AS day,
    
    -- [1] إجمالي السائقين (الكلي في النظام)
    (SELECT COUNT(*) FROM driver) AS totalDrivers,

    -- [2] يومي: عدد السائقين المسجلين
    (
        SELECT COUNT(*)
        FROM driver
        WHERE DATE(driver.created_at) = date_series.date
    ) AS dailyTotalDrivers,

    -- [3] يومي: عدد السائقين المتصل بهم (notesForDriverService)
    (
        SELECT COUNT(*)
        FROM notesForDriverService
        WHERE DATE(notesForDriverService.createdAt) = date_series.date
    ) AS dailyTotalCallingDrivers,

    -- [4] يومي: Matching Notes (Join with driver on phone)
    (
        SELECT COUNT(*)
        FROM notesForDriverService n
        JOIN driver d ON n.phone = d.phone
        WHERE DATE(n.createdAt) = date_series.date
    ) AS dailyMatchingNotes,

    -- [5] إجمالي الفترة: سائقين
    (
        SELECT COUNT(*)
        FROM driver
        WHERE driver.created_at BETWEEN '$start_date' AND '$end_date 23:59:59'
    ) AS totalMonthlyDrivers,

    -- [6] إجمالي الفترة: Calling Drivers
    (
        SELECT COUNT(*)
        FROM notesForDriverService
        WHERE notesForDriverService.createdAt BETWEEN '$start_date' AND '$end_date 23:59:59'
    ) AS totalMonthlyCallingDrivers,

    -- [7] إجمالي الفترة: Matching Notes
    (
        SELECT COUNT(*)
        FROM notesForDriverService n
        JOIN driver d ON n.phone = d.phone
        WHERE n.createdAt BETWEEN '$start_date' AND '$end_date 23:59:59'
    ) AS totalMonthlyMatchingNotes

FROM
    date_series
GROUP BY
    date_series.date
ORDER BY
    date_series.date ASC;
";

try {
    $stmt = $con->prepare($sql);
    $stmt->execute();
    $data = $stmt->fetchAll(PDO::FETCH_ASSOC);

    if ($data) {
        echo json_encode(array("status" => "success", "message" => $data));
    } else {
        echo json_encode(array("status" => "success", "message" => []));
    }
} catch (PDOException $e) {
    echo json_encode(array("status" => "failure", "message" => $e->getMessage()));
}
?>

File: serviceapp/addNotesDriver.php

<?php

require_once __DIR__ . '/../connect.php';

// Retrieve and sanitize input parameters
$phone  = filterRequest("phone");
$note   = filterRequest("note");
$editor = filterRequest("editor");

// Encrypt the phone number
$encryptedPhone = $encryptionHelper->encryptData($phone);

// SQL query: insert new row OR update existing one if phone already exists
$sql = "INSERT INTO `notesForDriverService` (`phone`, `note`, `editor`) 
        VALUES (:phone, :note, :editor)
        ON DUPLICATE KEY UPDATE 
            `note` = VALUES(`note`),
            `editor` = VALUES(`editor`)";

// Prepare the SQL statement
$stmt = $con->prepare($sql);

// Bind the parameters
$stmt->bindParam(':phone', $encryptedPhone);
$stmt->bindParam(':note', $note);
$stmt->bindParam(':editor', $editor);

// Execute the query
$success = $stmt->execute();

if ($success) {
    if ($stmt->rowCount() > 0) {
        jsonSuccess(null, "Note inserted/updated successfully");
    } else {
        jsonError("No changes were made");
    }
} else {
    jsonError("Database error");
}
?>

File: serviceapp/getNotesForEmployee.php

<?php
require_once __DIR__ . '/../connect.php';

// استقبال التاريخ المُراد عرض الملاحظات له
// إذا لم يتم إرسال تاريخ، نستخدم تاريخ اليوم الحالي
$filter_date = isset($_POST['date']) ? $_POST['date'] : date('Y-m-d');

// الاستعلام: جلب كافة الملاحظات لليوم المحدد مرتبة من الأحدث للأقدم
$sql = "SELECT * FROM `notesForDriverService` 
        WHERE DATE(`createdAt`) = '$filter_date'
        ORDER BY `createdAt` DESC";

try {
    $stmt = $con->prepare($sql);
    $stmt->execute();
    $notes_data = $stmt->fetchAll(PDO::FETCH_ASSOC);

    if ($notes_data) {
        // التصحيح: استخدام حلقة التكرار وتمرير الصف كمرجع (&) لتعديل البيانات الأصلية
        foreach ($notes_data as &$row) {
            // التأكد من وجود عمود الهاتف قبل فك التشفير
            if (isset($row['phone'])) {
                // استخدام دالة فك التشفير (تأكد أن الدالة decrypt موجودة في connect.php)
                // أو استخدم $encryptionHelper->decryptData($row['phone']) إذا كنت تستخدم كلاس
                $row['phone'] = $encryptionHelper->decryptData($row['phone']);
            }
        }
        unset($row); // كسر الارتباط بالمتغير الأخير لضمان سلامة الكود

        jsonSuccess($notes_data);
    } else {
        jsonError("No notes found for this date");
    }

} catch (PDOException $e) {
    jsonError("Database error: " . $e->getMessage());
}
?>

File: serviceapp/getEmployeeDriverAfterCallingRegister.php

<?php
require_once __DIR__ . '/../connect.php';

/**
 * منطق تحديد التواريخ:
 * 1. إذا تم إرسال start_date و end_date في الطلب، سيتم استخدامهما (للبحث في رينج مخصص).
 * 2. إذا لم يتم إرسالهما، سيتم الاعتماد على month و year (للبحث في شهر كامل).
 * 3. إذا لم يتم إرسال أي شيء، سيتم استخدام الشهر الحالي كافتراضي.
 */

if (isset($_POST['start_date']) && isset($_POST['end_date'])) {
    // الحالة الأولى: البحث بنطاق تاريخ محدد (من يوم كذا إلى يوم كذا)
    $start_date = $_POST['start_date'];
    $end_date   = $_POST['end_date'];
} else {
    // الحالة الثانية: البحث بالشهر (مثل السكربت القديم)
    $current_month = isset($_POST['month']) ? $_POST['month'] : date('m');
    $current_year  = isset($_POST['year'])  ? $_POST['year']  : date('Y');

    // تنسيق الشهر ليكون خانتين
    $current_month = str_pad($current_month, 2, "0", STR_PAD_LEFT);

    // حساب أول وآخر يوم في الشهر
    $start_date = date('Y-m-d', strtotime($current_year . '-' . $current_month . '-01'));
    $end_date   = date('Y-m-t', strtotime($start_date));
}

// الاستعلام: جلب عدد السائقين لكل نوع توظيف خلال الفترة المحددة
$sql = "SELECT 
            employmentType, 
            COUNT(*) AS `count` 
        FROM 
            `driver` 
        WHERE 
            DATE(created_at) >= '$start_date' 
            AND DATE(created_at) <= '$end_date'
        GROUP BY 
            employmentType";

try {
    $stmt = $con->prepare($sql);
    $stmt->execute();
    $stats_data = $stmt->fetchAll(PDO::FETCH_ASSOC);

    if ($stats_data) {
        // طباعة البيانات كـ JSON مع إضافة التواريخ المستخدمة للعلم
        printSuccess([
            "data" => $stats_data,
            "period" => [
                "start" => $start_date,
                "end" => $end_date
            ]
        ]);
    } else {
        jsonError("No data found for the selected period");
    }

} catch (PDOException $e) {
    // في حال حدوث خطأ في قاعدة البيانات
    jsonError("Database error: " . $e->getMessage());
}
?>

File: serviceapp/getRidesStatic.php

<?php
require_once __DIR__ . '/../connect.php';

// 1. استقبال تواريخ البداية والنهاية بدلاً من الشهر والسنة فقط
if (isset($_POST['start_date']) && isset($_POST['end_date'])) {
    // إذا أرسل التطبيق تواريخ محددة (الوضع الجديد)
    $start_date = $_POST['start_date']; // Format: YYYY-MM-DD
    $end_date   = $_POST['end_date'];   // Format: YYYY-MM-DD
} else {
    // (Fallback) إذا لم يرسل تواريخ، نستخدم منطق الشهر والسنة القديم
    $current_month = isset($_POST['month']) ? $_POST['month'] : date('m');
    $current_year  = isset($_POST['year'])  ? $_POST['year']  : date('Y');
    
    // التأكد من أن صيغة الشهر خانتين
    $current_month = str_pad($current_month, 2, "0", STR_PAD_LEFT);
    
    $start_date = date('Y-m-d', strtotime($current_year . '-' . $current_month . '-01'));
    $end_date   = date('Y-m-t', strtotime($start_date));
}

// 2. جملة الـ SQL المعدلة لتعمل مع النطاق الزمني
$sql = "
WITH RECURSIVE date_series AS (
    SELECT '$start_date' AS date
    UNION ALL
    SELECT DATE_ADD(date, INTERVAL 1 DAY)
    FROM date_series
    WHERE date < '$end_date'
)
SELECT 
    date_series.date AS day, 
    -- حساب الرحلات المنتهية في هذا اليوم
    COALESCE(SUM(ride.status = 'Finished'), 0) AS totalRides,
    
    -- حساب الإجمالي للفترة المحددة كاملة (وليس للشهر فقط)
    (SELECT COUNT(*) FROM ride 
     WHERE ride.created_at >= '$start_date' 
     AND ride.created_at <= '$end_date 23:59:59'
     AND ride.status = 'Finished') AS totalMonthly

FROM 
    date_series
LEFT JOIN 
    ride ON DATE(ride.created_at) = date_series.date 
    AND ride.status = 'Finished'
WHERE 
    date_series.date >= '$start_date' 
    AND date_series.date <= '$end_date'
GROUP BY 
    date_series.date
ORDER BY 
    date_series.date ASC;
";

$stmt = $con->prepare($sql);
$stmt->execute();
$data = $stmt->fetchAll(PDO::FETCH_ASSOC);

if ($data) {
    jsonSuccess($data);
} else {
    jsonError("No data found");
}
?>

File: serviceapp/getEmployeeStatic.php

<?php
require_once __DIR__ . '/../connect.php';

// استقبال الشهر والسنة، أو استخدام الحالي كافتراضي
$current_month = isset($_POST['month']) ? $_POST['month'] : date('m');
$current_year  = isset($_POST['year'])  ? $_POST['year']  : date('Y');

// التأكد من أن صيغة الشهر خانتين (مثلاً 5 تصبح 05)
$current_month = str_pad($current_month, 2, "0", STR_PAD_LEFT);

// حساب أول يوم وآخر يوم بناءً على الشهر والسنة المستلمة
$first_day_of_month = date('Y-m-d', strtotime($current_year . '-' . $current_month . '-01'));
$last_day_of_month  = date('Y-m-t', strtotime($first_day_of_month));

// تم تعديل الاستعلام ليستخدم المتغيرات $first_day_of_month و $last_day_of_month
$sql = "SELECT 
    DATE(d.created_at) AS `date`, 
    d.`maritalStatus` AS NAME, 
    COUNT(*) AS `count` 
FROM 
    `driver` d 
WHERE 
    d.`maritalStatus` IN ('mayar','masa', 'shahd', 'rama2','rama1') 
    AND DATE(d.created_at) >= '$first_day_of_month' 
    AND DATE(d.created_at) <= '$last_day_of_month'
GROUP BY 
    `date`, d.`maritalStatus` 
ORDER BY 
    `date` ASC;
";

$stmt = $con->prepare($sql);
$stmt->execute();
$passenger_data = $stmt->fetchAll(PDO::FETCH_ASSOC);

if ($passenger_data) {
    // طباعة البيانات كـ JSON
    jsonSuccess($data = $passenger_data);
} else {
    // طباعة رسالة فشل
    jsonError($message = "No data found");
}
?>

File: serviceapp/getPassengersStatic.php

<?php
require_once __DIR__ . '/../connect.php';

// منع الأخطاء النصية وضبط الترويسة
error_reporting(0);
header('Content-Type: application/json');

// 1. استقبال التواريخ
if (isset($_POST['start_date']) && isset($_POST['end_date'])) {
    $start_date = $_POST['start_date'];
    $end_date   = $_POST['end_date'];
} else {
    // Fallback: استخدام الشهر والسنة الحالية أو المرسلة
    $current_month = isset($_POST['month']) ? str_pad($_POST['month'], 2, "0", STR_PAD_LEFT) : date('m');
    $current_year  = isset($_POST['year'])  ? $_POST['year']  : date('Y');
    
    $start_date = date('Y-m-d', strtotime("$current_year-$current_month-01"));
    $end_date   = date('Y-m-t', strtotime($start_date));
}

// 2. جملة SQL المعدلة
$sql = "
WITH RECURSIVE date_series AS (
    SELECT '$start_date' AS date
    UNION ALL
    SELECT DATE_ADD(date, INTERVAL 1 DAY)
    FROM date_series
    WHERE date < '$end_date'
)
SELECT
    date_series.date AS day,
    
    -- (passengers) عدد الركاب اليومي
    COALESCE((SELECT COUNT(id) FROM passengers WHERE DATE(passengers.created_at) = date_series.date), 0) AS totalPassengers,
    
    -- (passengers) الإجمالي للفترة المحددة
    (
        SELECT COUNT(*) 
        FROM passengers 
        WHERE passengers.created_at BETWEEN '$start_date' AND '$end_date 23:59:59'
    ) AS totalMonthly

FROM
    date_series
GROUP BY date_series.date
ORDER BY date_series.date ASC; 
";
// ملاحظة: جعلت الترتيب ASC (تصاعدي) لأن الرسم البياني يحتاج الأيام من البداية للنهاية

try {
    $stmt = $con->prepare($sql);
    $stmt->execute();
    $passenger_data = $stmt->fetchAll(PDO::FETCH_ASSOC);

    if ($passenger_data) {
        echo json_encode(array("status" => "success", "message" => $passenger_data));
    } else {
        echo json_encode(array("status" => "success", "message" => []));
    }
} catch (PDOException $e) {
    echo json_encode(array("status" => "failure", "message" => $e->getMessage()));
}
?>

File: serviceapp/web/getDrivers.php

<?php
// إعدادات الإنتاج (إخفاء الأخطاء عن المستخدم)
ini_set('display_errors', 0);
error_reporting(E_ALL);

// ضبط الترويسة والترميز UTF-8 هام جداً للنصوص العربية
header('Content-Type: application/json; charset=utf-8');

require_once __DIR__ . '/../../get_connect.php';

// ضمان خروج النصوص العربية من قاعدة البيانات بشكل سليم
if (isset($con)) {
    $con->exec("set names utf8mb4");
}

$phone = "";
if (isset($_GET['phone_number'])) {
    $phone = htmlspecialchars(strip_tags($_GET['phone_number']));
} elseif (isset($_POST['phone_number'])) {
    $phone = htmlspecialchars(strip_tags($_POST['phone_number']));
} else {
    $phone = filterRequest("phone_number"); 
}

if (empty($phone)) {
    jsonError("Phone number is required");
    exit;
}

// تشفير الرقم للبحث
$phoneEncrypted = $encryptionHelper->encryptData($phone);

// الاستعلام: نختار الحقول بدقة لتجنب التضارب
$sql = "SELECT 
            d.id as driver_id,
            d.name_arabic as driver_name_encrypted, -- الاسم من جدول السائق
            d.phone as phone_encrypted,
            d.gender as gender_encrypted
            
        FROM 
            `driver` d
     
        WHERE 
            d.phone = ? 
               LIMIT 1";

try {
    $stmt = $con->prepare($sql);
    $stmt->execute([$phoneEncrypted]);
    
    if ($stmt->rowCount() > 0) {
        $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);

        foreach ($rows as &$item) {
            // ============================================
            // 1. فك تشفير الحقول المشفرة فقط (حسب ملف CSV)
            // ============================================
            
            // بيانات السائق
            if (!empty($item['driver_name_encrypted'])) {
                $item['driverName'] = $encryptionHelper->decryptData($item['driver_name_encrypted']);
            }
            if (!empty($item['phone_encrypted'])) {
                $item['phone'] = $encryptionHelper->decryptData($item['phone_encrypted']);
            }
            if (!empty($item['gender_encrypted'])) {
                $item['gender'] = $encryptionHelper->decryptData($item['gender_encrypted']);
            }
           

           
        }

        jsonSuccess($rows);

    } else {
        jsonError("No driver found with this phone number");
    }

} catch (PDOException $e) {
    error_log("SQL Error: " . $e->getMessage());
    jsonError("Database error");
} catch (Exception $e) {
    error_log("General Error: " . $e->getMessage());
    jsonError("System error");
}
?>

File: serviceapp/work/addDriverWantWork.php

<?php
require_once __DIR__ . '/../../connect.php';

// جلب البيانات من الطلب
$driver_name   = filterRequest("driver_name");
$national_id   = filterRequest("national_id");
$birth_date    = filterRequest("birth_date");
$license_type  = filterRequest("license_type");
$phone         = filterRequest("phone");
$site          = filterRequest("site");

// إعداد استعلام آمن باستخدام bind parameters
$sql = "INSERT INTO `driversWantWork`(
    `driver_name`,
    `phone`,
    `national_id`,
    `birth_date`,
    `license_type`,
    `site`
) VALUES (
    :driver_name,
    :phone,
    :national_id,
    :birth_date,
    :license_type,
    :site
)";

$stmt = $con->prepare($sql);

// ربط القيم
$stmt->bindParam(':driver_name', $driver_name);
$stmt->bindParam(':phone', $phone);
$stmt->bindParam(':national_id', $national_id);
$stmt->bindParam(':birth_date', $birth_date);
$stmt->bindParam(':license_type', $license_type);
$stmt->bindParam(':site', $site);

// تنفيذ الاستعلام
if ($stmt->execute()) {
    jsonSuccess(null, "Driver data saved successfully");
} else {
    jsonError("Failed to save driver data");
}
?>

File: serviceapp/work/addCarWantWork.php

<?php
require_once __DIR__ . '/../../connect.php';
header('Content-Type: application/json; charset=utf-8');

// دوال مساعدة لو لم تكن موجودة


// جلب بيانات السيارة من الطلب
$owner_name         = $encryptionHelper->encryptData(filterRequest("owner_name"));
$phone              = $encryptionHelper->encryptData(filterRequest("phone")); // 🔒
$car_number         = $encryptionHelper->encryptData(filterRequest("car_number"));
$manufacture_year   = filterRequest("manufacture_year");
$car_model          = filterRequest("car_model");
$car_type           = filterRequest("car_type");
$site               = filterRequest("site");
$registration_date  = filterRequest("registration_date");

// تحقق بسيط من القيم المطلوبة
if (empty($owner_name) || empty($phone)) {
    jsonError("Missing required fields", 422);
}

// SQL مع bind parameters
$sql = "INSERT INTO `carsToWork`(
    `owner_name`,
    `phone`,
    `car_number`,
    `manufacture_year`,
    `car_model`,
    `car_type`,
    `site`,
    `registration_date`
) VALUES (
    :owner_name,
    :phone,
    :car_number,
    :manufacture_year,
    :car_model,
    :car_type,
    :site,
    :registration_date
)";

try {
    $stmt = $con->prepare($sql);

    $stmt->bindParam(':owner_name', $owner_name);
    $stmt->bindParam(':phone', $phone);
    $stmt->bindParam(':car_number', $car_number);
    $stmt->bindParam(':manufacture_year', $manufacture_year);
    $stmt->bindParam(':car_model', $car_model);
    $stmt->bindParam(':car_type', $car_type);
    $stmt->bindParam(':site', $site);
    $stmt->bindParam(':registration_date', $registration_date);

    if ($stmt->execute()) {
        printSuccess("Car data saved successfully", ["insert_id" => $con->lastInsertId()]);
    } else {
        $err = $stmt->errorInfo();
        jsonError("Failed to save car data: " . ($err[2] ?? 'unknown error'), 500);
    }
} catch (Exception $e) {
    jsonError("Exception: " . $e->getMessage(), 500);
}
?>

File: ride/rate/add.php

<?php
require_once __DIR__ . '/../../connect.php';

$passenger_id = filterRequest("passenger_id");
$driverID = filterRequest("driverID");
$rideId = filterRequest("rideId");
$rating = filterRequest("rating");
$comment = filterRequest("comment");

$sql = "INSERT INTO `ratingPassenger` (
    `passenger_id`, `driverID`, `rideId`, `rating`, `comment`
) VALUES (
    :passenger_id, :driverID, :rideId, :rating, :comment
)";

$stmt = $con->prepare($sql);
$stmt->bindParam(':passenger_id', $passenger_id);
$stmt->bindParam(':driverID', $driverID);
$stmt->bindParam(':rideId', $rideId);
$stmt->bindParam(':rating', $rating);
$stmt->bindParam(':comment', $comment);

$stmt->execute();

if ($stmt->rowCount() > 0) {
    jsonSuccess(null, "Rate inserted successfully");
} else {
    jsonError("Failed to save rating information");
}
?>

File: ride/rate/add_rate_app.php

<?php
require_once __DIR__ . '/../../connect.php';

$name = filterRequest("name");
$email = filterRequest("email");
$phone = filterRequest("phone");
$userId = filterRequest("userId");
$userType = filterRequest("userType");
$rating = filterRequest("rating");
$comment = filterRequest("comment");

$email = $encryptionHelper->encryptData($email);
$phone = $encryptionHelper->encryptData($phone);

// Insert into `ratingApp` table
$sql = "INSERT INTO `ratingApp`(`id`, `name`, `email`, `phone`, `userId`, `userType`, `rating`, `comment`) 
        VALUES (null, :name, :email, :phone, :userId, :userType, :rating, :comment)";

$stmt = $con->prepare($sql);
$stmt->bindParam(':name', $name);
$stmt->bindParam(':email', $email);
$stmt->bindParam(':phone', $phone);
$stmt->bindParam(':userId', $userId);
$stmt->bindParam(':userType', $userType);
$stmt->bindParam(':rating', $rating);
$stmt->bindParam(':comment', $comment);
$stmt->execute();

if ($stmt->rowCount() > 0) {
    jsonSuccess($message = 'Rating inserted successfully');
} else {
    jsonError($message = "Failed to save rating information");
}
?>

File: ride/rate/addRateToDriver.php

<?php
require_once __DIR__ . '/../../connect.php';

// --- استقبال المتغيرات ---
$passenger_id = filterRequest("passenger_id");
$driver_id    = filterRequest("driver_id");
$ride_id      = filterRequest("ride_id");
$rating       = filterRequest("rating");
$comment      = filterRequest("comment");

try {
    // التحقق من صحة البيانات الأساسية قبل البدء
    if (empty($passenger_id) || empty($driver_id) || empty($ride_id)) {
        throw new Exception("Required fields are missing");
    }

    $sql = "INSERT INTO `ratingDriver`(
        `passenger_id`, `driver_id`, `ride_id`, `rating`, `comment`
    ) VALUES (
        :passenger_id, :driver_id, :ride_id, :rating, :comment
    )";

    $stmt = $con->prepare($sql);
    $stmt->bindParam(':passenger_id', $passenger_id);
    $stmt->bindParam(':driver_id', $driver_id);
    $stmt->bindParam(':ride_id', $ride_id);
    $stmt->bindParam(':rating', $rating);
    $stmt->bindParam(':comment', $comment);

    $stmt->execute();

    if ($stmt->rowCount() > 0) {
        jsonSuccess(null, "Rate inserted successfully");
    } else {
        // في حال لم يتم الإدخال ولكن لم يحدث خطأ فني (نادرة الحدوث في Insert)
        jsonError("Failed to save rating information");
    }

} catch (PDOException $e) {
    // --- هذا القسم خاص بأخطاء قاعدة البيانات ---
    
    // 1. تسجيل الخطأ في ملف نصي على السيرفر (للمطور فقط)
    // سيتم إنشاء ملف اسمه errors.log في نفس المجلد إذا لم يكن موجوداً
    $errorMsg = "[" . date("Y-m-d H:i:s") . "] DB Error: " . $e->getMessage() . " | RideID: $ride_id \n";
    file_put_contents("errors.log", $errorMsg, FILE_APPEND);

    // 2. إرجاع رسالة خطأ عامة للتطبيق
    jsonError("Database Error: Could not save rating");

} catch (Exception $e) {
    // --- هذا القسم خاص بالأخطاء العامة الأخرى ---
    
    $errorMsg = "[" . date("Y-m-d H:i:s") . "] General Error: " . $e->getMessage() . "\n";
    file_put_contents("errors.log", $errorMsg, FILE_APPEND);
    
    jsonError("Error: " . $e->getMessage());
}
?>

File: ride/rate/getPassengerRate.php

<?php
require_once __DIR__ . '/../../connect.php';

$passengerId = filterRequest("passenger_id");

$sql = "SELECT
    COALESCE(ROUND(AVG(ratingPassenger.rating), 2), 5) as rating
FROM
    ratingPassenger
WHERE
    ratingPassenger.passenger_id = :passenger_id";

$stmt = $con->prepare($sql);
$stmt->bindParam(':passenger_id', $passengerId);
$stmt->execute();

if ($stmt->rowCount() > 0) {
    $row = $stmt->fetch(PDO::FETCH_ASSOC);
    jsonSuccess($row);
} else {
    jsonError("No rating record found");
}
?>

File: ride/rate/sendEmailRateingApp.php

<?php
require_once __DIR__ . '/../../connect.php';

// --- الخطوة 1: استلام كافة البيانات من التطبيق ---
$email   = filterRequest("email");
$name    = filterRequest("name");
$rating  = filterRequest("rating");
$comment = filterRequest("comment");
$phone   = filterRequest("phone"); // **إضافة: استقبال رقم الهاتف**

// **تحسين: جلب أرقام الدعم من متغيرات البيئة لسهولة التعديل**
$SERVICE_PHONE1 = getenv("SERVICE_PHONE1") ?: 'الرقم الأول غير متوفر';
$SERVICE_PHONE2 = getenv("SERVICE_PHONE2") ?: 'الرقم الثاني غير متوفر';





// --- الخطوة 2: تجهيز رسالة واتساب مخصصة للكباتن بناءً على التقييم ---
$whatsappMessage = "";
if ($rating <= 4) {
    $whatsappMessage = "أهلاً كابتن $name، 👋

نشكرك على تقييمك لتطبيق *سيرو* بـ $rating نجوم. نحن نقدر رأيك كثيراً ونسعى دائماً لتحسين خدماتنا.

إذا واجهتك أي مشاكل أو كان لديك أي اقتراحات، يسعدنا تواصلك معنا مباشرة عبر أرقام الدعم التالية لمساعدتك بشكل أفضل:
- $SERVICE_PHONE1
- $SERVICE_PHONE2

فريق سيرو";
} else {
    $whatsappMessage = "أهلاً كابتن $name، ✨

شكراً جزيلاً لتقييمك الرائع ($rating نجوم) لتطبيق **سيرو**! يسعدنا أنك تحظى بتجربة مميزة معنا.

نتمنى لك رحلات آمنة وموفقة دائماً.

فريق سيرو";
}

// --- الخطوة 3: إرسال رسالة الواتساب ---
if (!empty($phone)) {
    if (sendWhatsAppFromServer($phone, $whatsappMessage)) {
        echo "WhatsApp message sent successfully to $phone.\n";
    } else {
        echo "Failed to send WhatsApp message.\n";
    }
} else {
    echo "Phone number not provided, skipping WhatsApp.\n";
}


// --- الخطوة 4: إرسال البريد الإلكتروني (كنظام احتياطي) ---
$admin = 'support@intaleqapp.com';
$headers = "MIME-Version: 1.0" . "\r\n";
$headers .= "Content-type: text/html; charset=UTF-8" . "\r\n";
$headers .= "From: $admin" . "\r\n";

$subject = "نشكرك على تقييمك لتطبيق سيرو";
$bodyEmail = "
<html><body dir='rtl' style='text-align:right;'>
<p>أهلاً كابتن $name،</p>
<p>نشكرك جزيل الشكر على تقييمك لتطبيق <strong>سيرو</strong>!</p>
<p>لقد استلمنا تقييمك وهو <strong>$rating نجوم</strong>.</p>
<p>تعليقك: \"$comment\"</p>
<p>نحن نقدر ملاحظاتك، ونسعد دائماً بتواصلك معنا لتحسين تجربتك. إذا كان لديك أي استفسار، لا تتردد بالرد على هذا البريد.</p>
<p>مع خالص الشكر،</p>
<p>فريق سيرو.</p>
</body></html>";

if (mail($email, $subject, $bodyEmail, $headers)) {
    echo "Email sent successfully to $email.";
} else {
    echo "Failed to send email.";
}
?>


File: ride/rate/getDriverRate.php

<?php
require_once __DIR__ . '/../../get_connect.php';
$driver_id = filterRequest("driver_id");

$sql = "SELECT
    COALESCE(ROUND(AVG(ratingDriver.rating), 2), 5) as rating
FROM
    ratingDriver
WHERE
    ratingDriver.driver_id = :driver_id";

$stmt = $con->prepare($sql);
$stmt->bindParam(':driver_id', $driver_id);
$stmt->execute();

if ($stmt->rowCount() > 0) {
    // Fetch the record
    $row = $stmt->fetchAll(PDO::FETCH_ASSOC);
   
    jsonSuccess($row);
} else {
    // Print a failure message
    jsonError($message = "No rating record found");
}
?>

File: ride/places_syria/add.php


File: ride/places_syria/get.php

<?php
/**
 * Get Places - Optimized with FULLTEXT and SPATIAL indexes.
 * يستخدم الفهارس الذكية للبحث السريع جداً.
 * * يتطلب:
 * - connect.php: $con (PDO object) + filterRequest() + jsonSuccess() / jsonError()
 * - جدول 'places11' مهيأ بالفهارس (FULLTEXT & SPATIAL)
 */

require_once __DIR__ . '/../../connect.php';

// اسم الجدول المستهدف
$tableName = 'palces11';

// تأكد من أن PDO يرمي استثناءات عند حدوث أخطاء
try {
    $con->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
    // تجاهل الخطأ إذا كان قد تم تعيينه بالفعل
}

// 1. استقبال المدخلات باستخدام دالة filterRequest الخاصة بك
$query  = trim((string) filterRequest("query"));
$latMin = filterRequest("lat_min");
$latMax = filterRequest("lat_max");
$lngMin = filterRequest("lng_min");
$lngMax = filterRequest("lng_max");

// 2. التحقق من المدخلات
if ($query === "" || $latMin === null || $latMax === null || $lngMin === null || $lngMax === null) {
    jsonError("Missing required parameters: query, lat_min, lat_max, lng_min, lng_max");
    exit;
}

// تحويل الإحداثيات إلى أرقام عشرية
$latMin = (float) $latMin;
$latMax = (float) $latMax;
$lngMin = (float) $lngMin;
$lngMax = (float) $lngMax;


// 3. بناء الاستعلام الذكي (الجزء المحدّث)

// تحضير كلمة البحث لوضعها في MATCH() AGAINST()
// نضيف '*' لكل كلمة للبحث عن الكلمات التي تبدأ بهذا الجزء
$search_terms = preg_split('/\s+/', $query, -1, PREG_SPLIT_NO_EMPTY);
$search_boolean = '';
foreach ($search_terms as $term) {
    $search_boolean .= '+' . $term . '* '; // '+' تعني أن الكلمة يجب أن تكون موجودة
}
$search_boolean = trim($search_boolean);


// بناء المضلع الجغرافي (Bounding Box Polygon) للفهرس المكاني
$bbox_wkt = sprintf(
    'POLYGON((%f %f, %f %f, %f %f, %f %f, %f %f))',
    $lngMin, $latMin,
    $lngMax, $latMin,
    $lngMax, $latMax,
    $lngMin, $latMax,
    $lngMin, $latMin
);


// الاستعلام النهائي الذي يجمع بين البحث النصي والجغرافي
$sql = "
    SELECT
        id, latitude, longitude, name, name_ar, name_en, address, category, created_at
    FROM 
        `{$tableName}`
    WHERE
        -- الشرط الأول: البحث بالنص الكامل (سريع جداً)
        MATCH(name, name_ar, name_en, address, category) AGAINST(? IN BOOLEAN MODE)
        
        -- الشرط الثاني: البحث الجغرافي (سريع جداً)
        AND ST_CONTAINS(ST_GEOMFROMTEXT(?), location)
    LIMIT 50; -- حد أعلى للنتائج الأولية
";

// 4. تنفيذ الاستعلام وإرجاع النتيجة
try {
    $stmt = $con->prepare($sql);
    
    // ربط المتغيرات بالاستعلام بالترتيب
    $stmt->execute([$search_boolean, $bbox_wkt]);
    
    $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
    
    jsonSuccess($rows);

} catch (PDOException $e) {
    // يمكنك استخدام هذا السطر أثناء التطوير لعرض الخطأ الفعلي
    // jsonError('DB Error: ' . $e->getMessage()); exit;

    // تسجيل الخطأ في سجلات الخادم للرجوع إليه لاحقاً
    error_log("search_places_optimized.php error: " . $e->getMessage());
    jsonError("Database query error occurred");
}
?>

File: ride/places_syria/reverse_geocode.php

<?php
// ضبط الهيدر لإرجاع JSON بترميز UTF-8
header('Content-Type: application/json; charset=utf-8');

// --- إعدادات الاتصال بقاعدة البيانات ---
$servername = "localhost";
$username = "routeuser";       // <== عدّل
$password = "VETA9mX4tSZzm6AGouIM";   // <== عدّل
$dbname = "routedb";           // <== عدّل

// --- استقبال الإحداثيات من الطلب ---
$input_lat = isset($_GET['lat']) ? (float)$_GET['lat'] : null;
$input_lon = isset($_GET['lon']) ? (float)$_GET['lon'] : null;

// التحقق من وجود الإحداثيات
if ($input_lat === null || $input_lon === null) {
    echo json_encode(['status' => 'error', 'message' => 'Missing lat or lon parameters']);
    exit;
}

// --- الاتصال بقاعدة البيانات ---
$conn = new mysqli($servername, $username, $password, $dbname);
$conn->set_charset("utf8mb4");
if ($conn->connect_error) {
     echo json_encode(['status' => 'error', 'message' => 'Database connection failed: ' . $conn->connect_error]);
     exit;
}

// --- دالة لتحليل other_tags (نفس الدالة من السكربت السابق) ---
function parseHstoreValue($hstoreString, $keyToFind) {
    if (empty($hstoreString) || empty($keyToFind)) return null;
    if (preg_match('/"' . preg_quote($keyToFind, '/') . '"\s*=>\s*"([^"]+)"/', $hstoreString, $matches)) {
        $value = $matches[1];
        $decodedValue = urldecode($value);
        $decodedValue = urldecode($decodedValue);
        $cleanedValue = iconv('UTF-8', 'UTF-8//IGNORE', $decodedValue);
        return ($cleanedValue === false || trim($cleanedValue) === '') ? null : $cleanedValue;
    }
    return null;
}


// --- الاستعلام الرئيسي: البحث عن أقرب نقطة باستخدام الفهرس المكاني ---
// نختار الأعمدة الأساسية + أعمدة المناطق المحسوبة مسبقاً + other_tags
$sql = "
    SELECT
        p.name,
        p.neighbourhood_name,
        p.city_name,
        p.other_tags,
        ST_Distance_Sphere(
            p.geom,
            ST_PointFromText(CONCAT('POINT(', ?, ' ', ?, ')'), 4326)
        ) AS distance_meters
    FROM
        osm_points_with_area p
    WHERE
        -- استخدام MBRContains للفلترة الأولية السريعة (باستخدام الفهرس المكاني)
        MBRContains(
             ST_Buffer(ST_PointFromText(CONCAT('POINT(', ?, ' ', ?, ')'), 4326), 0.01), -- مربع بحث ~ 1 كم
             p.geom
        )
    -- الترتيب الدقيق حسب المسافة الأقرب (يستخدم الفهرس المكاني بكفاءة)
    ORDER BY
        p.geom <-> ST_PointFromText(CONCAT('POINT(', ?, ' ', ?, ')'), 4326)
    LIMIT 1"; // نريد أقرب نقطة فقط

$stmt = $conn->prepare($sql);
if ($stmt === false) {
     echo json_encode(['status' => 'error', 'message' => 'Failed to prepare statement: ' . $conn->error]);
     $conn->close();
     exit;
}

// ربط المتغيرات (6 متغيرات: lon, lat مرتين للمربع ومرة للمسافة)
$stmt->bind_param("dddddd", $input_lon, $input_lat, $input_lon, $input_lat, $input_lon, $input_lat);

$stmt->execute();
$result = $stmt->get_result();

// --- تنسيق وإرجاع النتيجة ---
if ($result->num_rows > 0) {
    $row = $result->fetch_assoc();

    // استخراج التفاصيل الإضافية من other_tags
    $name_ar = parseHstoreValue($row['other_tags'], 'name:ar');
    $addr_street = parseHstoreValue($row['other_tags'], 'addr:street');
    $amenity = parseHstoreValue($row['other_tags'], 'amenity');
    $shop = parseHstoreValue($row['other_tags'], 'shop');

    // بناء اسم وصفي (الأولوية للعربي إن وجد)
    $primaryName = $name_ar ?? $row['name'] ?? $addr_street ?? null; // الاسم الأساسي للنقطة
    $displayName = $primaryName ?? 'موقع قريب'; // اسم افتراضي إذا لم يوجد اسم

    // إضافة اسم الحي والمدينة (المحسوبة مسبقاً)
    $addressParts = array_filter([
        $row['neighbourhood_name'],
        $row['city_name']
    ]);
    if (!empty($addressParts)) {
        // تجنب تكرار اسم المدينة إذا كان هو نفسه اسم النقطة
        if ($primaryName !== $row['city_name']) {
             $displayName .= '، ' . implode('، ', $addressParts);
        } elseif ($row['neighbourhood_name'] && $primaryName !== $row['neighbourhood_name']) {
             $displayName .= '، ' . $row['neighbourhood_name'];
        }
    }

    // إرجاع النتيجة كـ JSON
    echo json_encode([
        'status' => 'ok',
        'display_name' => $displayName,           // الاسم المنسق للعرض
        'name' => $row['name'],                   // الاسم الأصلي (إن وجد)
        'name_ar' => $name_ar,                   // الاسم العربي (إن وجد)
        'street' => $addr_street,               // اسم الشارع (إن وجد)
        'neighbourhood' => $row['neighbourhood_name'], // اسم الحي (المحسوب مسبقاً)
        'city' => $row['city_name'],             // اسم المدينة (المحسوب مسبقاً)
        'amenity' => $amenity,                   // نوع الخدمة (إن وجد)
        'shop' => $shop,                         // نوع المحل (إن وجد)
        'distance_meters' => round($row['distance_meters'], 1) // المسافة لأقرب POI
    ], JSON_UNESCAPED_UNICODE); // مهم لعرض العربية بشكل صحيح

} else {
    // لم يتم العثور على نقطة قريبة، ابحث عن أقرب مدينة/حي كحل بديل
     $areaSqlFallback = "
        SELECT name, other_tags, place_type
        FROM osm_areas
        ORDER BY ST_Distance_Sphere(geom, ST_PointFromText(CONCAT('POINT(', ?, ' ', ?, ')'), 4326)) ASC
        LIMIT 1";
     $stmtFallback = $conn->prepare($areaSqlFallback);
     if ($stmtFallback) {
         $stmtFallback->bind_param("dd", $input_lon, $input_lat);
         $stmtFallback->execute();
         $fallbackResult = $stmtFallback->get_result()->fetch_assoc();
         $stmtFallback->close();

         if ($fallbackResult) {
             $fallbackNameAr = parseHstoreValue($fallbackResult['other_tags'], 'name:ar');
             $fallbackDisplayName = $fallbackNameAr ?? $fallbackResult['name'] ?? 'منطقة غير معروفة';
              echo json_encode([
                  'status' => 'ok',
                  'display_name' => $fallbackDisplayName,
                  ($fallbackResult['place_type'] === 'city' || $fallbackResult['place_type'] === 'town' || $fallbackResult['place_type'] === 'village') ? 'city' : 'neighbourhood' => $fallbackDisplayName
              ], JSON_UNESCAPED_UNICODE);
         } else {
             echo json_encode(['status' => 'not_found', 'message' => 'No nearby places or areas found']);
         }
     } else {
          echo json_encode(['status' => 'error', 'message' => 'Fallback query failed: ' . $conn->error]);
     }
}

$stmt->close();
$conn->close();
?>

File: ride/rides/start_ride.php

<?php
// start_ride.php
require_once __DIR__ . '/../../connect.php'; 

$ride_id   = filterRequest("id"); 
$driver_id = filterRequest("driver_id");
$status    = filterRequest("status"); // 'Begin'
$passengerToken = filterRequest("passengerToken");

if (!$ride_id || !$driver_id || !$status) {
    jsonError("Missing parameters");
    exit;
}

try {
    // 1. تحديث سيرفر الرحلات (Remote DB - con_ride)
    $stmtRemote = $con_ride->prepare("UPDATE ride SET status = ?, rideTimeStart = NOW() WHERE id = ?");
    $stmtRemote->execute([$status, $ride_id]);
    
    if ($stmtRemote->rowCount() == 0) {
        // ملاحظة: أحياناً التحديث لا يؤثر بصفوف إذا كانت البيانات نفسها، 
        // لكن هنا نفترض الفشل إذا لم يجد الرحلة.
        // يمكنك إكمال التنفيذ إذا كنت متأكداً أن الرحلة موجودة.
    }

    // 2. تحديث السيرفر المحلي (Local DB) والمعاملات
    $con->beginTransaction();
    
    // تحديث الرحلة محلياً
    $stmtMainRide = $con->prepare("UPDATE ride SET status = ?, rideTimeStart = NOW() WHERE id = ?");
    $stmtMainRide->execute([$status, $ride_id]);

    // تحديث أو إدخال في جدول Driver Orders
    $checkSql = "SELECT `order_id` FROM `driver_orders` WHERE `order_id` = ?";
    $checkStmt = $con->prepare($checkSql);
    $checkStmt->execute([$ride_id]);

    if ($checkStmt->rowCount() > 0) {
        $updateSql = "UPDATE `driver_orders` SET `driver_id` = ?, `status` = ?, `created_at` = NOW() WHERE `order_id` = ?";
        $con->prepare($updateSql)->execute([$driver_id, $status, $ride_id]);
    } else {
        $insertSql = "INSERT INTO `driver_orders` (`driver_id`, `order_id`, `created_at`, `status`) VALUES (?, ?, NOW(), ?)";
        $con->prepare($insertSql)->execute([$driver_id, $ride_id, $status]);
    }

    // =================================================================
    // 🔥 الخطوة 3: إشعار الراكب (Socket + FCM)
    // =================================================================
    
    // جلب بيانات الراكب من قاعدة البيانات لضمان الدقة
    $stmtPas = $con_ride->prepare("SELECT passenger_id FROM ride WHERE id = ?");
    $stmtPas->execute([$ride_id]);
    $passenger_id = $stmtPas->fetchColumn();

    if ($passenger_id) {
        
        // أ) إرسال السوكيت (Socket)
        // تم إلغاء التعليق عنه ليكون السيرفر هو المسؤول
        $socketPayload = [
            'ride_id'   => $ride_id,
            'status'    => 'started', // أو 'Begin' حسب ما يتوقعه التطبيق
            'msg'       => 'بدأت الرحلة، نتمنى لك سلامة الوصول 🚀'
        ];
        
        if (function_exists('notifyPassengerOnRideServer')) {
            notifyPassengerOnRideServer($passenger_id, $socketPayload);
        }

        // ب) إرسال FCM (Internal)
        if (!empty($passengerToken)) {
            $fcmData = [
                'ride_id'  => (string)$ride_id
            ];
            
            // 🔥 استخدام sendFCM_Internal
            sendFCM_Internal(
                $passengerToken,                  // الهدف
                "بدأت الرحلة 🏁",                 // العنوان
                "نتمنى لك رحلة آمنة ومريحة.",     // النص
                $fcmData,                         // البيانات
                "Trip is Begin",                  // التصنيف (حافظنا عليه كما هو في التطبيق)
                false                             // ليس Topic
            );
        }
    }

    $con->commit();
    jsonSuccess(null, "Ride started successfully");

} catch (PDOException $e) {
    if ($con->inTransaction()) {
        $con->rollBack();
    }
    jsonError("Exception: " . $e->getMessage());
}
?>

File: ride/rides/add.php

<?php
require_once __DIR__ . '/../../connect.php';

// 🚀 1. تسجيل بداية الطلب
error_log("🚀 [add_ride.php] Request Started.");

// استلام البيانات
$start_location      = filterRequest("start_location");
$end_location        = filterRequest("end_location");
$date_raw            = filterRequest("date"); // نستلم القيمة الخام
$time_raw            = filterRequest("time"); // نستلم القيمة الخام
$endtime_raw         = filterRequest("endtime");
$price               = filterRequest("price");
$passenger_id        = filterRequest("passenger_id");
$driver_id           = filterRequest("driver_id");
$status              = filterRequest("status");
$price_for_driver    = filterRequest("price_for_driver");
$price_for_passenger = filterRequest("price_for_passenger");
$distance            = filterRequest("distance");
$carType             = filterRequest("carType");

error_log(" [add_ride.php] Data Received. Processing dates...");

// 🛠️ 2. معالجة التواريخ لتناسب MySQL (الحل الجذري للمشكلة)
// تحويل "2025-12-18 09:48:26.805" إلى "2025-12-18" فقط
$date_formatted = date("Y-m-d", strtotime($date_raw)); 

// تحويل "2025-12-18 09:48:26.810" إلى "09:48:26" فقط
$time_formatted = date("H:i:s", strtotime($time_raw)); 

// معالجة وقت الانتهاء (قد يكون مدة أو وقت)
// نحاول استخراج الوقت منه، إذا فشل نضعه 00:00:00
$endtime_formatted = date("H:i:s", strtotime($endtime_raw));
if (!$endtime_formatted) {
    $endtime_formatted = "00:00:00"; 
}

// تجهيز مصفوفة البيانات
$data = [
    ":start_location"      => $start_location,
    ":end_location"        => $end_location,
    ":date"                => $date_formatted, // نستخدم الصيغة المعالجة
    ":time"                => $time_formatted, // نستخدم الصيغة المعالجة
    ":endtime"             => $endtime_formatted,
    ":price"               => $price,
    ":passenger_id"        => $passenger_id,
    ":driver_id"           => $driver_id,
    ":status"              => $status,
    ":carType"             => $carType,
    ":price_for_driver"    => $price_for_driver,
    ":price_for_passenger" => $price_for_passenger,
    ":distance"            => $distance,
];

// تسجيل البيانات التي سيتم إدخالها للتأكد
error_log(" [add_ride.php] Prepared Data: " . json_encode($data));

// ---------------------------------------------------------
// 3. الإضافة في السيرفر المحلي (Main DB)
// ---------------------------------------------------------

$sql = "INSERT INTO `ride` (
    `start_location`, `end_location`, `date`, `time`, `endtime`, 
    `price`, `passenger_id`, `driver_id`, `status`, `carType`, 
    `price_for_driver`, `price_for_passenger`, `distance`
) VALUES (
    :start_location, :end_location, :date, :time, :endtime, 
    :price, :passenger_id, :driver_id, :status, :carType, 
    :price_for_driver, :price_for_passenger, :distance
)";

try {
    error_log("🔄 [add_ride.php] Inserting into LOCAL DB...");
    
    $stmt = $con->prepare($sql);
    $stmt->execute($data);
    
    $insertedId = $con->lastInsertId();
    $count = $stmt->rowCount();

    error_log("✅ [add_ride.php] Local Insert Success. ID: $insertedId");

    if ($count > 0) {
        
        // ---------------------------------------------------------
        // 4. الإضافة في سيرفر التتبع (Tracking DB)
        // ---------------------------------------------------------
        
        $sqlRemote = "INSERT INTO `ride` (
            `id`, `start_location`, `end_location`, `date`, `time`, `endtime`, 
            `price`, `passenger_id`, `driver_id`, `status`, `carType`, 
            `price_for_driver`, `price_for_passenger`, `distance`
        ) VALUES (
            :id, :start_location, :end_location, :date, :time, :endtime, 
            :price, :passenger_id, :driver_id, :status, :carType, 
            :price_for_driver, :price_for_passenger, :distance
        )";

        // إضافة الـ ID للمصفوفة
        $data[':id'] = $insertedId;

        try {
            error_log("🔄 [add_ride.php] Inserting into REMOTE DB...");
            
            $stmtRemote = $con_ride->prepare($sqlRemote);
            $stmtRemote->execute($data);
            
            error_log("✅ [add_ride.php] Remote Insert Success.");
            
        } catch (PDOException $eRemote) {
            // نسجل خطأ الريموت لكن لا نوقف العملية لأن اللوكل تم بنجاح
            error_log("⚠️ [add_ride.php] Remote DB Error: " . $eRemote->getMessage());
        }

        // طباعة النجاح (JSON صحيح)
        jsonSuccess($insertedId);
        
    } else {
        error_log("❌ [add_ride.php] Failed to insert locally (Rows affected 0).");
        jsonError("Failed to save ride information locally");
    }

} catch (PDOException $e) {
    // تسجيل الخطأ بدقة
    error_log("❌ [add_ride.php] SQL Error: " . $e->getMessage());
    jsonError("Database Error: " . $e->getMessage());
}
?>

File: ride/rides/updateStausFromSpeed.php

<?php
//updateStausFromSpeed.php"; 

require_once __DIR__ . '/../../connect.php';

$rideId = filterRequest("id");
$status = filterRequest("status"); 
$driverId = filterRequest("driver_id");
// لم نعد نحتاج لمتغير $rideTimeStart لربطه بالـ SQL، لكن نتركه لاستلام القيمة من الطلب
$rideTimeStart = filterRequest("rideTimeStart"); 

// 🚀 1. تسجيل بداية الطلب والبيانات المستلمة
error_log("🚀 [accept_ride.php] Request Started. RideID: $rideId | DriverID: $driverId | Status: $status");

if (!$rideId || !$driverId || !$status) {
    error_log("❌ [accept_ride.php] Missing required parameters.");
    jsonError("Missing required parameters.");
    exit;
}

try {
    // ---------------------------------------------------------
    // 1. التحديث على سيرفر التتبع (صاحب القرار)
    // ---------------------------------------------------------
    
    error_log("🔄 [accept_ride.php] Attempting to update REMOTE Tracking DB for Ride ID: $rideId");

    $stmtRideRemote = $con_ride->prepare("UPDATE `ride` 
                                          SET `status` = :status,
                                              `driver_id` = :driverId,
                                              `rideTimeStart` = NOW() 
                                          WHERE `id` = :id
                                          AND `status` IN ('waiting', 'wait')
                                         ");

    $stmtRideRemote->execute([
        ':status' => $status,
        ':driverId' => $driverId, 
        ':id'      => $rideId
    ]);

    $count = $stmtRideRemote->rowCount();
    error_log(" [accept_ride.php] Remote DB Rows Affected: $count");

    // نتحقق: هل نجح التحديث في سيرفر التتبع؟
    if ($count > 0) {

        // ---------------------------------------------------------
        // 2. التحديث على السيرفر الرئيسي (تثبيت السجل فقط)
        // ---------------------------------------------------------
        
        error_log("🔄 [accept_ride.php] Remote success. Updating LOCAL Main DB...");

        $sqlUpdate = "UPDATE `ride`
                      SET `driver_id` = :driverId,
                          `status` = :status,
                          `rideTimeStart` = NOW()
                      WHERE id = :rideId
                      AND `status` IN ('waiting', 'wait') "; 

        $stmtUpdate = $con->prepare($sqlUpdate);
        $stmtUpdate->bindParam(":driverId", $driverId);
        $stmtUpdate->bindParam(":status", $status);
        $stmtUpdate->bindParam(":rideId", $rideId);
        $stmtUpdate->execute();

        error_log("✅ [accept_ride.php] Ride accepted and started successfully for Driver: $driverId");
        jsonSuccess(null, "Ride accepted and started successfully at " . date('Y-m-d H:i:s')); 

    } else {
        error_log("⚠️ [accept_ride.php] Failed to accept ride. It might be already taken, canceled, or invalid status.");
        jsonError("Ride cannot be accepted (Already taken, Canceled, or Invalid Status).");
    }

} catch (PDOException $e) {
    error_log("❌ [accept_ride.php] Database Error: " . $e->getMessage());
    jsonError("Database Error: " . $e->getMessage());
}
?>

File: ride/rides/gterideForDriverManyTime.php

<?php
require_once __DIR__ . '/../../connect.php';

// لا حاجة للمتغير id لأنه غير مستخدم فعليًا
// $id = filterRequest("id");

$sql = "
    SELECT
        (
            SELECT COUNT(*) 
            FROM `ride` 
            WHERE `status` = 'Finished' 
            AND `created_at` BETWEEN CURRENT_DATE() + INTERVAL 7 HOUR AND CURRENT_DATE() + INTERVAL 10 HOUR
        ) AS morning_count,
        (
            SELECT COUNT(*) 
            FROM `ride` 
            WHERE `status` = 'Finished' 
            AND `created_at` BETWEEN CURRENT_DATE() + INTERVAL 15 HOUR AND CURRENT_DATE() + INTERVAL 18 HOUR
        ) AS afternoon_count
";

$stmt = $con->prepare($sql);
$stmt->execute();

$row = $stmt->fetch(PDO::FETCH_ASSOC);

echo json_encode([
    "status" => "success",
    "data" => $row
]);
?>

File: ride/rides/getRideStatusFromStartApp.php

<?php
require_once __DIR__ . '/../../get_connect.php';

$passenger_id = filterRequest("passenger_id");

try {
    // =========================================================
    // 1. سيرفر الرحلات: جلب بيانات الرحلة
    // =========================================================
    $stmt = $con_ride->prepare("
        SELECT 
            id AS rideId,
            status,
            start_location,
            end_location,
            carType,
            driver_id,distance,
            price,
            created_at
        FROM ride
        WHERE passenger_id = ? 
        AND (
            status IN ( 'Apply', 'Begin') AND created_at >= NOW() - INTERVAL 2 HOUR
            OR (status = 'Finished' AND created_at >= NOW() - INTERVAL 24 HOUR)
        )
        ORDER BY created_at DESC 
        LIMIT 1
    ");
    
    $stmt->execute([$passenger_id]);
    $ride = $stmt->fetch(PDO::FETCH_ASSOC);

    if (!$ride) {
        echo json_encode(["status" => "failure", "message" => "No active ride found"]);
        exit;
    }

    // =========================================================
    // 2. السيرفر الرئيسي: جلب اسم السائق + متوسط تقييمه العام
    // =========================================================
    
    // ملاحظة: تم الحفاظ على الاستعلام كما هو
    // rateDriver: هو الاسم الذي سنستخدمه في PHP
    $stmt2 = $con->prepare("
        SELECT 
            d.first_name AS driverName,
            (SELECT AVG(rating) FROM ratingDriver WHERE driver_id = d.id) AS rateDriver,
            (SELECT COUNT(*) FROM ratingDriver WHERE ride_id = ?) AS thisRideRated
        FROM driver d
        WHERE d.id = ?
    ");
    
    $stmt2->execute([$ride['rideId'], $ride['driver_id']]);
    $driverData = $stmt2->fetch(PDO::FETCH_ASSOC);

    // =========================================================
    // 3. المعالجة النهائية
    // =========================================================
    
    if ($driverData) {
        // فك التشفير
        $ride['driverName'] = $encryptionHelper->decryptData($driverData['driverName']);
        
        // --- تصحيح الخطأ هنا ---
        // كان يستدعي driverAvg وهو غير موجود، تم تغييره لـ rateDriver
        $ride['rateDriver'] = $driverData['rateDriver'] ? round($driverData['rateDriver'], 2) : 5;
        
        // --- منطق هل تحتاج الرحلة لتقييم (needsReview) ---
        $isFinished = ($ride['status'] === 'Finished');
        $isRated    = ($driverData['thisRideRated'] > 0);
        
        $ride['needsReview'] = ($isFinished && !$isRated) ? 1 : 0;
        
    } else {
        // حالة عدم وجود سائق (نادراً ما تحدث إذا كان driver_id موجوداً في جدول الرحلات)
        $ride['driverName']   = null;
        $ride['rateDriver']   = 5; 
        $ride['needsReview']  = 0;
    }

    // تنظيف البيانات
    unset($ride['created_at']);

    echo json_encode([
        "status" => "success",
        "data"   => $ride
    ]);

} catch (Exception $e) {
    echo json_encode(["status" => "failure", "message" => $e->getMessage()]);
}
?>

File: ride/rides/update.php

<?php
require_once __DIR__ . '/../../connect.php';

// 🚀 تسجيل بداية العملية
error_log("🚀 [update.php] Request Started to update Ride Dynamic Data.");

$id = filterRequest("id");

if (!$id) {
    error_log("❌ [update.php] Missing ID.");
    jsonError("Missing ID");
    exit;
}

$columnValues = [];
$params = [':id' => $id];

// قائمة الحقول القابلة للتحديث
$fields = [
    "start_location", "end_location", "date", "time", "endtime", "price",
    "passenger_id", "driver_id", "status", "created_at", "updated_at",
    "rideTimeStart", "rideTimeFinish", "price_for_driver", "driverGoToPassengerTime",
    "price_for_passenger", "distance"
];

// بناء الاستعلام ديناميكياً باستخدام filterRequest
foreach ($fields as $field) {
    // نتحقق من وجود المفتاح في الـ POST
    if (isset($_POST[$field])) {
        // نستخدم دالة الفلترة الخاصة بك
        $value = filterRequest($field);
        
        $columnValues[] = "`$field` = :$field";
        $params[":$field"] = $value;
    }
}

// إذا لم يتم إرسال أي حقول للتحديث
if (empty($columnValues)) {
    error_log("⚠️ [update.php] No data provided in request to update.");
    jsonError("No data provided for update.");
    exit;
}

// تجميع جملة SQL
$setClause = implode(", ", $columnValues);
$sql = "UPDATE `ride` SET $setClause WHERE `id` = :id";

try {
    // ---------------------------------------------------------
    // 1. التحديث على سيرفر التتبع (Remote DB) - هو الأساس
    // ---------------------------------------------------------
    error_log("🔄 [update.php] Attempting to update REMOTE Tracking DB for Ride ID: $id");

    $stmtRemote = $con_ride->prepare($sql);
    $stmtRemote->execute($params);

    $count = $stmtRemote->rowCount();
    error_log(" [update.php] Remote DB Rows Affected: $count");

    // التحقق: هل نجح التحديث هناك؟
    if ($count > 0) {

        // ---------------------------------------------------------
        // 2. التحديث على السيرفر المحلي (Local DB) للمطابقة
        // ---------------------------------------------------------
        error_log("🔄 [update.php] Remote success. Updating LOCAL Main DB...");

        $stmtLocal = $con->prepare($sql);
        $stmtLocal->execute($params);

        error_log("✅ [update.php] Update successful on both servers.");
        
        // استخدام دالة النجاح الخاصة بك
        jsonSuccess(null, "Ride data updated successfully");

    } else {
        // لم يتم التحديث (إما البيانات نفسها لم تتغير، أو المعرف غير موجود في السيرفر البعيد)
        error_log("⚠️ [update.php] Remote Update returned 0 rows (Data same or ID not found).");
        
        // استخدام دالة الفشل (يمكنك تغيير الرسالة لتكون success إذا كنت لا تعتبر عدم تغيير البيانات خطأ)
        jsonError("No changes made (Remote DB affected 0 rows). Check ID or Data.");
    }

} catch (PDOException $e) {
    error_log("❌ [update.php] Database Error: " . $e->getMessage());
    jsonError("Database Error: " . $e->getMessage());
}
?>

File: ride/rides/cancel_ride_by_passenger.php

<?php
require_once __DIR__ . '/../../connect.php'; 

// cancel_ride_by_passenger.php

$rideId = filterRequest("ride_id");
$reason = filterRequest("reason");

if (!$rideId) {
    jsonError("Missing Ride ID");
    exit;
}

try {
    // جلب بيانات الرحلة للتحقق
    $stmt = $con->prepare("SELECT driver_id, status FROM ride WHERE id = ?");
    $stmt->execute([$rideId]);
    $ride = $stmt->fetch(PDO::FETCH_ASSOC);

    if (!$ride) {
        jsonError("Ride not found");
        exit;
    }

    $driverId = $ride['driver_id'];
    $currentStatus = $ride['status'];

    if ($currentStatus == 'Begin') {
        jsonError("Cannot cancel started ride");
        exit;
    }

    // =================================================================
    // 1. تحديث قواعد البيانات (Transaction)
    // =================================================================
    $con->beginTransaction();

    // تحديث waitingRides
    $updateWaiting = $con->prepare("UPDATE waitingRides SET status = ? WHERE id = ?");
    $updateWaiting->execute(['cancelled_by_passenger', $rideId]);

    // تحديث ride (محلي)
    $updateRide = $con->prepare("UPDATE ride SET status = ?, updated_at = NOW() WHERE id = ?");
    $updateRide->execute(['cancelled_by_passenger', $rideId]);

    // تحديث driver_orders
    if ($driverId > 0) {
        $updateOrder = $con->prepare("UPDATE driver_orders SET status = 'cancelled_by_passenger', notes = ? WHERE order_id = ? AND driver_id = ?");
        $updateOrder->execute([$reason, $rideId, $driverId]);
    }

    $con->commit();

    // تحديث السيرفر البعيد (Remote DB)
    if (isset($con_ride)) {
        try {
            $updateRide2 = $con_ride->prepare("UPDATE ride SET status = ?, updated_at = NOW() WHERE id = ?");
            $updateRide2->execute(['cancelled_by_passenger', $rideId]);
        } catch (PDOException $e) {
            error_log("Secondary DB update failed: " . $e->getMessage());
        }
    }

    // =================================================================
    // 2. إشعار السائق (Socket + FCM)
    // =================================================================
    if ($driverId > 0) {
        
        // أ) Socket (إشعار السائق في التطبيق فوراً)
        $socketUrl = 'http://188.68.36.205:2021';
        $internalKeyPath = '/home/siro-api/.internal_socket_key';
        $internalKey = file_exists($internalKeyPath) ? trim(file_get_contents($internalKeyPath)) : '';

        $ch = curl_init($socketUrl);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query([
            'action'    => 'cancel_ride',
            'driver_id' => $driverId,
            'ride_id'   => $rideId,
            'reason'    => $reason
        ]));
        if (!empty($internalKey)) curl_setopt($ch, CURLOPT_HTTPHEADER, ["x-internal-key: $internalKey"]);
        curl_setopt($ch, CURLOPT_TIMEOUT_MS, 500);
        curl_setopt($ch, CURLOPT_NOSIGNAL, 1);
        @curl_exec($ch);
        curl_close($ch);

        // ب) FCM (باستخدام الدالة الجديدة مع فك التشفير)
        $stmtToken = $con->prepare("SELECT token FROM driverToken WHERE captain_id = ?");
        $stmtToken->execute([$driverId]);
        $rawToken = $stmtToken->fetchColumn();

        if ($rawToken) {
            $driverToken = $rawToken;
            
            // 🔥 محاولة فك التشفير (لأن التوكنات غالباً مشفرة)
            if (!empty($encryptionHelper)) {
                try {
                    $decrypted = $encryptionHelper->decryptData($rawToken);
                    if ($decrypted !== false && !empty($decrypted)) {
                        $driverToken = trim($decrypted);
                    }
                } catch (Exception $e) {
                    // في حال الفشل نستخدم الخام
                }
            }

            // تجهيز البيانات
            $fcmData = [
                'category' => 'Cancel Trip',
                'ride_id'  => (string)$rideId,
                'reason'   => $reason
            ];

            // إرسال الإشعار
            sendFCM_Internal(
                $driverToken,                         // الهدف
                "إلغاء الرحلة 🚫",                    // العنوان
                "قام الراكب بإلغاء الرحلة: $reason",  // النص
                $fcmData,                             // البيانات
                'Cancel Trip',                        // التصنيف
                false                                 // ليس Topic
            );
        }
    }

    jsonSuccess(null, "Ride cancelled successfully");

} catch (PDOException $e) {
    if ($con->inTransaction()) $con->rollBack();
    error_log("Cancel ride error: " . $e->getMessage());
    jsonError("Database error occurred");
}
?>

File: ride/rides/get.php

<?php
require_once __DIR__ . '/../../connect.php';

$passenger_id = filterRequest("passenger_id");
$driver_id = filterRequest("driver_id");

try {
    // Step 1: Count rides for passenger or driver
    $baseSql = "SELECT COUNT(*) AS total_rows FROM `ride`";
    $params = [];

    if (!empty($passenger_id)) {
        $baseSql .= " WHERE passenger_id = :passenger_id";
        $params[':passenger_id'] = $passenger_id;
    } elseif (!empty($driver_id)) {
        $baseSql .= " WHERE driver_id = :driver_id";
        $params[':driver_id'] = $driver_id;
    }

    $stmt = $con->prepare($baseSql);
    $stmt->execute($params);
    $row = $stmt->fetch(PDO::FETCH_ASSOC);
    $total_rows = $row['total_rows'] ?? 0;

    if ($total_rows > 0) {
        // Step 2: Fetch the latest 10 ride records
        $rideSql = "SELECT * FROM `ride`";
        if (!empty($passenger_id)) {
            $rideSql .= " WHERE passenger_id = :passenger_id ORDER BY created_at DESC LIMIT 10";
        } elseif (!empty($driver_id)) {
            $rideSql .= " WHERE driver_id = :driver_id ORDER BY created_at DESC LIMIT 10";
        }

        $rideStmt = $con->prepare($rideSql);
        $rideStmt->execute($params);
        $rides = $rideStmt->fetchAll(PDO::FETCH_ASSOC);

        echo json_encode([
            "status" => "success",
            "data" => $rides
        ]);
    } else {
        jsonError("No rides found");
    }
} catch (PDOException $e) {
    jsonError("Database error: " . $e->getMessage());
}
?>

File: ride/rides/get_driver_location.php

<?php
// تضمين ملف الاتصال الذي يحتوي على تعريف السيرفرات الثلاثة ($con, $con_ride, $con_tracking)
// وكائن التشفير $encryptionHelper
require_once __DIR__ . '/../../get_connect.php';

// السماح بالوصول من أي دومين (لأن الرابط سيفتح في متصفح العميل)
header("Access-Control-Allow-Origin: *");
header("Content-Type: application/json; charset=UTF-8");

    $rideID = filter_input(INPUT_GET, 'id', FILTER_SANITIZE_NUMBER_INT);

    // تنظيف الـ Token: نتأكد من تعقيم الرموز الخاصة لمنع XSS
    $token = filter_input(INPUT_GET, 'token', FILTER_SANITIZE_SPECIAL_CHARS);

// التحقق من وصول البيانات
if (!$rideID || !$token) {
    http_response_code(400);
    echo json_encode(["status" => "failure", "message" => "Missing Parameters"]);
    exit;
}

try {
    // =================================================================
    // الخطوة 1: الاتصال بسيرفر الرحلات ($con_ride)
    // الهدف: جلب driver_id وحالة الرحلة للتحقق
    // =================================================================
    
    $sqlRide = "SELECT driver_id, status FROM ride WHERE id = :rideID LIMIT 1";
    $stmtRide = $con_ride->prepare($sqlRide);
    $stmtRide->bindParam(':rideID', $rideID);
    $stmtRide->execute();
    $rideData = $stmtRide->fetch(PDO::FETCH_ASSOC);

    // إذا لم توجد الرحلة
    if (!$rideData) {
        echo json_encode(["status" => "failure", "message" => "Ride not found"]);
        exit;
    }

    $driverID = $rideData['driver_id'];
    $status   = $rideData['status'];

    // =================================================================
    // الخطوة 2: التحقق الأمني (Hashing Validation)
    // القاعدة: Token = MD5(rideID + driverID + SecretSalt)
    // هذا يضمن أن الرابط تم توليده بواسطة التطبيق ولم يتم تخمينه
    // =================================================================
    
    // * هام: هذه الكلمة السرية يجب أن تكون مطابقة تماماً للموجودة في تطبيق Flutter
    $secretSalt = getenv("secretSaltParent");
    
    // إعادة بناء الهاش للمقارنة
    $generatedToken = md5($rideID . $driverID . $secretSalt);

    if ($token !== $generatedToken) {
        http_response_code(403);
        echo json_encode(["status" => "failure", "message" => "Invalid Security Token"]);
        exit;
    }

    // =================================================================
    // الخطوة 3: التحقق من حالة الرحلة (Logic Check)
    // الشرط: التتبع يعمل فقط إذا كانت الرحلة قد بدأت
    // =================================================================

    // يمكنك إضافة 'Applied' أو 'Arrived' إذا أردت التتبع قبل الركوب
    $allowedStatuses = ['Begin', 'inProgress']; 

    if (!in_array($status, $allowedStatuses)) {
        echo json_encode(["status" => "failure", "message" => "Ride is not active", "ride_status" => $status]);
        exit;
    }

    // =================================================================
    // الخطوة 4: الاتصال بسيرفر التتبع ($con_tracking)
    // الهدف: جلب أحدث إحداثيات للسائق
    // =================================================================

    $sqlLoc = "SELECT latitude, longitude, heading, speed, updated_at 
               FROM car_locations 
               WHERE driver_id = :driverID 
               ORDER BY updated_at DESC LIMIT 1";
               
    $stmtLoc = $con_tracking->prepare($sqlLoc);
    $stmtLoc->bindParam(':driverID', $driverID);
    $stmtLoc->execute();
    $locData = $stmtLoc->fetch(PDO::FETCH_ASSOC);

    if (!$locData) {
        // السائق لم يرسل موقعه بعد
        echo json_encode(["status" => "failure", "message" => "Waiting for driver signal..."]);
        exit;
    }

    // =================================================================
    // الخطوة 5: الاتصال بالسيرفر الرئيسي ($con)
    // الهدف: جلب اسم السائق وموديل السيارة للعرض (اختياري لجمالية الصفحة)
    // =================================================================

    $sqlDriver = "SELECT 
                    d.first_name, 
                    d.last_name,
                    c.model, 
                    c.color, 
                    c.car_plate 
                  FROM driver d
                  LEFT JOIN CarRegistration c ON d.id = c.driverID
                  WHERE d.id = :driverID LIMIT 1";

    $stmtDriver = $con->prepare($sqlDriver);
    $stmtDriver->bindParam(':driverID', $driverID);
    $stmtDriver->execute();
    $driverInfo = $stmtDriver->fetch(PDO::FETCH_ASSOC);

    // فك التشفير إذا لزم الأمر (أسماء السائقين واللوحات غالباً مشفرة)
    if ($driverInfo) {
        // فك تشفير الاسم
        if (!empty($driverInfo['first_name'])) {
            $driverInfo['first_name'] = $encryptionHelper->decryptData($driverInfo['first_name']);
        }
        // فك تشفير اللوحة
        if (!empty($driverInfo['car_plate'])) {
            $driverInfo['car_plate'] = $encryptionHelper->decryptData($driverInfo['car_plate']);
        }
        // يمكنك فك تشفير باقي الحقول حسب الحاجة
    }

    // =================================================================
    // الخطوة 6: تجميع البيانات وإرسال الرد النهائي
    // =================================================================

    $response = [
        "status" => "success",
        "data"   => [
            "lat"         => $locData['latitude'],
            "lng"         => $locData['longitude'],
            "heading"     => $locData['heading'],
            "speed"       => $locData['speed'],
            "last_update" => $locData['updated_at'],
            "driver_name" => $driverInfo['first_name'] ?? "Captain",
            "car_model"   => $driverInfo['model'] ?? "",
            "car_color"   => $driverInfo['color'] ?? "",
            "plate"       => $driverInfo['car_plate'] ?? ""
        ]
    ];

    echo json_encode($response);

} catch (Exception $e) {
    // تسجيل الخطأ دون إظهاره للمستخدم العام
    error_log("Tracking Error: " . $e->getMessage());
    echo json_encode(["status" => "failure", "message" => "Server Error"]);
}
?>

File: ride/rides/update_ride_cancel_wait.php

<?php
// update_ride_cancel_wait.php
// يوضع على السيرفر الرئيسي (Main Server)

require_once __DIR__ . '/../../connect.php';

$rideId = filterRequest("ride_id");
$driverId = filterRequest("driver_id");
$status = "CancelAfterWait";

try {
    $con->beginTransaction();

    // 1. تحديث جدول الرحلات
    $stmtRide = $con->prepare("UPDATE ride SET status = ?, rideTimeStart = NOW() WHERE id = ?");
    $stmtRide->execute([$status, $rideId]);

    // 2. تحديث جدول طلبات السائقين
    // نستخدم Check لضمان عدم تكرار التحديث إذا كان محدثاً مسبقاً
    $stmtOrder = $con->prepare("UPDATE driver_orders SET status = ? WHERE order_id = ? AND driver_id = ?");
    $stmtOrder->execute([$status, $rideId, $driverId]);

    $con->commit();
    jsonSuccess(null, "Ride status updated");

} catch (PDOException $e) {
    $con->rollBack();
    jsonError("DB Error");
}
?>

File: ride/rides/updateRideAndCheckIfApplied.php

<?php
require_once __DIR__ . '/../../connect.php';

$rideId = filterRequest("id");
$rideTimeStart = filterRequest("rideTimeStart");
$driverId = filterRequest("driver_id");

// Step 1: تأكد أن الرحلة غير محجوزة مسبقًا
$sqlCheck = "SELECT `status` FROM `ride` WHERE `id` = :rideId LIMIT 1";
$stmtCheck = $con->prepare($sqlCheck);
$stmtCheck->bindParam(":rideId", $rideId);
$stmtCheck->execute();

$ride = $stmtCheck->fetch(PDO::FETCH_ASSOC);

if (!$ride) {
    jsonError("Ride not found.");
    exit;
}

if ($ride['status'] === 'Apply') {
    jsonError("This ride is already applied by another driver.");
    exit;
}

// Step 2: تحديث حالة الرحلة وربط السائق بها
$sqlUpdate = "UPDATE `ride`
    SET `driver_id` = :driverId,
        `status` = 'Apply',
        `rideTimeStart` = :rideTimeStart
    WHERE `id` = :rideId";

$stmtUpdate = $con->prepare($sqlUpdate);
$stmtUpdate->bindParam(":driverId", $driverId);
$stmtUpdate->bindParam(":rideTimeStart", $rideTimeStart);
$stmtUpdate->bindParam(":rideId", $rideId);

$stmtUpdate->execute();

if ($stmtUpdate->rowCount() > 0) {
    jsonSuccess(null, "Ride data updated successfully");
    // يمكنك هنا إرسال إشعار للسائقين الآخرين إذا أردت
    // FirebaseMessagesController()->sendNotificationToOtherDrivers(...)
} else {
    jsonError("Failed to update ride data.");
}
?>

File: ride/rides/retry_search_drivers.php

<?php
// retry_search_drivers.php
require_once __DIR__ . '/../../connect.php'; 

// 1. استقبال البيانات القادمة من الفلتر (لتوفير الاستعلامات)
$rideId           = filterRequest("ride_id");
$passengerId      = filterRequest("passenger_id");
$passengerName    = filterRequest("passenger_name");
$passengerPhone   = filterRequest("passenger_phone");
$passengerEmail   = filterRequest("passenger_email");
$passengerToken   = filterRequest("passenger_token");
$passengerWallet  = filterRequest("passenger_wallet"); // الرصيد
$isWallet         = filterRequest("is_wallet"); // هل الدفع بالمحفظة؟ (true/false)
$passengerRating  = filterRequest("passenger_rating");

// بيانات الموقع والرحلة (يفضل إرسالها أيضاً لضمان الدقة)
$startLat         = filterRequest("start_lat");
$startLng         = filterRequest("start_lng");
$endLat           = filterRequest("end_lat");
$endLng           = filterRequest("end_lng");
$startName        = filterRequest("start_name");
$endName          = filterRequest("end_name");
$distance         = filterRequest("distance");
$distanceText     = filterRequest("distance_text");
$durationText     = filterRequest("duration_text");
$price            = filterRequest("price");
$priceForDriver   = filterRequest("price_for_driver");
$carType          = filterRequest("car_type");

// بيانات الخطوات (إن وجدت)
$hasSteps = filterRequest("has_steps");
$step0    = filterRequest("step0");
$step1    = filterRequest("step1");
$step2    = filterRequest("step2");
$step3    = filterRequest("step3");
$step4    = filterRequest("step4");

if (!$rideId) {
    jsonError("Missing Ride ID");
    exit;
}

try {
    // 2. تحديث حالة الرحلة في قاعدة البيانات (Reset)
    $updateStmt = $con->prepare("UPDATE ride SET status = 'waiting', driver_id = 0, updated_at = NOW() WHERE id = ?");
    $updateStmt->execute([$rideId]);

    // 3. حساب العمولة (Kazan)
    $kazan = (double)$price - (double)$priceForDriver;

    // 4. بناء Payload مطابق لـ add_ride.php (0 - 33)
    $payloadTemplate = [];
    $payloadTemplate[0]  = (string)$startLat;
    $payloadTemplate[1]  = (string)$startLng;
    $payloadTemplate[2]  = (string)number_format((float)$price, 2, '.', '');
    $payloadTemplate[3]  = (string)$endLat;
    $payloadTemplate[4]  = (string)$endLng;
    $payloadTemplate[5]  = (string)$distanceText;
    $payloadTemplate[6]  = ""; // Driver ID placeholder
    $payloadTemplate[7]  = (string)$passengerId;
    $payloadTemplate[8]  = (string)$passengerName;
    $payloadTemplate[9]  = (string)$passengerToken;
    $payloadTemplate[10] = (string)$passengerPhone;
    $payloadTemplate[11] = (string)$distance;
    $payloadTemplate[12] = "1";
    $payloadTemplate[13] = (string)$isWallet;
    $payloadTemplate[14] = (string)$distance;
    $payloadTemplate[15] = (string)$durationText;
    $payloadTemplate[16] = (string)$rideId;
    $payloadTemplate[17] = "";
    $payloadTemplate[18] = ""; // Driver ID placeholder
    $payloadTemplate[19] = (string)$durationText;
    $payloadTemplate[20] = (string)$hasSteps;
    $payloadTemplate[21] = (string)$step0;
    $payloadTemplate[22] = (string)$step1;
    $payloadTemplate[23] = (string)$step2;
    $payloadTemplate[24] = (string)$step3;
    $payloadTemplate[25] = (string)$step4;
    $payloadTemplate[26] = (string)number_format((float)$priceForDriver, 2, '.', '');
    $payloadTemplate[27] = (string)$passengerWallet;
    $payloadTemplate[28] = (string)$passengerEmail;
    $payloadTemplate[29] = (string)$startName;
    $payloadTemplate[30] = (string)$endName;
    $payloadTemplate[31] = (string)$carType;
    $payloadTemplate[32] = (string)number_format($kazan, 2, '.', '');
    $payloadTemplate[33] = (string)$passengerRating;

    ksort($payloadTemplate);
    $payloadTemplate = array_values($payloadTemplate);

    // 5. البحث عن السائقين وإرسال الطلب (Using Helper Function)
    $latVal = doubleval($startLat);
    $lngVal = doubleval($startLng);
    
    $driversData = findBestDrivers($con, $con_tracking, $latVal, $lngVal, $carType);
    
    if (!empty($driversData)) {
        // استدعاء دالة الإرسال الموحدة (الموجودة في functions.php)
        dispatchRideToDrivers($driversData, $rideId, $payloadTemplate, $startName);
    }

    jsonSuccess(null, "Ride reset and resent to drivers");

} catch (PDOException $e) {
    jsonError("DB Error: " . $e->getMessage());
}
?>

File: ride/rides/acceptRide.php

<?php
// acceptRide.php

// 1. Include Database Connection
// This file connects to both the Main DB ($con) and the Ride DB ($con_ride).
require_once __DIR__ . '/../../connect.php'; 

// 2. Input Validation & Filtering
// We sanitize the inputs to prevent SQL injection or XSS.
$rideId         = filterRequest("id"); 
$driverId       = filterRequest("driver_id");
$status         = filterRequest("status"); // Expected: 'Apply' or 'accepted'
$passengerToken = filterRequest("passengerToken");

// Check if critical data is missing
if (!$rideId || !$driverId) {
    jsonError("Missing required parameters.");
    exit;
}



try {
    // =================================================================================
    // 3. 🔒 ATOMIC UPDATE (The Race Condition Solver)
    // We attempt to update the ride status ONLY if it is currently 'waiting'.
    // This prevents two drivers from accepting the same ride simultaneously.
    // We execute this on the Remote/Ride Database first ($con_ride).
    // =================================================================================
    $stmtRemote = $con_ride->prepare("
        UPDATE `ride` 
        SET `status` = ?, `driver_id` = ?, `rideTimeStart` = NOW() 
        WHERE `id` = ? AND `status` IN ('waiting', 'wait')
    ");
    $stmtRemote->execute([$status, $driverId, $rideId]);
    
    // Check if the update actually changed a row.
    // If rowCount > 0, IT MEANS SUCCESS! This driver won the ride.
    if ($stmtRemote->rowCount() > 0) {
        
        // 4. Synchronization: Update Local Database
        // Now that we secured the ride, we update the main server's DB ($con) to match.
        if (isset($con)) {
             $stmtLocal = $con->prepare("UPDATE `ride` SET `driver_id` = ?, `status` = ?, `rideTimeStart` = NOW() WHERE id = ?");
             $stmtLocal->execute([$driverId, $status, $rideId]);
        }

        // 5. Update/Insert Driver Orders Table
        // This tracks the driver's history or active orders.
        $checkSql = "SELECT `order_id` FROM `driver_orders` WHERE `order_id` = ?";
        $checkStmt = $con->prepare($checkSql);
        $checkStmt->execute([$rideId]);

        if ($checkStmt->rowCount() > 0) {
            // If entry exists, update it
            $updateSql = "UPDATE `driver_orders` SET `driver_id` = ?, `status` = ?, `created_at` = NOW() WHERE `order_id` = ?";
            $con->prepare($updateSql)->execute([$driverId, $status, $rideId]);
        } else {
            // If not, insert new record
            $insertSql = "INSERT INTO `driver_orders` (`driver_id`, `order_id`, `created_at`, `status`) VALUES (?, ?, NOW(), ?)";
            $con->prepare($insertSql)->execute([$driverId, $rideId, $status]);
        }

        // =================================================================
        // 6. 👤 GET DRIVER INFO (For the Passenger)
        // We need to fetch driver details (Car, Name, Rating) to show to the passenger.
        // =================================================================
        
        $driverInfo = [];
        
        $sqlDetails = "SELECT 
            d.id as driver_id,
            d.first_name, 
            d.last_name, 
            d.gender, 
            d.phone, 
            c.make, 
            c.model, 
            c.car_plate, 
            c.year, 
            c.color, 
            c.color_hex,
            (SELECT ROUND(AVG(rating), 2) FROM ratingDriver WHERE driver_id = d.id) AS ratingDriver,
            dt.token
        FROM driver d
        LEFT JOIN CarRegistration c ON c.driverID = d.id
        LEFT JOIN driverToken dt ON dt.captain_id = d.id
        WHERE d.id = ?";

        $stmtDetails = $con->prepare($sqlDetails);
        $stmtDetails->execute([$driverId]);
        $driverRawData = $stmtDetails->fetch(PDO::FETCH_ASSOC);

        if ($driverRawData) {
            // List of encrypted fields that need decryption
            $fieldsToDecrypt = ['first_name', 'last_name', 'gender', 'phone', 'car_plate', 'token'];
            
            foreach ($driverRawData as $key => $value) {
                if (in_array($key, $fieldsToDecrypt) && !empty($value)) {
                    // Decrypt sensitive data
                    $driverInfo[$key] = $encryptionHelper->decryptData($value);
                } else {
                    $driverInfo[$key] = $value;
                }
            }
            
            // Format Full Name
            $driverInfo['driverName'] = trim(($driverInfo['first_name'] ?? '') . ' ' . ($driverInfo['last_name'] ?? ''));
            
            // Default rating if null
            if (empty($driverInfo['ratingDriver'])) {
                $driverInfo['ratingDriver'] = "5.0"; 
            }
        }

        // =================================================================
        // 7. 🔔 NOTIFY PASSENGER (Socket + FCM)
        // Inform the passenger that a driver has been found.
        // =================================================================
        
        // Fetch Passenger ID based on Ride ID
        $stmtPas = $con->prepare("SELECT passenger_id FROM ride WHERE id = ?");
        $stmtPas->execute([$rideId]);
        $passenger_id = $stmtPas->fetchColumn();

        if ($passenger_id) {
            // A. Send Socket Notification (Real-time update on map)
            if (function_exists('notifyPassengerOnRideServer')) {
                notifyPassengerOnRideServer($passenger_id, [
                    'status'      => 'accepted',
                    'ride_id'     => $rideId,
                    'driver_id'   => $driverId,
                    'driver_info' => $driverInfo 
                ]);
            }

            // B. Send FCM Notification (Push Notification)
            if (!empty($passengerToken)) {
                // Using the standardized FCM function
                sendFCM_Internal(
                    $passengerToken, 
                    "Ride Accepted 🚖", // Title
                    "Captain " . ($driverInfo['driverName'] ?? 'Driver') . " is coming to you.", // Body
                    ['ride_id' => (string)$rideId, 'driver_info' => $driverInfo], // Data Payload
                    "Accepted Ride", // Category
                    false // Not a topic
                );
            }
        }

        // =================================================================
        // 8. 🧹 MARKETPLACE CLEANUP (Notify Location Server)
        // Crucial Step: We tell the Location Server that this ride is taken.
        // The Location Server will:
        //    1. Remove the ride from Redis (geo:rides:waiting).
        //    2. Broadcast 'ride_taken' to other drivers to remove it from their screens.
        // =================================================================
        sendToLocationServer('ride_taken_event', [
            'ride_id' => $rideId,
            'taken_by_driver_id' => $driverId
        ]);

        // 9. Final Response to the Driver App
        echo json_encode([
            "status"  => "success", 
            "message" => "Ride Accepted", 
            "data"    => $driverInfo
        ]);
        
    } else {
        // Failure: This means rowCount was 0.
        // Reason: The ride status was NOT 'waiting' (another driver took it milliseconds ago).
        jsonError("Ride not available (Already taken)");
    }

} catch (Exception $e) {
    // Handle unexpected errors
    jsonError("Error: " . $e->getMessage());
}
?>

File: ride/rides/heatmap_live.json

[]

File: ride/rides/getRealTimeHeatmap.php

<?php
// getRealTimeHeatmap.php
require_once __DIR__ . '/../../get_connect.php';
header('Content-Type: application/json; charset=utf-8');

try {
    $precision = 2; // دقة الشبكة (تقريباً 1 كم)

    // الأوزان
    $WEIGHT_WAITING = 5;  // طلب انتظار = 5 نقاط
    $WEIGHT_MISSED  = 8;  // طلب ضائع = 8 نقاط (أهمية قصوى)
    $WEIGHT_ACTIVE  = 1;  // طلب نشط = 1 نقطة

    $grid = [];

    // 1. طلبات الانتظار (Waiting)
    $stmtW = $con->prepare("SELECT start_lat, start_lng FROM waitingRides WHERE status IN ('wait', 'waiting')");
    $stmtW->execute();
    while ($row = $stmtW->fetch(PDO::FETCH_ASSOC)) {
        addToGrid($grid, $row['start_lat'], $row['start_lng'], $precision, $WEIGHT_WAITING);
    }

    // 2. طلبات ضائعة (Timeout)
    $stmtM = $con->prepare("SELECT start_location FROM ride WHERE (status = 'timeout' OR status = 'cancelled_no_driver_found') AND created_at >= DATE_SUB(NOW(), INTERVAL 20 MINUTE)");
    $stmtM->execute();
    while ($row = $stmtM->fetch(PDO::FETCH_ASSOC)) {
        $parts = explode(',', $row['start_location']);
        if (count($parts) == 2) addToGrid($grid, $parts[0], $parts[1], $precision, $WEIGHT_MISSED);
    }

    // 3. طلبات نشطة (Active)
    $stmtA = $con->prepare("SELECT start_location FROM ride WHERE created_at >= DATE_SUB(NOW(), INTERVAL 15 MINUTE) AND status NOT IN ('timeout', 'cancelled_no_driver_found')");
    $stmtA->execute();
    while ($row = $stmtA->fetch(PDO::FETCH_ASSOC)) {
        $parts = explode(',', $row['start_location']);
        if (count($parts) == 2) addToGrid($grid, $parts[0], $parts[1], $precision, $WEIGHT_ACTIVE);
    }

    // تجهيز البيانات النهائية
    $finalData = [];
    foreach ($grid as $cell) {
        $score = $cell['score']; // مجموع النقاط (الوزن)
        $count = $cell['count']; // العدد الحقيقي للطلبات

        // 🧠 المنطق المزدوج: نحدد اللون بناءً على النقاط أو العدد
        $intensity = "low";
        $surge = 1.0;

        // المعادلة: منطقة حمراء إذا كان السكور عالي جداً (مشاكل) أو العدد كبير جداً (زحمة)
        if ($score >= 15 || $count >= 5) { 
            $intensity = "high"; // أحمر (خطر/فرصة ذهبية)
            $surge = 1.5;
        } elseif ($score >= 8 || $count >= 3) {
            $intensity = "medium"; // برتقالي
            $surge = 1.2;
        } elseif ($score >= 3 || $count >= 1) {
            $intensity = "normal"; // أصفر
        }

        if ($score > 0) {
            $finalData[] = [
                'lat'       => $cell['lat'],
                'lng'       => $cell['lng'],
                'count'     => $count,      // ✅ العدد الحقيقي (مهم للعرض)
                'intensity' => $intensity,  // ✅ التصنيف الذكي
                'surge'     => $surge
            ];
        }
    }

    file_put_contents('heatmap_live.json', json_encode($finalData)); // الكاش

    echo json_encode(["status" => "success", "data" => $finalData]);

} catch (Exception $e) {
    echo json_encode(["status" => "failure", "message" => $e->getMessage()]);
}

function addToGrid(&$grid, $lat, $lng, $precision, $weight) {
    if (empty($lat) || empty($lng)) return;
    $rLat = round(floatval($lat), $precision);
    $rLng = round(floatval($lng), $precision);
    $key = "$rLat,$rLng";
    
    if (!isset($grid[$key])) {
        $grid[$key] = ['lat' => $rLat, 'lng' => $rLng, 'count' => 0, 'score' => 0];
    }
    $grid[$key]['count']++;       // زيادة العدد (+1 دائماً)
    $grid[$key]['score'] += $weight; // زيادة الوزن (حسب نوع الطلب)
}
?>

File: ride/rides/getTripCountByCaptain.php

<?php
require_once __DIR__ . '/../../connect.php';

$driver_id = filterRequest("driver_id");

$sql = "
    SELECT COUNT(*) as count 
    FROM `ride` 
    WHERE driver_id = :driver_id AND status = 'Finished'
";

$stmt = $con->prepare($sql);
$stmt->bindParam(':driver_id', $driver_id, PDO::PARAM_INT); // أو PARAM_STR حسب نوع الـ ID

$stmt->execute();

if ($stmt->rowCount() > 0) {
    $row = $stmt->fetch(PDO::FETCH_ASSOC);
    jsonSuccess($row);
} else {
    jsonError($message = "No finished ride records found for this driver");
}
?>

File: ride/rides/arrive_ride.php

<?php
// arrive_ride.php
require_once __DIR__ . '/../../connect.php'; 

$rideId = filterRequest("ride_id");
$driverId = filterRequest("driver_id");
$passengerToken = filterRequest("passengerToken");

if (!$rideId || !$driverId) {
    jsonError("Missing required parameters.");
    exit;
}

try {
    // 1. تحديث الحالة في السيرفر البعيد (Remote DB - con_ride)
    $stmtRemote = $con_ride->prepare("UPDATE ride SET status = 'arrived', updated_at = NOW() WHERE id = ? AND driver_id = ? AND status = 'Apply'");
    $stmtRemote->execute([$rideId, $driverId]);

    // 2. تحديث الحالة في السيرفر المحلي (Local DB - con)
    if (isset($con)) {
        $stmtLocal = $con->prepare("UPDATE ride SET status = 'arrived', updated_at = NOW() WHERE id = ? AND driver_id = ? AND status = 'Apply'");
        $stmtLocal->execute([$rideId, $driverId]);
    }

    // 3. جلب بيانات الراكب للإرسال
    // نستخدم con_ride لضمان الدقة
    $stmtPas = $con_ride->prepare("SELECT passenger_id FROM ride WHERE id = ?");
    $stmtPas->execute([$rideId]);
    $passenger_id = $stmtPas->fetchColumn();

    if ($passenger_id) {
        
        // أ) إرسال Socket (الأسرع)
        $payload = [
            'status'  => 'arrived',
            'ride_id' => $rideId,
            'msg'     => 'السائق وصل إلى موقعك 🚖'
        ];
        
        if (function_exists('notifyPassengerOnRideServer')) {
            notifyPassengerOnRideServer($passenger_id, $payload);
        }

        // ب) إرسال FCM (باستخدام الدالة الجديدة)
        if (!empty($passengerToken)) {
            $fcmData = [
                'category' => 'Arrive Ride', // نفس الاسم القديم لضمان عمل التطبيق
                'ride_id'  => (string)$rideId
            ];
            
            // 🔥 استخدام sendFCM_Internal
            sendFCM_Internal(
                $passengerToken,                      // الهدف
                "السائق وصل 📍",                      // العنوان
                "الكابتن ينتظرك في الموقع المحدد.",   // النص
                $fcmData,                             // البيانات
                "Arrive Ride",                        // التصنيف
                false                                 // ليس Topic
            );
        }
    }

    jsonSuccess(null, "Arrival notified successfully");

} catch (Exception $e) {
    jsonError("Error: " . $e->getMessage());
}
?>

File: ride/rides/add_ride.php

<?php
// add_ride.php

// 1. تضمين ملف الاتصال بقاعدة البيانات
require_once __DIR__ . '/../../connect.php'; 
// include "functions.php"; // (تأكد من وجود دوال المساعدة مثل notifyPassengerSocket هنا أو ضمنها)

// إعدادات تتبع الأخطاء (للسيرفر)
ini_set('log_errors', 1);
ini_set('error_log', '/home/siro-api/add_ride_error.log');

// =================================================================================
// 🛠️ دالة مساعدة: إرسال الرحلة لسوق السائقين (Marketplace Broadcast)
// الوظيفة: ترسل بيانات الرحلة لسيرفر اللوكيشن ليقوم بحفظها في Redis وبثها للسائقين
// =================================================================================
function broadcastRideToMarket($rideId, $lat, $lng, $payloadData) {
    // رابط سيرفر اللوكيشن (تأكد من صحة الرابط والبورت)
    $url = "http://location.intaleq.xyz:2021"; 

    // قراءة مفتاح الأمان الداخلي للمصادقة
    $INTERNAL_KEY = trim(@file_get_contents('/home/siro-api/.internal_socket_key'));

    // تجهيز البيانات بشكل (Key-Value Map) لسهولة التعامل في التطبيق والسوكيت
    // ملاحظة: نستخدم القيم من $payloadData التي هي عبارة عن List حالياً
    $marketPayload = [
        'id'            => (string)$rideId,
        'start_lat'     => $lat,
        'start_lng'     => $lng,
        'price'         => $payloadData[2],  // السعر
        'carType'       => $payloadData[31], // نوع السيارة
        'startName'     => $payloadData[29], // اسم موقع البدء
        'endName'       => $payloadData[30], // اسم موقع الوصول
        'distance'      => $payloadData[11], // المسافة
        'duration'      => $payloadData[15], // الوقت
        'passengerRate' => $payloadData[33], // تقييم الراكب
        // يمكنك إضافة المزيد هنا حسب الحاجة
    ];

    $postData = [
        'action'  => 'market_new_ride', // اسم الحدث في السوكيت
        'payload' => $marketPayload
    ];

    // إرسال الطلب (cURL)
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_POST, 1);
    curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData));
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    // وقت انتظار قصير جداً (200ms) لأننا لا نريد تأخير استجابة الراكب
    curl_setopt($ch, CURLOPT_TIMEOUT_MS, 200); 
    curl_setopt($ch, CURLOPT_HTTPHEADER, ["x-internal-key: $INTERNAL_KEY"]);
    curl_exec($ch);
    curl_close($ch);
}

// =================================================================================
// 2. استقبال وتصفية البيانات من التطبيق
// =================================================================================
$start_location      = filterRequest("start_location");
$end_location        = filterRequest("end_location");
$date_raw            = filterRequest("date");
$time_raw            = filterRequest("time");
$endtime_raw         = filterRequest("endtime");
$price               = filterRequest("price");
$passenger_id        = filterRequest("passenger_id");
$driver_id           = filterRequest("driver_id") ?: 0;
$status              = filterRequest("status");
$price_for_driver    = filterRequest("price_for_driver");
$price_for_passenger = filterRequest("price_for_passenger");
$distance            = filterRequest("distance");
$carType             = filterRequest("carType");

// بيانات الراكب الإضافية
$passenger_name      = filterRequest("passenger_name");
$passenger_phone     = filterRequest("passenger_phone");
$passenger_token     = filterRequest("passenger_token");
$passenger_email     = filterRequest("passenger_email");
$passenger_wallet    = filterRequest("passenger_wallet");
$passenger_rating    = filterRequest("passenger_rating");

// تفاصيل الرحلة والنصوص
$start_name_loc      = filterRequest("start_name");
$end_name_loc        = filterRequest("end_name");
$duration_text       = filterRequest("duration_text");
$distance_text       = filterRequest("distance_text");
$is_wallet           = filterRequest("is_wallet");
$has_steps           = filterRequest("has_steps");

$step0 = filterRequest("step0"); $step1 = filterRequest("step1");
$step2 = filterRequest("step2"); $step3 = filterRequest("step3");
$step4 = filterRequest("step4");

// معالجة الإحداثيات (فصل النص إلى Lat/Lng)
$startLat = ""; $startLng = "";
if (!empty($start_location)) {
    $parts = explode(',', $start_location);
    $startLat = trim($parts[0] ?? ""); $startLng = trim($parts[1] ?? "");
}

$endLat = ""; $endLng = "";
if (!empty($end_location)) {
    $parts = explode(',', $end_location);
    $endLat = trim($parts[0] ?? ""); $endLng = trim($parts[1] ?? "");
}

// تنسيق التواريخ
$date_formatted = date("Y-m-d", strtotime($date_raw));
$time_formatted = date("H:i:s", strtotime($time_raw));
$endtime_formatted = $endtime_raw ? date("H:i:s", strtotime($endtime_raw)) : "00:00:00";

// مصفوفة البيانات للإدخال
$data = [
    ":start_location"      => $start_location,
    ":end_location"        => $end_location,
    ":date"                => $date_formatted,
    ":time"                => $time_formatted,
    ":endtime"             => $endtime_formatted,
    ":price"               => $price,
    ":passenger_id"        => $passenger_id,
    ":driver_id"           => $driver_id,
    ":status"              => $status,
    ":carType"             => $carType,
    ":price_for_driver"    => $price_for_driver,
    ":price_for_passenger" => $price_for_passenger,
    ":distance"            => $distance,
];

// جملة SQL للإدخال
$sql = "INSERT INTO `ride` (
    `start_location`, `end_location`, `date`, `time`, `endtime`, 
    `price`, `passenger_id`, `driver_id`, `status`, `carType`, 
    `price_for_driver`, `price_for_passenger`, `distance`
) VALUES (
    :start_location, :end_location, :date, :time, :endtime, 
    :price, :passenger_id, :driver_id, :status, :carType, 
    :price_for_driver, :price_for_passenger, :distance
)";

try {
    // 3. الإدخال في قاعدة البيانات الرئيسية (Main DB)
    $stmtMain = $con->prepare($sql);
    $stmtMain->execute($data);
    $insertedId = $con->lastInsertId(); // ID الرحلة الجديد

    // 4. الإدخال في قاعدة بيانات الرحلات (Ride DB) للأرشفة والتزامن
    try {
        $stmtRide = $con_ride->prepare($sql);
        $stmtRide->execute($data);
    } catch (Exception $e) {
        error_log("⚠️ RideDB Insert Warning: " . $e->getMessage());
    }

    if ($insertedId) {
        error_log("📝 Ride #$insertedId added successfully.");

        // 5. تجهيز الـ Payload (قائمة البيانات للتطبيق)
        $kazan = (double)$price - (double)$price_for_driver;
        $payloadTemplate = [];
        // تعبئة البيانات بالترتيب الذي يتوقعه التطبيق (Indices 0-33)
        $payloadTemplate[0] = (string)$startLat;
        $payloadTemplate[1] = (string)$startLng;
        $payloadTemplate[2] = (string)number_format($price, 2, '.', '');
        $payloadTemplate[3] = (string)$endLat;
        $payloadTemplate[4] = (string)$endLng;
        $payloadTemplate[5] = (string)$distance_text;
        $payloadTemplate[6] = "";
        $payloadTemplate[7] = (string)$passenger_id;
        $payloadTemplate[8] = (string)$passenger_name;
        $payloadTemplate[9] = (string)$passenger_token;
        $payloadTemplate[10] = (string)$passenger_phone;
        $payloadTemplate[11] = (string)$distance;
        $payloadTemplate[12] = "1";
        $payloadTemplate[13] = (string)$is_wallet;
        $payloadTemplate[14] = (string)$distance;
        $payloadTemplate[15] = (string)$duration_text;
        $payloadTemplate[16] = (string)$insertedId;
        $payloadTemplate[17] = "";
        $payloadTemplate[18] = "";
        $payloadTemplate[19] = (string)$duration_text;
        $payloadTemplate[20] = $has_steps ?: 'false';
        $payloadTemplate[21] = (string)$step0;
        $payloadTemplate[22] = (string)$step1;
        $payloadTemplate[23] = (string)$step2;
        $payloadTemplate[24] = (string)$step3;
        $payloadTemplate[25] = (string)$step4;
        $payloadTemplate[26] = (string)number_format($price_for_driver, 2, '.', '');
        $payloadTemplate[27] = (string)$passenger_wallet;
        $payloadTemplate[28] = (string)$passenger_email;
        $payloadTemplate[29] = (string)$start_name_loc;
        $payloadTemplate[30] = (string)$end_name_loc;
        $payloadTemplate[31] = (string)$carType;
        $payloadTemplate[32] = (string)number_format($kazan, 2, '.', '');
        $payloadTemplate[33] = (string)$passenger_rating;

        ksort($payloadTemplate);
        $payloadTemplate = array_values($payloadTemplate);

        // 6. البحث عن السائقين للتوزيع المباشر (Direct Dispatch)
        $driversData = findBestDrivers($con, $startLat, $startLng, $carType);
        
        // متغير لنعرف هل وجدنا سائقين للتوجيه المباشر أم لا
        $foundDirectDrivers = false;

        if (!empty($driversData)) {
            // أ. إرسال إشعار مباشر للسائقين المختارين
            dispatchRideToDrivers($driversData, $insertedId, $payloadTemplate, $start_name_loc, $encryptionHelper);
            error_log("📨 Dispatched Ride #$insertedId to " . count($driversData) . " drivers.");
            $foundDirectDrivers = true;
        } else {
            error_log("⚠️ No specific drivers found for Direct Dispatch for Ride #$insertedId. Moved to Market only.");
        }

        // ب. 🔥 نشر الرحلة في السوق المفتوح (Marketplace) دائماً 🔥
        // هذا هو طوق النجاة: حتى لو لم نجد سائقين أعلاه، نضعها في السوق
        broadcastRideToMarket($insertedId, $startLat, $startLng, $payloadTemplate);
        
        // ج. ✅ إرجاع نجاح للتطبيق دائماً (ليبقى الراكب في شاشة البحث)
        // يمكنك إرسال معلومة إضافية للتطبيق أن البحث "عام" وليس "مباشر" إذا أردت
        jsonSuccess($insertedId); 
        
        // ملاحظة: قمنا بإزالة كود الإلغاء (UPDATE ride SET status = 'cancelled...')
        // لأننا نريد منح الفرصة للسائقين البعيدين قليلاً أو الذين فتحوا التطبيق للتو

    
      /*
      else {
            // 🛑 حالة عدم العثور على سائقين
            error_log("⚠️ No drivers found for Ride #$insertedId.");

            // أ. إلغاء الرحلة فوراً في قواعد البيانات
            // ملاحظة: غيرنا الحالة إلى رسالة واضحة
            $con->prepare("UPDATE ride SET status = 'cancelled_no_driver_found' WHERE id = ?")->execute([$insertedId]);
            $con_ride->prepare("UPDATE ride SET status = 'cancelled_no_driver_found' WHERE id = ?")->execute([$insertedId]);

            // ب. إشعار الراكب عبر السوكيت (لإظهار Popup)
            if (function_exists('notifyPassengerSocket')) {
                notifyPassengerSocket($passenger_id, 'no_drivers_found', [
                    'ride_id' => $insertedId,
                    'message' => 'No drivers available nearby'
                ]);
            }

            // ج. إرجاع فشل للتطبيق
            jsonError("no_drivers_found");
        */
    } else {
        jsonError("Failed to add ride");
    }

} catch (Exception $e) {
    error_log("AddRide Critical Error: " . $e->getMessage());
    jsonError("Database Error");
}
?>

File: ride/rides/cancelRideFromDriver.php

<?php
// cancelRideFromDriver.php

// تأكد أن هذا الملف يحتوي على دوال الإشعارات (notifyPassengerOnRideServer)
require_once __DIR__ . '/../../connect.php'; 

// 🚀 تسجيل بداية العملية
error_log("🚀 [cancelRide.php] Request Started to Cancel Ride From Driver.");

$id = filterRequest("id"); // Ride ID

if (!$id) {
    error_log("❌ [cancelRide.php] Missing Ride ID.");
    jsonError("Missing ID");
    exit;
}

// الحالة الجديدة (إلغاء نهائي من طرف السائق)
$newStatus = "cancelRideFromDriver"; 

// الحالات المسموح بإلغاء الرحلة فيها فقط
// نسمح بالإلغاء إذا كانت في وضع الانتظار أو القبول المبدئي
$allowedStatuses = "'wait', 'waiting', 'Apply', 'accepted', 'arrive'";

try {
    // ---------------------------------------------------------
    // 1. التحديث على سيرفر التتبع (Remote DB)
    // ---------------------------------------------------------
    // نستخدم شرط الحالة لضمان عدم إلغاء رحلة بدأت بالفعل (Start/Begin)
    $sql = "UPDATE `ride` 
            SET `status` = ?, `updated_at` = CURRENT_TIMESTAMP 
            WHERE `id` = ? 
            AND `status` IN ($allowedStatuses)";
    
    // استخدام Prepared Statements للأمان
    $stmtRemote = $con_ride->prepare($sql);
    $stmtRemote->execute([$newStatus, $id]);

    $count = $stmtRemote->rowCount();
    error_log(" [cancelRide.php] Remote DB Rows Affected: $count");

    // التحقق: هل تم التحديث؟ 
    if ($count > 0) {

        // ---------------------------------------------------------
        // 2. التحديث على السيرفر المحلي (Local DB)
        // ---------------------------------------------------------
        // نبدأ معاملة لضمان تكامل البيانات
        if (isset($con)) {
             $con->beginTransaction();
             try {
                $stmtLocal = $con->prepare($sql);
                $stmtLocal->execute([$newStatus, $id]);
                
                // تحديث جدول driver_orders أيضاً لتوحيد الحالة (اختياري ولكنه مفضل)
                $stmtDriverOrder = $con->prepare("UPDATE driver_orders SET status = ? WHERE order_id = ?");
                $stmtDriverOrder->execute([$newStatus, $id]);

                $con->commit();
             } catch (Exception $eLocal) {
                $con->rollBack();
                error_log("⚠️ Local DB Update Failed: " . $eLocal->getMessage());
             }
        }

        // ---------------------------------------------------------
        // 3. 🔥 إشعار الراكب عبر السوكيت (القطعة المفقودة) 🔥
        // ---------------------------------------------------------
        
        // أ. جلب معرف الراكب لإرسال الإشعار له
        // نستخدم connection الرحلات لضمان وجود البيانات
        $stmtPas = $con_ride->prepare("SELECT passenger_id FROM ride WHERE id = ?");
        $stmtPas->execute([$id]);
        $passenger_id = $stmtPas->fetchColumn();

        if ($passenger_id) {
            $payload = [
                'ride_id' => $id,
                'status'  => 'cancelled', // هذه الحالة يستقبلها الفلاتر ويغلق الواجهة
                'msg'     => 'للأسف، قام السائق بإلغاء الرحلة.'
            ];

            // استدعاء الدالة المعرفة في functions.php/connect.php
            if (function_exists('notifyPassengerOnRideServer')) {
                notifyPassengerOnRideServer($passenger_id, $payload);
                error_log("📡 [cancelRide.php] Notification sent to Passenger ID: $passenger_id");
            } else {
                error_log("⚠️ [cancelRide.php] Function notifyPassengerOnRideServer not found!");
            }
        }

        // ---------------------------------------------------------
        // 4. إنهاء العملية
        // ---------------------------------------------------------
        error_log("✅ [cancelRide.php] Ride cancelled successfully.");
        jsonSuccess(null, "Ride cancelled successfully");

    } else {
        // الفشل يعني أن الرحلة غير موجودة أو حالتها لا تسمح بالإلغاء (مثلاً بدأت بالفعل)
        error_log("⚠️ [cancelRide.php] Failed. ID invalid OR Status not allowed (maybe started?).");
        jsonError("Cannot cancel ride. Status might be started or already completed.");
    }

} catch (PDOException $e) {
    error_log("❌ [cancelRide.php] Database Error: " . $e->getMessage());
    jsonError("Database Error: " . $e->getMessage());
}
?>

File: ride/rides/finish_ride_updates.php

<?php
require_once __DIR__ . '/../../connect.php';

// finish_ride_updates.php

$rideId    = filterRequest("rideId");    
$driver_id = filterRequest("driver_id");
$passengerId=filterRequest("passengerId");
$newStatus = filterRequest("status");   // "Finished"
$price     = filterRequest("price");
$passengerToken = filterRequest("passengerToken");
$driver_token   =filterRequest("driver_token");

if (empty($rideId) || empty($newStatus) || empty($price) || empty($driver_id)) {
    jsonError("Missing parameters");
    exit;
}

try {
    // 1. تحديث الريموت (Remote Server - con_ride)
    $stmtRemote = $con_ride->prepare("UPDATE ride SET status = ?, rideTimeFinish = NOW(), price = ? WHERE id = ? AND status = 'Begin'");
    $stmtRemote->execute([$newStatus, $price, $rideId]);
    
    if ($stmtRemote->rowCount() == 0) {
        // إذا لم يجد الصف (ربما تم إنهاؤها بالفعل)
        // jsonError("Could not finish ride (Remote).");
        // exit; 
        // ملاحظة: الأفضل إكمال العملية محلياً احتياطاً
    }

    // 2. التحديث المحلي (Local DB)
    $con->beginTransaction();

    $con->prepare("UPDATE ride SET status = ?, rideTimeFinish = NOW(), price = ? WHERE id = ? AND status = 'Begin'")
        ->execute([$newStatus, $price, $rideId]);

    // تحديث driver_orders
    $checkStmt = $con->prepare("SELECT order_id FROM driver_orders WHERE order_id = ?");
    $checkStmt->execute([$rideId]);
    
    if ($checkStmt->rowCount() > 0) {
        $con->prepare("UPDATE driver_orders SET driver_id = ?, status = ?, created_at = NOW() WHERE order_id = ?")
            ->execute([$driver_id, $newStatus, $rideId]);
    } else {
        $con->prepare("INSERT INTO driver_orders (driver_id, order_id, created_at, status) VALUES (?, ?, NOW(), ?)")
            ->execute([$driver_id, $rideId, $newStatus]);
    }

    // =================================================================
    // 🔥 الخطوة 3: إشعار الراكب (Socket + FCM)
    // =================================================================
    
    
   

    if ($passenger_id) {
        
        // تجهيز القائمة المتوافقة مع الكود القديم (Legacy List)
        // [driver_id, ride_id, driver_token, price]
        $legacyList = [
            (string)$driver_id,
            (string)$rideId,
            (string)$driver_token,
            (string)$price
        ];

        // أ) إرسال Socket
        $socketPayload = [
            'ride_id'    => $rideId,
            'status'     => 'finished',
            'price'      => $price,
            'DriverList' => $legacyList // إرسال القائمة للسوكيت أيضاً
        ];
        
        if (function_exists('notifyPassengerOnRideServer')) {
            notifyPassengerOnRideServer($passenger_id, $socketPayload);
        }

        // ب) إرسال FCM (Internal)
        if (!empty($passengerToken)) {
            $fcmData = [
                'ride_id'    => (string)$rideId,
                'price'      => (string)$price,
                'DriverList' => $legacyList // ✅ نمرر المصفوفة، والدالة الداخلية تحولها لـ JSON
            ];
            
            sendFCM_Internal(
                $passengerToken,              // الهدف
                "تم إنهاء الرحلة 🏁",         // العنوان
                "المبلغ المطلوب: " . $price . " ل.س", // النص (أضفت العملة افتراضياً)
                $fcmData,                     // البيانات
                'Driver Finish Trip',         // التصنيف (كما هو في التطبيق القديم)
                false                         // ليس Topic
            );
        }
    }

    $con->commit();
    jsonSuccess(null, "Ride finished successfully");

} catch (PDOException $e) {
    if ($con->inTransaction()) $con->rollBack();
    jsonError("DB Error: " . $e->getMessage());
}
?>

File: ride/rides/getRideStatusBegin.php

<?php
//getRideStatusBegin.php
require_once __DIR__ . '/../../connect.php';

$ride_id = filterRequest("ride_id");

if (empty($ride_id)) {
    jsonError("Ride ID is missing.");
    exit;
}

$sql = "SELECT `status`, `DriverIsGoingToPassenger`, `rideTimeStart` FROM `ride` WHERE `id` = :ride_id";
$stmt = $con->prepare($sql);
$stmt->bindParam(':ride_id', $ride_id, PDO::PARAM_INT);
$stmt->execute();

$row = $stmt->fetch(PDO::FETCH_ASSOC);

if ($row) {
    echo json_encode([
        "status" => "success",
        "data" => $row
    ]);
} else {
    jsonError("Ride not found.");
}
?>

File: ride/rides/cron_ride_timeout.php

<?php
// cron_cleanup_waiting.php
// مسار الاتصال بقاعدة البيانات
require_once __DIR__ . '/../../get_connect.php';

// تسجيل في اللوج لبداية العملية
error_log("⏰ [Cleanup Cron] Started cleaning old waiting rides...");

try {
    // المدة المسموحة بالدقائق
    $minutesLimit = 15;

    // =========================================================
    // الخطوة 1: تحديث الحالة في الجدول الرئيسي (الأرشيف)
    // =========================================================
    // نقوم بتحديث حالة الرحلات التي ستُحذف ليعلم الراكب أنها انتهت (Time Out)
    // بدلاً من أن تبقى 'waiting' للأبد في سجلات الراكب
    
    $sqlUpdate = "UPDATE ride 
                  SET status = 'timeout' 
                  WHERE id IN (
                      SELECT id FROM waitingRides 
                      WHERE created_at < DATE_SUB(NOW(), INTERVAL $minutesLimit MINUTE)
                  ) AND status = 'waiting'"; // نتأكد أننا نحدث ما هو معلق فقط

    $stmtUpdate = $con->prepare($sqlUpdate);
    $stmtUpdate->execute();
    $updatedCount = $stmtUpdate->rowCount();

    // =========================================================
    // الخطوة 2: الحذف من جدول الانتظار (تنظيف Hot Data)
    // =========================================================
    
    $sqlDelete = "DELETE FROM waitingRides 
                  WHERE created_at < DATE_SUB(NOW(), INTERVAL $minutesLimit MINUTE)";

    $stmtDelete = $con->prepare($sqlDelete);
    $stmtDelete->execute();
    $deletedCount = $stmtDelete->rowCount();

    // =========================================================
    // الخطوة 3: (اختياري) تنظيف الريدز
    // =========================================================
    // بما أنك تستخدم Redis، المفترض أن تحذفها منه أيضاً.
    // لكن بما أن الريدز يعتمد على TTL (Expire) أو سيتم تحديثه عند الطلب القادم،
    // فالحذف من الـ MySQL يكفي لأن getRideWaiting سيفحص MySQL ولن يجدها.
    
    // تقرير العملية
    if ($deletedCount > 0) {
        $msg = "✅ [Cleanup Cron] Success: Timed out $updatedCount rides in Main DB, and Deleted $deletedCount rides from Waiting DB.";
        error_log($msg);
        echo json_encode(["status" => "success", "message" => $msg]);
    } else {
        $msg = "💤 [Cleanup Cron] No expired rides found.";
        error_log($msg);
        echo json_encode(["status" => "success", "message" => "Nothing to clean."]);
    }

} catch (PDOException $e) {
    $errorMsg = "❌ [Cleanup Cron] Error: " . $e->getMessage();
    error_log($errorMsg);
    echo json_encode(["status" => "failure", "message" => $e->getMessage()]);
}
?>

File: ride/rides/delete.php

<?php
require_once __DIR__ . '/../../connect.php';

// استلام قيمة ID بعد التصفية
$id = filterRequest("id");

// استخدام استعلام محضّر لتفادي SQL Injection
$sql = "DELETE FROM `ride` WHERE `id` = :id";
$stmt = $con->prepare($sql);
$stmt->bindParam(':id', $id, PDO::PARAM_INT);
$stmt->execute();

// التحقق من نجاح العملية
if ($stmt->rowCount() > 0) {
    jsonSuccess(null, "Ride deleted successfully");
} else {
    jsonError("Failed to delete ride");
}
?>

File: ride/rides/public_track_location.php

<?php
// ابدأ التخزين المؤقت فوراً
ob_start();

require_once __DIR__ . '/../../get_connect.php';

// تنظيف *جميع* مستويات التخزين المؤقت (Loop)
// هذا يضمن التخلص من أي مسافات أو أخطاء ظهرت من ملفات الـ include
while (ob_get_level()) {
    ob_end_clean();
}

// ابدأ مخزناً جديداً ونظيفاً لهذا الملف فقط
ob_start();

header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Methods: GET");
header("Content-Type: application/json; charset=UTF-8");

function sendError($message, $code = 400, $extra = []) {
    // تنظيف ما قبل الخطأ
    ob_clean();
    http_response_code($code);
    echo json_encode(array_merge(["status" => "failure", "message" => $message], $extra));
    exit;
}

try {
    $rideID = filter_input(INPUT_GET, 'id', FILTER_SANITIZE_NUMBER_INT);
    $token = filter_input(INPUT_GET, 'token', FILTER_SANITIZE_SPECIAL_CHARS);

    if (!$rideID || !$token) {
        sendError("Missing parameters");
    }

    $stmtRide = $con_ride->prepare("SELECT driver_id, status FROM ride WHERE id = ? LIMIT 1");
    $stmtRide->execute([$rideID]);
    $rideData = $stmtRide->fetch(PDO::FETCH_ASSOC);

    if (!$rideData) sendError("Ride not found");

    $driverID = $rideData['driver_id'];
    $status   = $rideData['status'];
    $secretSalt = "Siro_Secure_Track_2025"; 
    $generatedToken = md5(trim(strval($rideID)) . trim(strval($driverID)) . $secretSalt);

    if ($token !== $generatedToken) sendError("Invalid Token");

    $allowedStatuses = ['Applied', 'Arrived', 'Begin', 'inProgress']; 
    if (!in_array($status, $allowedStatuses)) {
        sendError("Ride not active", 200, ["current_status" => $status]);
    }

    $stmtLoc = $con_tracking->prepare("SELECT latitude, longitude, heading, speed, updated_at FROM car_locations WHERE driver_id = ? ORDER BY updated_at DESC LIMIT 1");
    $stmtLoc->execute([$driverID]);
    $locData = $stmtLoc->fetch(PDO::FETCH_ASSOC);

    if (!$locData) sendError("Waiting for driver signal...", 200);

    $stmtDriver = $con->prepare("SELECT d.first_name, c.model, c.color, c.car_plate FROM driver d LEFT JOIN CarRegistration c ON d.id = c.driverID WHERE d.id = ? LIMIT 1");
    $stmtDriver->execute([$driverID]);
    $driverInfo = $stmtDriver->fetch(PDO::FETCH_ASSOC);

    $driverName = "Captain";
    $carModel   = "Car";
    $carColor   = "";
    $plate      = "";

    if ($driverInfo) {
        if (!empty($driverInfo['first_name'])) $driverName = $encryptionHelper->decryptData($driverInfo['first_name']);
        if (!empty($driverInfo['model'])) $carModel = $driverInfo['model'];
        if (!empty($driverInfo['color'])) $carColor = $driverInfo['color'];
        if (!empty($driverInfo['car_plate'])) $plate = $encryptionHelper->decryptData($driverInfo['car_plate']);
    }

    $response = [
        "status" => "success",
        "data"   => [
            "lat"         => $locData['latitude'],
            "lng"         => $locData['longitude'],
            "heading"     => $locData['heading'],
            "speed"       => $locData['speed'],
            "last_update" => $locData['updated_at'],
            "driver_name" => $driverName,
            "car_model"   => $carModel,
            "car_color"   => $carColor,
            "plate"       => $plate,
            "ride_status" => $status 
        ]
    ];

    // التنظيف النهائي قبل الطباعة
    ob_clean();
    echo json_encode($response);

} catch (Exception $e) {
    error_log("Tracking API Error: " . $e->getMessage());
    sendError("Server Error");
}

File: ride/rides/getRideOrderID.php

<?php
// نقوم بتضمين ملف الاتصال المعدل الذي يحتوي على $con (الرئيسي) و $con_ride (الرحلات)
require_once __DIR__ . '/../../get_connect.php';

// استلام البيانات (يمكن استلام ID الرحلة أو ID الراكب)
$passengerID = filterRequest("passengerID");
$rideID      = filterRequest("id"); // إضافة استقبال متغير رقم الرحلة

try {
    // =================================================================
    // 1. الخطوة الأولى: تحديد استراتيجية البحث (بواسطة رقم الرحلة أو الراكب)
    // =================================================================

    $sqlRide = "SELECT 
        id, 
        start_location, 
        end_location, 
        date, 
        driver_id, 
        passenger_id,
        price, 
        status, 
        created_at, 
        DriverIsGoingToPassenger, 
        rideTimeStart, 
        rideTimeFinish, 
        price_for_driver, 
        distance
    FROM ride ";

    // المنطق الجديد:
    // إذا تم إرسال rideID، نبحث عن الرحلة المحددة بدقة (تجنباً لأي تضارب)
    // إذا لم يتم إرساله، نبحث عن أحدث رحلة للراكب (للتتبع المباشر)
    if (!empty($rideID)) {
        $sqlRide .= "WHERE id = :rideID";
    } else {
        $sqlRide .= "WHERE passenger_id = :passengerID ORDER BY id DESC LIMIT 1";
    }

    // نستخدم المتغير $con_ride (سيرفر الرحلات)
    $stmtRide = $con_ride->prepare($sqlRide);

    // ربط المتغيرات حسب نوع البحث
    if (!empty($rideID)) {
        $stmtRide->bindParam(':rideID', $rideID);
    } else {
        $stmtRide->bindParam(':passengerID', $passengerID);
    }

    $stmtRide->execute();

    $rideData = $stmtRide->fetch(PDO::FETCH_ASSOC);

    // إذا لم يتم العثور على رحلة في سيرفر الرحلات، نوقف العملية
    if (!$rideData) {
        echo json_encode(["status" => "failure", "message" => "No ride found"]);
        exit;
    }

    // =================================================================
    // 2. الخطوة الثانية: جلب البيانات الثابتة (سائق، سيارة، تقييم) من السيرفر الرئيسي ($con)
    // نستخدم المعرفات التي حصلنا عليها من نتيجة الاستعلام الأول
    // =================================================================

    $driverID = $rideData['driver_id'];
    $pID = $rideData['passenger_id']; // نأخذ معرف الراكب من الرحلة نفسها لضمان التطابق

    // ملاحظة: استخدام :driverID_Sub في الاستعلام الفرعي لتجنب أخطاء PDO
    $sqlDetails = "SELECT 
        passengers.first_name AS passengerName, 
        passengers.last_name,

        CarRegistration.make, 
        CarRegistration.model, 
        CarRegistration.car_plate, 
        CarRegistration.year, 
        CarRegistration.color, 
        CarRegistration.color_hex,

        driver.first_name AS driverName, 
        driver.gender, 
        driver.phone,

        (
            SELECT ROUND(AVG(ratingDriver.rating), 2) 
            FROM ratingDriver 
            WHERE ratingDriver.driver_id = :driverID_Sub
        ) AS ratingDriver,

        driverToken.token AS token

    FROM driver 
    LEFT JOIN passengers ON passengers.id = :passengerID
    LEFT JOIN CarRegistration ON CarRegistration.driverID = driver.id
    LEFT JOIN driverToken ON driverToken.captain_id = driver.id
    WHERE driver.id = :driverID";

    // نستخدم المتغير الأصلي $con للسيرفر الرئيسي
    $stmtDetails = $con->prepare($sqlDetails);
    
    // نربط المتغيرات
    $stmtDetails->bindParam(':driverID', $driverID);
    $stmtDetails->bindParam(':driverID_Sub', $driverID);
    $stmtDetails->bindParam(':passengerID', $pID);
    
    $stmtDetails->execute();

    $detailsData = $stmtDetails->fetch(PDO::FETCH_ASSOC);

    // =================================================================
    // 3. الخطوة الثالثة: دمج البيانات وتجهيز الرد
    // =================================================================

    $finalData = [];

    if ($detailsData) {
        // دمج مصفوفة الرحلة (من سيرفر الرحلات) مع مصفوفة التفاصيل (من الرئيسي)
        $finalData = array_merge($rideData, $detailsData);
    } else {
        // في حال كانت الرحلة بدون سائق بعد، نكتفي ببيانات الرحلة
        $finalData = $rideData;
    }

    // =================================================================
    // 4. فك التشفير (Decrypt)
    // =================================================================

    if ($finalData) {
        $fieldsToDecrypt = ['driverName', 'gender', 'phone', 'car_plate', 'passengerName', 'last_name', 'token'];
        
        foreach ($fieldsToDecrypt as $field) {
            if (!empty($finalData[$field])) {
                $finalData[$field] = $encryptionHelper->decryptData($finalData[$field]);
            }
        }
    }

    echo json_encode([
        "status" => "success",
        "data" => $finalData
    ]);

} catch (Exception $e) {
    error_log("API Error: " . $e->getMessage());
    http_response_code(500);
    echo json_encode(["status" => "failure", "message" => "Server Error: " . $e->getMessage()]);
}
?>

File: ride/rides/test_notification.php

<?php
// test_socket_dispatch.php

$socketUrl = "http://188.68.36.205:2021";
$INTERNAL_KEY = trim(file_get_contents('/home/siro-api/.internal_socket_key'));

// جرّب Driver ID موجود عندك
$driverId = 691;
$rideId   = 99999;

// payload تجريبي (بنفس شكل اللي عم تبعته بالـ add_ride)
$payload = ["32.11153","36.0668","173.00","32.12207","36.06351","1.8064","","849a9faf3e68c1aeb708",
"حمزه عايد","TOKEN","963992952235","1.8064","1","false","1.8064","3","692","","","3","false",
"32.11153499923237,36.06680665165186","","","","","173.00","28.00","963992952235@intaleqapp.com",
"وادي أكيدر","وادي أكيدر","Fixed Price","0.00","5.0"];

$postData = [
    'action'      => 'dispatch_order',
    'drivers_ids' => json_encode([$driverId]),
    'ride_id'     => $rideId,
    'payload'     => $payload
];

$ch = curl_init($socketUrl);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData));
curl_setopt($ch, CURLOPT_HTTPHEADER, ["x-internal-key: $INTERNAL_KEY"]);
curl_setopt($ch, CURLOPT_TIMEOUT, 3);

$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);

if (curl_errno($ch)) {
    die("Curl error: " . curl_error($ch));
}
curl_close($ch);

echo "HTTP Code: $httpCode\n";
echo "Response: $response\n";

File: ride/rides/getRideStatus.php

<?php
require_once __DIR__ . '/../../connect.php';

$id = filterRequest("id");

if (empty($id)) {
    jsonError("Missing ride ID.");
    exit;
}

$sql = "SELECT `status` FROM `ride` WHERE `id` = :id";
$stmt = $con->prepare($sql);
$stmt->bindParam(':id', $id, PDO::PARAM_INT);
$stmt->execute();

$row = $stmt->fetch(PDO::FETCH_ASSOC);

if ($row && isset($row['status'])) {
    echo json_encode([
        "status" => "success",
        "data" => $row['status']
    ]);
} else {
    jsonError("Ride not found.");
}
?>

File: ride/rides/cancel_ride_by_driver.php

<?php
// cancel_ride_by_driver.php
require_once __DIR__ . '/../../connect.php';

$rideId         = filterRequest("ride_id");
$driverId       = filterRequest("driver_id");
$reason         = filterRequest("reason");
$passengerToken = filterRequest("passenger_token"); 

// تثبيت الحالة
$statusText     = "CancelFromDriverAfterApply"; 

if (!$rideId || !$driverId) {
    jsonError("Missing parameters");
    exit;
}

try {
    $con->beginTransaction();

    // ---------------------------------------------------------
    // 1. معالجة driver_orders (Insert or Update)
    // ---------------------------------------------------------
    $checkStmt = $con->prepare("SELECT order_id FROM driver_orders WHERE order_id = ? AND driver_id = ?");
    $checkStmt->execute([$rideId, $driverId]);
    
    if ($checkStmt->rowCount() > 0) {
        // موجود: تحديث
        $stmtLog = $con->prepare("UPDATE driver_orders SET status = ?, notes = ?, created_at = NOW() WHERE order_id = ? AND driver_id = ?");
        $stmtLog->execute([$statusText, $reason, $rideId, $driverId]);
    } else {
        // غير موجود: إدخال
        $stmtLog = $con->prepare("INSERT INTO driver_orders (driver_id, order_id, status, created_at, notes) VALUES (?, ?, ?, NOW(), ?)");
        $stmtLog->execute([$driverId, $rideId, $statusText, $reason]);
    }

    // ---------------------------------------------------------
    // 2. منطق الحظر (Business Logic)
    // ---------------------------------------------------------
    $stmtCount = $con->prepare("
        SELECT COUNT(*) FROM driver_orders 
        WHERE driver_id = ? 
        AND status = ? 
        AND created_at >= NOW() - INTERVAL 1 DAY
    ");
    $stmtCount->execute([$driverId, $statusText]);
    $cancelCount = $stmtCount->fetchColumn();

    $isBlocked = false;
    $blockUntil = "";

    if ($cancelCount >= 3) {
        $isBlocked = true;
        $blockUntil = date('Y-m-d H:i:s', strtotime('+4 hours'));
        // يمكنك هنا تحديث حالة السائق في جدول driver إذا لزم الأمر
    }

    // ---------------------------------------------------------
    // 3. تحديث حالة الرحلة في جدول ride
    // ---------------------------------------------------------
    $sqlRide = "UPDATE ride SET status = ?, driver_id = 0 WHERE id = ?";
    
    // Local DB
    $con->prepare($sqlRide)->execute([$statusText, $rideId]);
    
    // Remote DB (إن وجد)
    if (isset($con_ride)) {
        $con_ride->prepare($sqlRide)->execute([$statusText, $rideId]);
    }

    // ---------------------------------------------------------
    // 4. إشعار الراكب
    // ---------------------------------------------------------
    
    // أ) Socket (يحتاج Passenger ID)
    $stmtPas = $con->prepare("SELECT passenger_id FROM ride WHERE id = ?");
    $stmtPas->execute([$rideId]);
    $passenger_id = $stmtPas->fetchColumn();

    if ($passenger_id) {
        $socketPayload = [
            'ride_id' => $rideId, 
            'status'  => 'cancelled_by_driver', 
            'msg'     => 'تم إلغاء الرحلة من قبل السائق'
        ];
        if (function_exists('notifyPassengerOnRideServer')) {
            notifyPassengerOnRideServer($passenger_id, $socketPayload);
        }
    }

    // ب) FCM (Internal)
    if (!empty($passengerToken)) {
        $fcmData = [
            'ride_id'  => (string)$rideId
        ];
        
        // 🔥 استخدام الدالة الجديدة
        sendFCM_Internal(
            $passengerToken,                  // الهدف
            "تم إلغاء الرحلة ❌",             // العنوان
            "عذراً، قام السائق بإلغاء الرحلة.", // النص
            $fcmData,                         // البيانات
            "Cancel Trip from driver",        // التصنيف (تأكد أنه يطابق ما في تطبيق الراكب)
            false                             // ليس Topic
        );
    }

    $con->commit();

    // 5. الرد للفلاتر
    echo json_encode([
        "status"       => "success",
        "cancel_count" => $cancelCount,
        "is_blocked"   => $isBlocked,
        "block_until"  => $blockUntil
    ]);

} catch (PDOException $e) {
    if ($con->inTransaction()) $con->rollBack();
    jsonError("DB Error: " . $e->getMessage());
}
?>

File: ride/rides/emailToPassengerTripDetail.php

<?php

use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception;

// الاتصال بقاعدة البيانات والدوال المشتركة
require_once __DIR__ . '/../../connect.php';

// تضمين autoload من Composer (مجلد vendor في الجذر)
require_once __DIR__ . '/../../../vendor/autoload.php';

// استقبال البيانات من الطلب
$passengerName = filterRequest("name");
$passengerEmail = filterRequest("email");
$passengerPhone = filterRequest("phone");
$fee = floatval(filterRequest("fee"));
$startLocation = filterRequest("startLocation");
$endLocation = filterRequest("endLocation");
$startNameLocation = filterRequest("startNameLocation");
$endNameLocation = filterRequest("endNameLocation");
$timeOfTrip = filterRequest("timeOfTrip");
$duration = intval(filterRequest("duration"));
$duration = floor($duration / 60); // تحويل للـ minutes

// حساب الخصم
$discount = 0;
if ($startNameLocation && $endNameLocation) {
    $discount = $fee * 0.12;
    $beforDiscount = $fee;
    $fee -= $discount;
}

// بناء الإيميل
$bodyEmail = "
<html>
<head>
<style>
body { font-family: 'Arial', sans-serif; background-color: #f8f9fa; color: #333; line-height: 1.6; }
table { border-collapse: collapse; width: 100%; background-color: white; margin: 20px 0; box-shadow: 0 4px 6px rgba(0,0,0,0.1); }
th, td { padding: 12px; text-align: left; border-bottom: 1px solid #ddd; }
th { background-color: #007bff; color: white; }
tr:nth-child(even) { background-color: #f2f2f2; }
</style>
</head>
<body>
<img src='https://api.tripz-egypt.com/tripz/images/logo%20(1).png' alt='Tripz Logo' style='width: 150px; margin: 20px auto; display: block;'>
<p>Hi $passengerName,</p>
<p>Thank you for booking your ride with <strong>Tripz</strong>. Here are the details of your recent trip:</p>
<table>
  <tr><th>Detail</th><th>Value</th></tr>
  <tr><td>Passenger</td><td>$passengerName</td></tr>
  <tr><td>Email</td><td>$passengerEmail</td></tr>
  <tr><td>Phone</td><td>$passengerPhone</td></tr>
  <tr><td>Fee</td><td>$$fee</td></tr>
  <tr><td>Start Location</td><td>$startLocation ($startNameLocation)</td></tr>
  <tr><td>End Location</td><td>$endLocation ($endNameLocation)</td></tr>
  <tr><td>Time of Trip</td><td>$timeOfTrip</td></tr>
  <tr><td>Duration</td><td>$duration minutes</td></tr>
</table>";

if ($discount > 0) {
    $bodyEmail .= "<p>You have received a 12% discount on your trip from $startNameLocation to $endNameLocation. The original fee was $$beforDiscount. Your discounted fee is $$fee.</p>";
}

$bodyEmail .= "<p>Thank you for using <strong>Tripz</strong>. We hope you have a great day!</p><p>Best regards,<br>Tripz Team</p></body></html>";

// إعداد البريد
$mail = new PHPMailer(true);

try {
    $mail->isSMTP();
    $mail->Host = 'smtp.hostinger.com';
    $mail->SMTPAuth = true;
    $mail->Username = 'hamzaayed@tripz-egypt.com';
    $mail->Password = $TRIPZ_SMTP_PASSWORD;
    $mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS;
    $mail->Port = 587;

    $mail->setFrom('hamzaayed@tripz-egypt.com', 'Tripz');
    $mail->addAddress($passengerEmail, $passengerName);
    $mail->isHTML(true);
    $mail->Subject = 'Your Tripz Trip Details';
    $mail->Body    = $bodyEmail;

    $mail->send();
    echo json_encode(["status" => "success", "message" => "Email sent successfully"]);
} catch (Exception $e) {
    echo json_encode(["status" => "error", "message" => $mail->ErrorInfo]);
}

File: ride/rides/getRideOrderIDNew.php

<?php
// نقوم بتضمين ملف الاتصال المعدل الذي يحتوي على $con (الرئيسي) و $con_ride (الرحلات)
require_once __DIR__ . '/../../get_connect.php';

// استلام البيانات (يمكن استلام ID الرحلة أو ID الراكب)
$passengerID = filterRequest("passengerID");
$rideID      = filterRequest("id"); // إضافة استقبال متغير رقم الرحلة

try {
    // =================================================================
    // 1. الخطوة الأولى: تحديد استراتيجية البحث (بواسطة رقم الرحلة أو الراكب)
    // =================================================================

    $sqlRide = "SELECT 
        id, 
        start_location, 
        end_location, 
        date, 
        driver_id, 
        passenger_id,
        price, 
        status, 
        created_at, 
        DriverIsGoingToPassenger, 
        rideTimeStart, 
        rideTimeFinish, 
        price_for_driver, 
        distance
    FROM ride ";

    // المنطق الجديد:
    // إذا تم إرسال rideID، نبحث عن الرحلة المحددة بدقة (تجنباً لأي تضارب)
    // إذا لم يتم إرساله، نبحث عن أحدث رحلة للراكب (للتتبع المباشر)
    if (!empty($rideID)) {
        $sqlRide .= "WHERE id = :rideID";
    } else {
        $sqlRide .= "WHERE passenger_id = :passengerID ORDER BY id DESC LIMIT 1";
    }

    // نستخدم المتغير $con_ride (سيرفر الرحلات)
    $stmtRide = $con_ride->prepare($sqlRide);

    // ربط المتغيرات حسب نوع البحث
    if (!empty($rideID)) {
        $stmtRide->bindParam(':rideID', $rideID);
    } else {
        $stmtRide->bindParam(':passengerID', $passengerID);
    }

    $stmtRide->execute();

    $rideData = $stmtRide->fetch(PDO::FETCH_ASSOC);

    // إذا لم يتم العثور على رحلة في سيرفر الرحلات، نوقف العملية
    if (!$rideData) {
        echo json_encode(["status" => "failure", "message" => "No ride found"]);
        exit;
    }

    // =================================================================
    // 2. الخطوة الثانية: جلب البيانات الثابتة (سائق، سيارة، تقييم) من السيرفر الرئيسي ($con)
    // نستخدم المعرفات التي حصلنا عليها من نتيجة الاستعلام الأول
    // =================================================================

    $driverID = $rideData['driver_id'];
    $pID = $rideData['passenger_id']; // نأخذ معرف الراكب من الرحلة نفسها لضمان التطابق

    // ملاحظة: استخدام :driverID_Sub في الاستعلام الفرعي لتجنب أخطاء PDO
    $sqlDetails = "SELECT 
        passengers.first_name AS passengerName, 
        passengers.last_name,

        CarRegistration.make, 
        CarRegistration.model, 
        CarRegistration.car_plate, 
        CarRegistration.year, 
        CarRegistration.color, 
        CarRegistration.color_hex,

        driver.first_name AS driverName, 
        driver.gender, 
        driver.phone,

        (
            SELECT ROUND(AVG(ratingDriver.rating), 2) 
            FROM ratingDriver 
            WHERE ratingDriver.driver_id = :driverID_Sub
        ) AS ratingDriver,

        driverToken.token AS token

    FROM driver 
    LEFT JOIN passengers ON passengers.id = :passengerID
    LEFT JOIN CarRegistration ON CarRegistration.driverID = driver.id
    LEFT JOIN driverToken ON driverToken.captain_id = driver.id
    WHERE driver.id = :driverID";

    // نستخدم المتغير الأصلي $con للسيرفر الرئيسي
    $stmtDetails = $con->prepare($sqlDetails);
    
    // نربط المتغيرات
    $stmtDetails->bindParam(':driverID', $driverID);
    $stmtDetails->bindParam(':driverID_Sub', $driverID);
    $stmtDetails->bindParam(':passengerID', $pID);
    
    $stmtDetails->execute();

    $detailsData = $stmtDetails->fetch(PDO::FETCH_ASSOC);

    // =================================================================
    // 3. الخطوة الثالثة: دمج البيانات وتجهيز الرد
    // =================================================================

    $finalData = [];

    if ($detailsData) {
        // دمج مصفوفة الرحلة (من سيرفر الرحلات) مع مصفوفة التفاصيل (من الرئيسي)
        $finalData = array_merge($rideData, $detailsData);
    } else {
        // في حال كانت الرحلة بدون سائق بعد، نكتفي ببيانات الرحلة
        $finalData = $rideData;
    }

    // =================================================================
    // 4. فك التشفير (Decrypt)
    // =================================================================

    if ($finalData) {
        $fieldsToDecrypt = ['driverName', 'gender', 'phone', 'car_plate', 'passengerName', 'last_name', 'token'];
        
        foreach ($fieldsToDecrypt as $field) {
            if (!empty($finalData[$field])) {
                $finalData[$field] = $encryptionHelper->decryptData($finalData[$field]);
            }
        }
    }

    echo json_encode([
        "status" => "success",
        "data" => $finalData
    ]);

} catch (Exception $e) {
    error_log("API Error: " . $e->getMessage());
    http_response_code(500);
    echo json_encode(["status" => "failure", "message" => "Server Error: " . $e->getMessage()]);
}
?>

File: ride/license/add.php

<?php
require_once __DIR__ . '/../../connect.php';

$driverID = filterRequest("driverID");
$name = filterRequest("name");
$licenseClass = filterRequest("licenseClass");
$documentNo = filterRequest("documentNo");
$address = filterRequest("address");
$height = filterRequest("height");
$postalCode = filterRequest("postalCode");
$sex = filterRequest("sex");
$stateCode = filterRequest("stateCode");
$expireDate = filterRequest("expireDate");
$dateOfBirth = filterRequest("dateOfBirth");

$sql = "INSERT INTO `lisenceDetails`(`id`,`driverID`, `name`, `licenseClass`, `documentNo`, `address`, `height`, `postalCode`, `sex`, `stateCode`, `expireDate`, `dateOfBirth`) VALUES (
  UUID(),
  :driverID
  :name,
  :licenseClass,
  :documentNo,
  :address,
  :height,
  :postalCode,
  :sex,
  :stateCode,
  :expireDate,
  :dateOfBirth
)";

$stmt = $con->prepare($sql);
$stmt->bindParam(':driverID', $driverID);
$stmt->bindParam(':name', $name);
$stmt->bindParam(':licenseClass', $licenseClass);
$stmt->bindParam(':documentNo', $documentNo);
$stmt->bindParam(':address', $address);
$stmt->bindParam(':height', $height);
$stmt->bindParam(':postalCode', $postalCode);
$stmt->bindParam(':sex', $sex);
$stmt->bindParam(':stateCode', $stateCode);
$stmt->bindParam(':expireDate', $expireDate);
$stmt->bindParam(':dateOfBirth', $dateOfBirth);
$stmt->execute();

if ($stmt->rowCount() > 0) {
  // Print a success message
  jsonSuccess($message = "Data saved successfully");
} else {
  // Print a failure message
  jsonError($message = "Failed to save data");
}
?>

File: ride/license/update.php


File: ride/license/get.php

<?php
require_once __DIR__ . '/../../connect.php';


// $promo_code = filterRequest("promo_code"); 
$driverID = filterRequest("driverID");

$sql = "SELECT * FROM `lisenceDetails`WHERE`driverID`='$driverID'";

$stmt = $con->prepare($sql);
$stmt->execute();
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);

if ($result) {
    // Print all promo records
    jsonSuccess($result);
} else {
    // Print a failure message
    jsonError($message = "Failed to retrieve promo records");
   
}
?>

File: ride/license/delete.php


File: ride/notificationPassenger/add.php

<?php

require_once __DIR__ . '/../../connect.php';

$title = filterRequest("title");
$body = filterRequest("body");
$passengerID = filterRequest("passenger_id");

// SQL الآمن باستخدام placeholders
$sql = "INSERT INTO `notifications` (
  `title`,
  `body`,
  `passenger_id`
) VALUES (
  :title,
  :body,
  :passengerID
)";

$stmt = $con->prepare($sql);
$stmt->execute([
    ':title' => $title,
    ':body' => $body,
    ':passengerID' => $passengerID
]);

if ($stmt->rowCount() > 0) {
    jsonSuccess(null, "Notification data saved successfully");
} else {
    jsonError("Failed to save notification data");
}

?>

File: ride/notificationPassenger/update.php

<?php
require_once __DIR__ . '/../../connect.php';

$id = filterRequest("id");

$fields = [];
$params = [':id' => $id];

$mapping = [
    "title"        => "title",
    "body"         => "body",
    "passengerID"  => "passenger_id",
    "isShown"      => "isShown",
    "updatedAt"    => "updated_at"
];

// تجهيز الـ SET والأرقام المقابلة
foreach ($mapping as $requestKey => $dbColumn) {
    if (isset($_POST[$requestKey])) {
        $value = filterRequest($requestKey);
        $fields[] = "`$dbColumn` = :$requestKey";
        $params[":$requestKey"] = $value;
    }
}

if (empty($fields)) {
    jsonError("No fields to update");
    exit;
}

$setClause = implode(", ", $fields);
$sql = "UPDATE `notifications` SET $setClause WHERE `id` = :id";

$stmt = $con->prepare($sql);
$stmt->execute($params);

if ($stmt->rowCount() > 0) {
    jsonSuccess(null, "Notification data updated successfully");
} else {
    jsonError("Failed to update notification data");
}
?>

File: ride/notificationPassenger/get.php

<?php

require_once __DIR__ . '/../../connect.php';
$passenger_id = filterRequest("passenger_id");

$sql = "SELECT
    `id`,
    `title`,
    `body`,
    `passenger_id`,
    `isShown`,
    `created_at`,
    `updated_at`
FROM
    `notifications`
WHERE
    `passenger_id` = :passenger_id
    AND `created_at` >= CURDATE() - INTERVAL 7 DAY
ORDER BY `created_at` DESC
LIMIT 10";

$stmt = $con->prepare($sql);
$stmt->bindParam(':passenger_id', $passenger_id, PDO::PARAM_STR);
$stmt->execute();
$notifications = $stmt->fetchAll(PDO::FETCH_ASSOC);

if ($notifications) {
    jsonSuccess($notifications);
} else {
    jsonError("No notification data found");
}

?>

File: ride/notificationPassenger/delete.php


File: ride/card-image-driver/add.php



// require_once __DIR__ . '/../../connect.php';

// $driverID = filterRequest("driver_id");
// $imageName = filterRequest("image_name");
// $link = filterRequest("link");

// // Check if the driverID exists in the table
// $checkSQL = "SELECT * FROM `card_images` WHERE `driver_id` = '$driverID'";
// $checkStmt = $con->prepare($checkSQL);
// $checkStmt->execute();

// if ($checkStmt->rowCount() > 0) {
//     // Driver ID found, update the upload_date
//     $uploadDate = date("Y-m-d H:i:s");
    
//     $updateSQL = "UPDATE `card_images` SET `upload_date` = '$uploadDate' WHERE `driver_id` = '$driverID'";
//     $updateStmt = $con->prepare($updateSQL);
//     $updateStmt->execute();
    
//     if ($updateStmt->rowCount() > 0) {
//         // Print a success message for update
//         jsonSuccess($message = "Record updated successfully");
//     } else {
//         // Print a failure message for update
//         jsonError($message = "Failed to update record");
//     }
// } else {
//     // Driver ID not found, insert a new record
//     $sql = "INSERT INTO `card_images` (`id`, `driver_id`, `image_name`, `link`) 
//             VALUES (SHA2(UUID(), 256), '$driverID', '$imageName', '$link')";
    
//     $stmt = $con->prepare($sql);
//     $stmt->execute();
    
//     if ($stmt->rowCount() > 0) {
//         // Print a success message for insert
//         jsonSuccess($message = "Record inserted successfully");
//     } else {
//         // Print a failure message for insert
//         jsonError($message = "Failed to insert record");
//     }
// }





<?php

require_once __DIR__ . '/connect.php';

// Get the image file from the request.
$image_file = $_FILES['image'];
$driverID = filterRequest("driver_id");

// Check if the image file was uploaded successfully.
if ($image_file['error'] != UPLOAD_ERR_OK) {
  echo json_encode(array('status' => 'The image file was not uploaded successfully.'));
  exit;
}

// Get the file name of the image file.
$image_name = $image_file['name'];

// Get the file extension of the image file.
$image_extension = pathinfo($image_name, PATHINFO_EXTENSION);

// Check if the image file is a valid image file.
if (!in_array($image_extension, array('jpg', 'jpeg', 'png'))) {
  echo json_encode(array('status' => 'The image file is not a valid image file.'));
  exit;
}

// Generate a new filename using the driver ID.
$new_filename = $driverID . '.' . $image_extension;

// Move the image file to the uploads directory with the new filename.
$target_dir = "card_image/";
$target_file = $target_dir . $new_filename;
move_uploaded_file($image_file['tmp_name'], $target_file);

// Update the image name variable with the new filename.
$image_name = $new_filename;

// Check if the driverID already exists in the database.
$sql = "SELECT * FROM card_images WHERE driver_id = '$driverID'";
$result = mysqli_query($conn, $sql);

if (mysqli_num_rows($result) > 0) {
  // The driverID already exists in the database, so update the upload_date
  $uploadDate = date("Y-m-d H:i:s");
  $linlImage='https://ride.mobile-app.store/card_image/'.$image_name;
  $updateSQL = "UPDATE card_images SET upload_date = '$uploadDate' WHERE driver_id = '$driverID'";
  mysqli_query($conn, $updateSQL);
  
  if (mysqli_affected_rows($conn) > 0) {
    // Print a success message for update
    echo json_encode(array('status' => 'Record updated successfully'));
  } else {
    // Print a failure message for update
    echo json_encode(array('status' => 'Failed to update record'));
  }
} else {
  // The driverID does not exist in the database, so insert a new row.
  $insertSQL = "INSERT INTO card_images (id, driver_id, image_name, `link`) 
                VALUES (SHA2(UUID(), 256), '$driverID', '$image_name',)";
  mysqli_query($conn, $insertSQL);
  
  if (mysqli_affected_rows($conn) > 0) {
    // Print a success message for insert
    echo json_encode(array('status' => 'Record inserted successfully'));
  } else {
    // Print a failure message for insert
    echo json_encode(array('status' => 'Failed to insert record'));
  }
}

?>

File: ride/card-image-driver/update.php


File: ride/card-image-driver/get.php


File: ride/card-image-driver/delete.php


File: ride/mishwari/add.php

<?php
require_once __DIR__ . '/../../connect.php';

// استقبال البيانات
$driverId = filterRequest("id");
$phone = filterRequest("phone");
$gender = filterRequest("gender");
$name = filterRequest("name");
$name_english = filterRequest("name_english");
$address = filterRequest("address");
$religion = filterRequest("religion");
$age = filterRequest("age");
$startNameAddress = filterRequest("startNameAddress");
$locationCoordinate = filterRequest("locationCoordinate");
$education = filterRequest("education");
$license_type = filterRequest("license_type");
$national_number = filterRequest("national_number");
$car_plate = filterRequest("car_plate");
$make = filterRequest("make");
$model = filterRequest("model");
$year = filterRequest("year");
$color = filterRequest("color");
$color_hex = filterRequest("color_hex");
$token = filterRequest("token");
$rating = filterRequest("rating");
$countRide = filterRequest("countRide");
$passengerId = filterRequest("passengerId");
$timeSelected = filterRequest("timeSelected");
$status = filterRequest("status");

// 🔐 تشفير الحقول الحساسة
$phone = $encryptionHelper->encryptData($phone);
$gender = $encryptionHelper->encryptData($gender);
$name = $encryptionHelper->encryptData($name);
$name_english = $encryptionHelper->encryptData($name_english);
$car_plate = $encryptionHelper->encryptData($car_plate);
$token = $encryptionHelper->encryptData($token);
$education = $encryptionHelper->encryptData($education);
$national_number = $encryptionHelper->encryptData($national_number);
$age = $encryptionHelper->encryptData($age);

// ⏰ تحويل الوقت للفحص
$selectedTime = new DateTime($timeSelected);
$startTime = $selectedTime->format('Y-m-d H:i:s');
$endTime = $selectedTime->add(new DateInterval('PT6H'))->format('Y-m-d H:i:s');

// ✅ فحص هل السائق لديه أكثر من رحلتين خلال 6 ساعات
$sqlCheck = "SELECT COUNT(*) as trip_count 
             FROM `mishwaritrips` 
             WHERE `driverId` = :driverId
             AND `timeSelected` BETWEEN :startTime AND :endTime";
$stmtCheck = $con->prepare($sqlCheck);
$stmtCheck->bindParam(':driverId', $driverId);
$stmtCheck->bindParam(':startTime', $startTime);
$stmtCheck->bindParam(':endTime', $endTime);
$stmtCheck->execute();
$result = $stmtCheck->fetch(PDO::FETCH_ASSOC);

if ($result['trip_count'] >= 2) {
    jsonError("Driver already has 2 trips within the specified period.");
    exit;
}

// ✅ فحص إن الراكب لا يملك رحلة فعالة بنفس اليوم
$sqlCheckPassenger = "
SELECT * 
FROM `mishwaritrips`
WHERE `passengerId` = :passengerId
AND `status` != 'Finished'
AND DATE(`timeSelected`) = CURDATE()
";
$stmtCheckPassenger = $con->prepare($sqlCheckPassenger);
$stmtCheckPassenger->bindParam(':passengerId', $passengerId);
$stmtCheckPassenger->execute();
$existingTrip = $stmtCheckPassenger->fetch(PDO::FETCH_ASSOC);

// إذا كانت موجودة يتم التحديث
if ($existingTrip) {
    $sqlUpdate = "UPDATE `mishwaritrips` SET 
        `driverId` = :driverId,
        `phone` = :phone,
        `gender` = :gender,
        `name` = :name,
        `name_english` = :name_english,
        `address` = :address,
        `religion` = :religion,
        `age` = :age,
        `startNameAddress` = :startNameAddress,
        `locationCoordinate` = :locationCoordinate,
        `education` = :education,
        `license_type` = :license_type,
        `national_number` = :national_number,
        `car_plate` = :car_plate,
        `make` = :make,
        `model` = :model,
        `color` = :color,
        `color_hex` = :color_hex,
        `token` = :token,
        `rating` = :rating,
        `countRide` = :countRide,
        `timeSelected` = :timeSelected,
        `status` = :status 
        WHERE `passengerId` = :passengerId";

    $stmtUpdate = $con->prepare($sqlUpdate);
    $stmtUpdate->execute([
        ':driverId' => $driverId,
        ':phone' => $phone,
        ':gender' => $gender,
        ':name' => $name,
        ':name_english' => $name_english,
        ':address' => $address,
        ':religion' => $religion,
        ':age' => $age,
        ':startNameAddress' => $startNameAddress,
        ':locationCoordinate' => $locationCoordinate,
        ':education' => $education,
        ':license_type' => $license_type,
        ':national_number' => $national_number,
        ':car_plate' => $car_plate,
        ':make' => $make,
        ':model' => $model,
        ':color' => $color,
        ':color_hex' => $color_hex,
        ':token' => $token,
        ':rating' => $rating,
        ':countRide' => $countRide,
        ':timeSelected' => $timeSelected,
        ':status' => $status,
        ':passengerId' => $passengerId
    ]);

    if ($stmtUpdate->rowCount() > 0) {
        jsonSuccess(null, "Trip updated successfully");
    } else {
        jsonError("Failed to update trip data");
    }

} else {
    // إدخال رحلة جديدة
    $sqlInsert = "INSERT INTO `mishwaritrips` (
        `driverId`, `phone`, `gender`, `name`, `name_english`, `address`, `religion`, 
        `age`, `startNameAddress`, `locationCoordinate`, `education`, `license_type`, 
        `national_number`, `car_plate`, `make`, `model`, `color`, `color_hex`, `token`, 
        `rating`, `countRide`, `passengerId`, `timeSelected`, `createdAt`, `status`
    ) VALUES (
        :driverId, :phone, :gender, :name, :name_english, :address, :religion, 
        :age, :startNameAddress, :locationCoordinate, :education, :license_type, 
        :national_number, :car_plate, :make, :model, :color, :color_hex, :token, 
        :rating, :countRide, :passengerId, :timeSelected, NOW(), :status
    )";

    $stmtInsert = $con->prepare($sqlInsert);
    $stmtInsert->execute([
        ':driverId' => $driverId,
        ':phone' => $phone,
        ':gender' => $gender,
        ':name' => $name,
        ':name_english' => $name_english,
        ':address' => $address,
        ':religion' => $religion,
        ':age' => $age,
        ':startNameAddress' => $startNameAddress,
        ':locationCoordinate' => $locationCoordinate,
        ':education' => $education,
        ':license_type' => $license_type,
        ':national_number' => $national_number,
        ':car_plate' => $car_plate,
        ':make' => $make,
        ':model' => $model,
        ':color' => $color,
        ':color_hex' => $color_hex,
        ':token' => $token,
        ':rating' => $rating,
        ':countRide' => $countRide,
        ':passengerId' => $passengerId,
        ':timeSelected' => $timeSelected,
        ':status' => $status
    ]);

    if ($stmtInsert->rowCount() > 0) {
        jsonSuccess(null, "New trip inserted successfully");
    } else {
        jsonError("Failed to insert new trip data");
    }
}
?>

File: ride/mishwari/get.php

<?php
require_once __DIR__ . '/../../connect.php';
$driverId = filterRequest("driverId");

$sql = "
SELECT
    mi.`id`,
    mi.`driverId`,
    mi.`phone`,
    mi.`gender`,
    mi.`name`,
    mi.`name_english`,
    mi.`address`,
    mi.`religion`,
    mi.`age`,
    mi.`education`,
    mi.`license_type`,
    mi.`national_number`,
    mi.`car_plate`,
    mi.`make`,
    mi.`model`,
    mi.`color`,
    mi.`color_hex`,
    mi.`token`,
    mi.`rating`,
    mi.`countRide`,
    mi.`passengerId`,
    mi.`timeSelected`,
    mi.`createdAt`,
    mi.`status`,
    p.phone AS passengerPhone,
    p.first_name AS passengerName,
    p.last_name AS passengerLastName,
    p.gender AS passengergender,
    d.name_arabic,
    tkp.token AS passengerToken
FROM
    `mishwaritrips` mi
LEFT JOIN driver d ON
    d.id = mi.driverId
LEFT JOIN passengers p ON
    p.id = mi.passengerId
LEFT JOIN tokens tkp ON
    tkp.passengerID = mi.passengerId
WHERE
   mi. passengerId = :driverId
   AND mi.createdAt >= CURDATE() - INTERVAL 4 DAY
     AND mi.timeSelected > NOW()
ORDER BY
   mi. `createdAt`
DESC
LIMIT 1

     ";
$stmt = $con->prepare($sql);
$stmt->bindParam(':driverId', $driverId, PDO::PARAM_STR);
$stmt->execute();

if ($stmt->rowCount() > 0) {
    // Fetch the record
    $row = $stmt->fetchAll(PDO::FETCH_ASSOC);

    jsonSuccess($row);
    
}
    else{
    // Print a failure message
    jsonError($message = "No wallet record found");
}
?>

File: ride/mishwari/cancel.php

<?php
require_once __DIR__ . '/../../connect.php';

// Fetch the input data
$id = filterRequest("id");  // Trip ID to identify the trip
$status = "cancelled";  // New status

// Check if the trip ID is provided
if (empty($id)) {
    jsonError("Trip ID is missing.");
    exit;
}

// Update the status of the trip to "cancelled"
$sql = "
UPDATE `mishwaritrips`
SET `status` = :status
WHERE `id` = :id AND `status` != 'cancelled'
";

$stmt = $con->prepare($sql);
$stmt->bindParam(':status', $status, PDO::PARAM_STR);
$stmt->bindParam(':id', $id, PDO::PARAM_INT);  // Bind the ID parameter

// Execute the update
if ($stmt->execute()) {
    // Check if the update was successful
    if ($stmt->rowCount() > 0) {
        // Trip status updated successfully
        jsonSuccess(null, "Trip cancelled successfully.");
    } else {
        // No rows updated, meaning the trip might not have been found or was already cancelled
        jsonError("No trip found to cancel.");
    }
} else {
    // Print failure if the update query failed
    $errorInfo = $stmt->errorInfo();
    error_log('SQL Error: ' . implode(", ", $errorInfo));
    jsonError("Failed to cancel the trip.");
}
?>

File: ride/mishwari/getDriver.php

<?php
require_once __DIR__ . '/../../connect.php';
$driverId = filterRequest("driverId");

$sql = "
SELECT
    mi.`id`,
    mi.`driverId`,
    mi.`phone`,
    mi.`gender`,
    mi.`name`,
    mi.`name_english`,
    mi.`address`,
    mi.`religion`,
    mi.`age`,
    mi.`education`,
    mi.`license_type`,
    mi.`national_number`,
    mi.`car_plate`,
    mi.`make`,
    mi.`model`,
    mi.`color`,
    mi.`color_hex`,
    mi.`token`,
    mi.`rating`,
    mi.`countRide`,
    mi.`passengerId`,
    mi.`timeSelected`,
    mi.`createdAt`,
    mi.`status`,
    p.phone AS passengerPhone,
    p.first_name AS passengerName,
    p.last_name AS passengerLastName,
    p.gender AS passengergender,
    d.name_arabic,
    tkp.token AS passengerToken
FROM
    `mishwaritrips` mi
LEFT JOIN driver d ON
    d.id = mi.driverId
LEFT JOIN passengers p ON
    p.id = mi.passengerId
LEFT JOIN tokens tkp ON
    tkp.passengerID = mi.passengerId
WHERE
   mi. driverId = :driverId
   AND mi.createdAt >= CURDATE() - INTERVAL 4 DAY
     AND mi.timeSelected > NOW()
ORDER BY
   mi. `createdAt`
DESC
LIMIT 1

     ";
$stmt = $con->prepare($sql);
$stmt->bindParam(':driverId', $driverId, PDO::PARAM_STR);
$stmt->execute();

if ($stmt->rowCount() > 0) {
    // Fetch the record
    $row = $stmt->fetchAll(PDO::FETCH_ASSOC);

    jsonSuccess($row);
    
}
    else{
    // Print a failure message
    jsonError($message = "No wallet record found");
}
?>

File: ride/mishwari/test.php

<?php
require_once __DIR__ . '/../../connect.php';

$sql = "SELECT * FROM `passengers` ORDER BY `created_at` DESC LIMIT 5";
$stmt = $con->prepare($sql);
$stmt->execute();

if ($stmt->rowCount() > 0) {
    $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);

    // فك التشفير للحقول الحساسة
    foreach ($rows as &$row) {
        $row['phone']           = $encryptionHelper->decryptData($row['phone']);
        $row['email']           = $encryptionHelper->decryptData($row['email']);
        $row['gender']          = $encryptionHelper->decryptData($row['gender']);
        $row['birthdate']       = $encryptionHelper->decryptData($row['birthdate']);
        $row['site']            = $encryptionHelper->decryptData($row['site']);
        $row['first_name']      = $encryptionHelper->decryptData($row['first_name']);
        $row['last_name']       = $encryptionHelper->decryptData($row['last_name']);
        $row['sosPhone']        = $encryptionHelper->decryptData($row['sosPhone']);
        $row['education']       = $encryptionHelper->decryptData($row['education']);
        $row['employmentType']  = $encryptionHelper->decryptData($row['employmentType']);
        $row['maritalStatus']   = $encryptionHelper->decryptData($row['maritalStatus']);
    }

    jsonSuccess($rows);
} else {
    jsonError("No passengers found");
}
?>

File: ride/driverWallet/driverStatistic.php

<?php
require_once __DIR__ . '/../../connect.php';
$driverID = filterRequest("driverID");

$sql = "SELECT
    YEAR(`driver_orders`.`created_at`) AS `year`,
    MONTH(`driver_orders`.`created_at`) AS `month`,
    COUNT(*) AS `total_orders`,
    SUM(CASE WHEN `ride`.`status` = 'Finished' THEN 1 ELSE 0 END) AS `completed_orders`,
    SUM(CASE WHEN `ride`.`status` = 'Apply' THEN 1 ELSE 0 END) AS `pending_orders`,
    SUM(CASE WHEN `ride`.`status` = 'Cancel' THEN 1 ELSE 0 END) AS `canceled_orders`,
    ROUND(SUM(CASE WHEN `ride`.`status` = 'Finished' THEN 1 ELSE 0 END) / COUNT(*) * 100, 2) AS `percent_completed`,
    ROUND(SUM(CASE WHEN `ride`.`status` = 'Apply' THEN 1 ELSE 0 END) / COUNT(*) * 100, 2) AS `percent_pending`,
    ROUND(SUM(CASE WHEN `ride`.`status` = 'Cancel' THEN 1 ELSE 0 END) / COUNT(*) * 100, 2) AS `percent_canceled`,
    SUM(CASE WHEN `ride`.`status` = 'Refused' THEN 1 ELSE 0 END) AS `rejected_orders`,
    ROUND(SUM(CASE WHEN `ride`.`status` = 'Refused' THEN 1 ELSE 0 END) / COUNT(*) * 100, 2) AS `percent_rejected`
FROM
    `driver_orders`
LEFT JOIN `ride` ON `ride`.`id` = `driver_orders`.`order_id`
WHERE
    `driver_orders`.`driver_id` = '$driverID'
    AND YEAR(`driver_orders`.`created_at`) = YEAR(CURDATE())
    AND MONTH(`driver_orders`.`created_at`) = MONTH(CURDATE())
GROUP BY
    YEAR(`driver_orders`.`created_at`),
    MONTH(`driver_orders`.`created_at`)
ORDER BY
    `year`,
    `month`;

";
$stmt = $con->prepare($sql);
$stmt->execute();

if ($stmt->rowCount() > 0) {
    // Fetch the record
    $row = $stmt->fetchAll(PDO::FETCH_ASSOC);

    jsonSuccess($row);
    
}
    else{
    // Print a failure message
    jsonError($message = "No wallet record found");
}
?>

File: ride/driverWallet/add.php

<?php

// Include the database connection file
require_once __DIR__ . '/../../connect.php';

// Get the request parameters
$driverID = filterRequest("driverID");
$paymentID = filterRequest("paymentID");
$amount = filterRequest("amount");
$paymentMethod = filterRequest("paymentMethod");
$token = filterRequest("token");

// Retrieve token details from the database
$stmt = $con->prepare("SELECT * FROM payment_tokens WHERE token = :token AND isUsed = FALSE");
$stmt->execute(array(
    ':token' => $token
));

$tokenData = $stmt->fetch();

if ($tokenData) {
    // Add payment to the driver's wallet table
    $sql = "INSERT INTO `driverWallet` (
        `driverID`,
        `paymentID`,
        `amount`,
        `paymentMethod`
    ) VALUES (
        :driverID,
        :paymentID,
        :amount,
        :paymentMethod
    );";

    $stmt = $con->prepare($sql);
    $stmt->execute(array(
        ':driverID' => $driverID,
        ':paymentID' => $paymentID,
        ':amount' => $amount,
        ':paymentMethod' => $paymentMethod
    ));

    if ($stmt->rowCount() > 0) {
        // Print a success message
        jsonSuccess(null, "Record saved successfully");
        
        // Mark the token as used in the database
        $stmt = $con->prepare("UPDATE payment_tokens SET isUsed = TRUE WHERE id = :tokenID");
        $stmt->execute(array(
            ':tokenID' => $tokenData['id']
        ));
    } else {
        // Print a failure message
        jsonError("Failed to save record");
    }
} else {
    jsonError("Invalid or already used token");
}

File: ride/driverWallet/update.php


File: ride/driverWallet/get.php

<?php
require_once __DIR__ . '/../../connect.php';
$driverID = filterRequest("driverID");

$sql = "SELECT
    COALESCE(dw.id, 0) AS id,
    COALESCE(dw.driverID, '0') AS driverID,
    COALESCE(dw.paymentID, '0') AS paymentID,
    COALESCE(dw.dateCreated, '1970-01-01 00:00:00') AS dateCreated,
    COALESCE(dw.amount, 0) AS amount,
    COALESCE(dw.paymentMethod, '0') AS paymentMethod,
    COALESCE(dw.dateUpdated, '1970-01-01 00:00:00') AS dateUpdated,
    COALESCE((SELECT SUM(amount) FROM driverWallet WHERE driverID = '$driverID'), 0) AS total_amount
FROM
    driverWallet dw
WHERE
    dw.driverID = '$driverID'
GROUP BY
    dw.id,
    dw.driverID,
    dw.paymentID,
    dw.dateCreated,
    dw.amount,
    dw.paymentMethod,
    dw.dateUpdated

     ";
$stmt = $con->prepare($sql);
$stmt->execute();

if ($stmt->rowCount() > 0) {
    // Fetch the record
    $row = $stmt->fetchAll(PDO::FETCH_ASSOC);

    jsonSuccess($row);
    
}
    else{
    // Print a failure message
    jsonError($message = "No wallet record found");
}
?>

File: ride/driverWallet/getDriverWeekPaymentMove.php

<?php
require_once __DIR__ . '/../../connect.php';
$driverID = filterRequest("driverID");

$sql = "SELECT 
    `id`, 
    `driverID`, 
    `paymentID`, 
    `dateCreated`, 
    `amount`, 
    `paymentMethod`, 
    `dateUpdated`, 
    (SELECT SUM(`amount`) 
     FROM `driverWallet` 
     WHERE `driverID` = '$driverID' 
     AND `dateCreated` >= DATE_SUB(NOW(), INTERVAL 1 WEEK)
    ) AS totalAmount
FROM `driverWallet`
WHERE `driverID` = '$driverID'
AND `dateCreated` >= DATE_SUB(NOW(), INTERVAL 1 WEEK)
ORDER BY `dateCreated` DESC;
";
$stmt = $con->prepare($sql);
$stmt->execute();

if ($stmt->rowCount() > 0) {
    // Fetch the record
    $row = $stmt->fetchAll(PDO::FETCH_ASSOC);

    jsonSuccess($row);
    
}
    else{
    // Print a failure message
    jsonError($message = "No wallet record found");
}
?>

File: ride/driverWallet/getWalletByDriver.php

<?php
require_once __DIR__ . '/../../connect.php';
$driverID = filterRequest("driverID");

$sql = "SELECT
    paymentsDriverPoints.`id`,
    paymentsDriverPoints.amount,
    paymentsDriverPoints.created_at
FROM
    `paymentsDriverPoints`
WHERE
    paymentsDriverPoints.driverID = '$driverID' AND paymentsDriverPoints.created_at >= DATE_SUB(NOW(), INTERVAL 1 MONTH)
ORDER BY
    `paymentsDriverPoints`.`id`
DESC";
$stmt = $con->prepare($sql);
$stmt->execute();

if ($stmt->rowCount() > 0) {
    // Fetch the record
    $row = $stmt->fetchAll(PDO::FETCH_ASSOC);

    jsonSuccess($row);
    
}
    else{
    // Print a failure message
    jsonError($message = "No wallet record found");
}
?>

File: ride/driverWallet/getDriverDetails.php

<?php
require_once __DIR__ . '/../../connect.php';

$driver_phone = filterRequest("driver_phone");

$sql = "SELECT
    `driverToken`.`token`,
    `driver`.`id`,
    `driver`.`phone`,
    `driver`.`name_arabic`as name,
    driver.national_number
FROM
    `driverToken`
LEFT JOIN `driver` ON `driver`.`id` = `driverToken`.`captain_id`
WHERE
    `driver`.`phone` = '$driver_phone'";

$stmt = $con->prepare($sql);
$stmt->execute();
$data = $stmt->fetchAll(PDO::FETCH_ASSOC);

if ($data) {
    // Print the car location data as JSON
    echo json_encode([
            'status' => 'success',
            
            'data' => $data
        ]);
} else {
    // Print a failure message
    jsonError($message = "No car locations found");
}

?>

File: ride/driverWallet/sendEmailTransfer.php

<?php

// Connect to database
require_once __DIR__ . '/../../connect.php';

// Get trip details
$driverName = filterRequest('name');
$driverEmail = filterRequest('email');
$driverPhone = filterRequest('phone');
$amount = filterRequest('amount');
$newDriverName = filterRequest('newDriver');
$newEmail=filterRequest('newEmail');

// Get language preference from database or user input
$language = 'en'; // Default to English
// Email content
if ($language === 'ar') {
  $bodyEmail = "<html>
    <head>
      <style>
        body {
          font-family: Arial, sans-serif;
          background-color: #f5f8fa;
          color: #14171a;
        }
        .container {
          max-width: 600px;
          margin: 0 auto;
          padding: 20px;
          background-color: white;
          border-radius: 5px;
          box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
        }
        h1 {
          color: #1da1f2;
          margin-top: 0;
        }
        p {
          line-height: 1.5;
        }
        a {
          color: #1da1f2;
          text-decoration: none;
        }
        a:hover {
          text-decoration: underline;
        }
      </style>
    </head>
    <body>
      <div class='container'>
        <h1>تفاصيل نقلك على سفر</h1>
        <p>شكراً لاستخدام خدمتنا. نتمنى لك يوماً رائعاً!</p>
        <p>نريد إعلامك أن مبلغ $amount تم نقله من حسابك إلى السائق الجديد، $newDriverName (هاتف: $driverPhone).</p>
        <p>مع خالص التحية،<br> فريق سفر</p>
      </div>
    </body>
  </html>";
} else {
  $bodyEmail = "<html>
    <head>
      <style>
        body {
          font-family: Arial, sans-serif;
          background-color: #f5f8fa;
          color: #14171a;
        }
        .container {
          max-width: 600px;
          margin: 0 auto;
          padding: 20px;
          background-color: white;
          border-radius: 5px;
          box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
        }
        h1 {
          color: #1da1f2;
          margin-top: 0;
        }
        p {
          line-height: 1.5;
        }
        a {
          color: #1da1f2;
          text-decoration: none;
        }
        a:hover {
          text-decoration: underline;
        }
      </style>
    </head>
    <body>
      <div class='container'>
      <img src='https://lh3.googleusercontent.com/a/ACg8ocLe5TgvmTjoFx7KjIoWGxX0G2ryKBTzUZi2-mBYb9DI1dsKQ0WEYh5ZPdnA3WeFbp9VnaTNzJuA0w8S4RiQ7042AKrOwXo3=s576-c-no' alt='SEFER App Logo' style='width: 150px; margin: 20px auto; display: block;'>

        <h1>Your SEFER Transfer Details</h1>
        <p>Thank you for using our service. We hope you have a great day!</p>
        <p>We want to inform you that an amount of $amount has been transferred from your account to the new driver: $newDriverName (Phone: $driverPhone).</p>
        <p>Regards,<br> SEFER Team</p>
      </div>
    </body>
  </html>";
}

// Email headers
$supportEmail = 'seferteam@sefer.live';
$headers = "MIME-Version: 1.0\r\n";
$headers .= "Content-Type: text/html; charset=UTF-8\r\n";
$headers .= "From: $supportEmail\r\n";

// Send email
if (!empty($driverEmail)) {
  if (mail($driverEmail, "Your SEFER Transfer Details", $bodyEmail, $headers)) {
   
    mail($newEmail, "Your SEFER Transfer Details", $bodyEmail, $headers);
     echo "Email sent successfully.";
  } else {
    echo "Email sending failed.";
  }
} else {
  echo "Invalid email address: $driverEmail";
}

File: ride/driverWallet/delete.php


File: ride/driverWallet/addPaymentToken.php

<?php
require_once __DIR__ . '/../../connect.php';

$driverID = filterRequest("driverID");
$amount = filterRequest("amount");

// Check if required fields are present
if ($driverID === null || $amount === null) {
    jsonError("Missing required fields: driverID and amount must be provided");
    exit;
}

// Generate a more secure token
$token = generateSecureToken($driverID, $amount);

// Store the token in the database
$stmt = $con->prepare("INSERT INTO payment_tokens (token, driverID, dateCreated, amount) VALUES (?, ?, NOW(), ?)");

try {
    $stmt->execute([$token, $driverID, $amount]);
    if ($stmt->rowCount() > 0) {
        jsonSuccess($token);
    } else {
        jsonError("Failed to save record");
    }
} catch (PDOException $e) {
    jsonError("Database error: " . $e->getMessage());
}

function generateSecureToken($driverID, $amount) {
    global $secretKey;
    // Concatenate the parameters
    $data = $driverID . $amount . time();

    // Add the secret key from the environment variable
    $data .= $secretKey;

    // Generate a hash
    $hash = hash('sha256', $data);

    // Add some randomness
    $randomBytes = bin2hex(random_bytes(16));

    // Combine hash and random bytes
    $token = $hash . $randomBytes;

    // Truncate to a reasonable length (e.g., 64 characters)
    return substr($token, 0, 64);
}

File: ride/location/getSpeed.php

<?php
require_once __DIR__ . '/../../connect.php'; // يفترض أن هذا الملف ينشئ $con و $con_tracking
//getSpeed.php
try {
    // 1) قراءة والتحقق من الإحداثيات
    $southwestLat = filterRequest("southwestLat");
    $southwestLon = filterRequest("southwestLon");
    $northeastLat = filterRequest("northeastLat");
    $northeastLon = filterRequest("northeastLon");

    if ($southwestLat === false || $southwestLon === false || $northeastLat === false || $northeastLon === false) {
        jsonError("Invalid coordinates provided");
        exit;
    }

    $freshSeconds = 180; // 3 دقائق

    // =================================================================
    // الخطوة 1: جلب المواقع والمعرفات من قاعدة بيانات التتبع
    // =================================================================
    $boundingBoxWKT = sprintf(
        'POLYGON((%f %f, %f %f, %f %f, %f %f, %f %f))',
        $southwestLon, $southwestLat,
        $northeastLon, $southwestLat,
        $northeastLon, $northeastLat,
        $southwestLon, $northeastLat,
        $southwestLon, $southwestLat
    );

    // نجلب مجموعة من المرشحين المحتملين للفلترة والترتيب لاحقاً
    $sql_locations = "
        SELECT driver_id, latitude, longitude, heading, speed, status, updated_at
        FROM car_locations
        WHERE
            ST_CONTAINS(ST_GeomFromText(:boundingBox, 4326), location_point)
            AND status = 'off'
            AND updated_at >= NOW() - INTERVAL :freshSeconds SECOND
        ORDER BY updated_at DESC
        LIMIT 100; -- نجلب 100 مرشح محتمل
    ";

    $stmt_locations = $con_tracking->prepare($sql_locations);
    $stmt_locations->bindValue(':boundingBox', $boundingBoxWKT);
    $stmt_locations->bindValue(':freshSeconds', $freshSeconds, PDO::PARAM_INT);
    $stmt_locations->execute();
    $locations = $stmt_locations->fetchAll(PDO::FETCH_ASSOC);

    if (!$locations) {
        jsonError("No car locations found in the specified area.");
        exit;
    }

    // =================================================================
    // الخطوة 2: تجميع معرفات السائقين (driver_id)
    // =================================================================
    $driver_ids = array_column($locations, 'driver_id');

    // =================================================================
    // الخطوة 3: جلب البيانات الثابتة من القاعدة الأساسية وتطبيق الفلاتر الإضافية
    // =================================================================
    $drivers_info = [];
    if (!empty($driver_ids)) {
        $placeholders = implode(',', array_fill(0, count($driver_ids), '?'));

        // هنا نطبق الشروط الخاصة بهذا السكريبت (موديل السيارة > 2000)
        $sql_drivers_info = "
            SELECT
                d.id AS driver_id, d.phone, d.email, d.birthdate, d.first_name, d.last_name, d.gender, d.maritalStatus,
                cr.make, cr.model, cr.color, cr.color_hex, cr.year,
                dt.token,
                COALESCE(rdAvg.ratingDriver, 0) AS ratingDriver,
                COALESCE(rdAvg.ratingCount, 0) AS ratingCount
            FROM driver d
            LEFT JOIN CarRegistration cr ON cr.driverID = d.id
            LEFT JOIN driverToken dt ON dt.captain_id = d.id
            LEFT JOIN (
                SELECT driver_id, AVG(rating) AS ratingDriver, COUNT(id) AS ratingCount
                FROM ratingDriver
                GROUP BY driver_id
            ) rdAvg ON rdAvg.driver_id = d.id
            WHERE d.id IN ($placeholders)
             -- AND COALESCE(cr.year, 0) > 2000 -- ⭐ الشرط الخاص بهذا السكريبت
           --   AND (cr.make NOT LIKE '%دراج%' AND cr.model NOT LIKE '%دراج%')
              AND (cr.model NOT LIKE '%Van%' AND cr.make NOT LIKE '%Van%')
        ";

        $stmt_drivers_info = $con->prepare($sql_drivers_info);
        $stmt_drivers_info->execute($driver_ids);
        $drivers_info_raw = $stmt_drivers_info->fetchAll(PDO::FETCH_ASSOC);

        // تحويل المصفوفة لتسهيل عملية الدمج لاحقاً
        foreach ($drivers_info_raw as $driver) {
            $drivers_info[$driver['driver_id']] = $driver;
        }
    }

    // =================================================================
    // الخطوة 4: دمج النتائج في PHP
    // =================================================================
    $final_results = [];
    foreach ($locations as $location) {
        $driver_id = $location['driver_id'];
        if (isset($drivers_info[$driver_id])) {
            $final_results[] = array_merge($location, $drivers_info[$driver_id]);
        }
    }

    // =================================================================
    // الخطوة 5: تطبيق الترتيب والحد النهائي في PHP
    // =================================================================
    usort($final_results, function ($a, $b) {
        if ($a['ratingDriver'] != $b['ratingDriver']) {
            return $b['ratingDriver'] <=> $a['ratingDriver'];
        }
        if ($a['ratingCount'] != $b['ratingCount']) {
            return $b['ratingCount'] <=> $a['ratingCount'];
        }
        return strtotime($b['updated_at']) <=> strtotime($a['updated_at']);
    });

    $limited_results = array_slice($final_results, 0, 10);

    if (empty($limited_results)) {
        jsonError("No cars matching the specific criteria (year > 2000) found.");
        exit;
    }

    // =================================================================
    // الخطوة 6: فك التشفير وحساب العمر (بدون تغيير)
    // =================================================================
    $fieldsToDecrypt = [ 'phone','email','gender','birthdate', 'first_name','last_name', 'token','car_plate','vin' ];
    foreach ($limited_results as &$row) {
        foreach ($fieldsToDecrypt as $field) {
            if (isset($row[$field]) && !empty($row[$field])) {
                try { $row[$field] = $encryptionHelper->decryptData($row[$field]); }
                catch (Exception $e) { $row[$field] = null; }
            }
        }
        if (!empty($row['birthdate'])) {
            try {
                $birthDate = new DateTime($row['birthdate']);
                $today = new DateTime();
                $row['age'] = $today->diff($birthDate)->y;
            } catch (Exception $e) { $row['age'] = null; }
        } else {
            $row['age'] = null;
        }
    }
    unset($row);

    jsonSuccess($limited_results);

} catch (PDOException $e) {
    jsonError("Database error: " . $e->getMessage());
} catch (Throwable $e) {
    jsonError("Internal error: " . $e->getMessage());
}

File: ride/location/add.php

<?php
require_once __DIR__ . '/../../connect.php';
header('Content-Type: application/json; charset=utf-8');

try {
    $driver_id = filterRequest("driver_id");
    $latitude  = filterRequest("latitude");
    $longitude = filterRequest("longitude");
    $status    = filterRequest("status");
    $heading   = filterRequest("heading");
    $speed     = filterRequest("speed");

    // distance قد تأتي باسم totalDistance من التطبيق
    $distanceRaw = filterRequest("distance");
    if ($distanceRaw === null || $distanceRaw === '') {
        $distanceRaw = filterRequest("totalDistance");
    }

    // تطبيع القيم الرقمية
    $norm = function($v, $default = 0.0) {
        if ($v === null) return $default;
        $v = str_replace(',', '.', trim((string)$v));
        return is_numeric($v) ? (float)$v : $default;
    };

    $lat  = $norm($latitude, 0.0);
    $lng  = $norm($longitude, 0.0);
    $head = $norm($heading, 0.0);
    $spd  = $norm($speed, 0.0);

    // ✅ قرّب لمرتين عشريتين ليتطابق مع DECIMAL(10,2)
    $dist = round($norm($distanceRaw, 0.0), 2);

    // ✅ حارس بسيط للمدى (اختياري)
    if ($dist > 99999999.99) { $dist = 99999999.99; }
    if ($dist < -99999999.99){ $dist = -99999999.99; }

    if (empty($driver_id) || ($lat == 0.0 && $lng == 0.0)) {
        jsonError("Invalid payload");
        exit;
    }

    $created_at = date("Y-m-d H:i:s");

    $sql = "INSERT INTO `car_tracks`
        (`driver_id`,`latitude`,`longitude`,`heading`,`speed`,`distance`,`status`,`created_at`)
        VALUES
        (:driver_id,:latitude,:longitude,:heading,:speed,:distance,:status,:created_at)";

    $stmt = $con->prepare($sql);
    $ok = $stmt->execute([
        ':driver_id'  => $driver_id,
        ':latitude'   => $lat,
        ':longitude'  => $lng,
        ':heading'    => $head,
        ':speed'      => $spd,
        ':distance'   => $dist,      // ← now DECIMAL(10,2)-friendly
        ':status'     => (string)($status ?? 'on'),
        ':created_at' => $created_at,
    ]);

    if ($ok) {
        jsonSuccess(null, "car_tracks saved successfully");
    } else {
        jsonError("Failed to save car track");
    }
} catch (PDOException $e) {
    error_log("car_tracks insert error: " . $e->getMessage());
    jsonError("Database error");
} catch (Throwable $e) {
    error_log("car_tracks insert fatal: " . $e->getMessage());
    jsonError("Server error");
}

File: ride/location/getfemalbehavior.php

<?php
require_once __DIR__ . '/../../connect.php';
try {
    $southwestLat = filterRequest("southwestLat");
    $southwestLon = filterRequest("southwestLon");
    $northeastLat = filterRequest("northeastLat");
    $northeastLon = filterRequest("northeastLon");

    $sql = "
SELECT
    cl.driver_id,
    cl.latitude,
    cl.longitude,
    cl.heading,
    cl.speed,
    cl.status,
    cl.created_at,
    cl.updated_at,
    d.phone,
    d.email,
    d.birthdate,
    d.first_name,
    d.last_name,
    d.gender,
    d.maritalStatus,
    cr.make,
    cr.car_plate,
    cr.model,
    cr.color,
    cr.vin,
    cr.color_hex,
    cr.year,
    dt.token,
    COALESCE(AVG(rd.rating), 0) AS ratingDriver,
    COUNT(rd.id) AS ratingCount,
    TIMESTAMPDIFF(YEAR, d.birthdate, CURDATE()) AS age,
    (
        SELECT COALESCE(AVG(sub.behavior_score), 100)
        FROM (
            SELECT behavior_score
            FROM driver_behavior db
            WHERE db.driver_id = cl.driver_id
            ORDER BY db.id DESC
            LIMIT 5
        ) AS sub
    ) AS ai_behavior_score
FROM
    car_locations cl
LEFT JOIN driver d ON
    d.id = cl.driver_id
LEFT JOIN CarRegistration cr ON
    cr.driverID = cl.driver_id
LEFT JOIN driverToken dt ON
    dt.captain_id = cl.driver_id
LEFT JOIN ratingDriver rd ON
    rd.driver_id = cl.driver_id
WHERE
    cl.latitude >= :southwestLat AND cl.latitude <= :northeastLat 
    AND cl.longitude >= :southwestLon AND cl.longitude <= :northeastLon
    AND cl.status = 'off'
    AND cl.updated_at >= NOW() - INTERVAL 5 SECOND
    AND (cr.make NOT LIKE '%دراجة%' OR cr.model NOT LIKE '%دراجة%')
    AND d.gender = 'Female'
GROUP BY cl.driver_id
ORDER BY ratingDriver DESC, cl.updated_at DESC
LIMIT 10;
";

    $stmt = $con->prepare($sql);
    $stmt->bindParam(':southwestLat', $southwestLat);
    $stmt->bindParam(':southwestLon', $southwestLon);
    $stmt->bindParam(':northeastLat', $northeastLat);
    $stmt->bindParam(':northeastLon', $northeastLon);

    $stmt->execute();
    $car_locations = $stmt->fetchAll(PDO::FETCH_ASSOC);

    if ($car_locations) {
        jsonSuccess($car_locations);
    } else {
        jsonError("No car locations found");
    }
} catch (PDOException $e) {
    jsonError("Database error: " . $e->getMessage());
}
?>

File: ride/location/getDriverTimeOnline.php

<?php
// getDriverTimeOnline.php
// الغرض: توليد تقرير نشاط السائقين لآخر 10 أيام بناءً على الملخص اليومي

require_once __DIR__ . '/../../get_connect.php';

header('Content-Type: application/json; charset=utf-8');

// إعدادات التقرير
$daysToLookBack = 10; // عدد الأيام في الماضي
$jsonFileName = 'active_drivers_cache.json';
$savePath = __DIR__ . '/' . $jsonFileName;

try {
    // =================================================================
    // 1. جلب البيانات من جدول الملخصات (سيرفر اللوكيشن) ⚡
    // =================================================================
    // نجمع الثواني لكل سائق خلال الفترة المحددة
    
    $sql_summary = "
        SELECT 
            driver_id, 
            SUM(total_seconds) as grand_total_seconds,
            COUNT(DISTINCT date) as days_worked -- (اختياري) معرفة عدد أيام العمل الفعلية
        FROM driver_daily_summary
        WHERE date >= DATE_SUB(CURDATE(), INTERVAL ? DAY)
        GROUP BY driver_id
        HAVING grand_total_seconds > 60 -- (اختياري) تجاهل من عمل أقل من دقيقة
        ORDER BY grand_total_seconds DESC
    ";

    $stmt = $con_tracking->prepare($sql_summary);
    $stmt->execute([$daysToLookBack]);
    $summary_data = $stmt->fetchAll(PDO::FETCH_ASSOC);

    if (empty($summary_data)) {
        // حفظ ملف فارغ وإنهاء
        saveJsonFile($savePath, ["last_updated" => date('Y-m-d H:i:s'), "data" => []]);
        printSuccess("No active drivers found in summary.", $savePath);
        exit;
    }

    // =================================================================
    // 2. جلب تفاصيل السائقين (الأسماء) من السيرفر الرئيسي 📝
    // =================================================================
    
    // استخراج الـ IDs
    $driver_ids = array_column($summary_data, 'driver_id');
    
    // تجهيز الـ Placeholders (?,?,?)
    $placeholders = implode(',', array_fill(0, count($driver_ids), '?'));

    $sql_drivers = "SELECT id, name_arabic, phone, created_at FROM driver WHERE id IN ($placeholders)";
    
    $stmt_d = $con->prepare($sql_drivers);
    $stmt_d->execute($driver_ids);
    $drivers_raw = $stmt_d->fetchAll(PDO::FETCH_ASSOC);

    // تحويل البيانات لـ Map لسرعة الدمج: [id => data]
    $drivers_map = [];
    foreach ($drivers_raw as $d) {
        $drivers_map[$d['id']] = $d;
    }

    // =================================================================
    // 3. دمج البيانات وفك التشفير وتنسيق الوقت 🔄
    // =================================================================
    
    $final_report = [];
    $fieldsToDecrypt = ['phone', 'name_arabic']; // الحقول المشفرة

    foreach ($summary_data as $row) {
        $did = $row['driver_id'];
        $seconds = $row['grand_total_seconds'];

        // البيانات الشخصية
        $personalData = isset($drivers_map[$did]) ? $drivers_map[$did] : ['name_arabic' => 'Unknown', 'phone' => ''];

        // فك التشفير
        foreach ($fieldsToDecrypt as $field) {
            if (!empty($personalData[$field])) {
                try {
                    $personalData[$field] = $encryptionHelper->decryptData($personalData[$field]);
                } catch (Exception $e) {
                    // ابقها مشفرة أو ضع قيمة افتراضية عند الفشل
                }
            }
        }

        // تنسيق الوقت (مقروء للبشر)
        $hours = floor($seconds / 3600);
        $minutes = floor(($seconds % 3600) / 60);
        $human_time = sprintf("%d ساعة و %d دقيقة", $hours, $minutes);

        // بناء الصف النهائي
        $final_report[] = [
            'driver_id'   => $did,
            'name'        => $personalData['name_arabic'],
            'phone'       => $personalData['phone'],
            'join_date'   => $personalData['created_at'], // تاريخ انضمام السائق
            'total_seconds' => $seconds,
            'active_time' => $human_time,
            'days_active' => $row['days_worked'] // عدد الأيام التي عمل فيها خلال الـ 10 أيام
        ];
    }

    // =================================================================
    // 4. الحفظ والنشر 💾
    // =================================================================
    
    $output = [
        "last_updated" => date('Y-m-d H:i:s'),
        "period_days" => $daysToLookBack,
        "total_drivers" => count($final_report),
        "data" => $final_report
    ];

    saveJsonFile($savePath, $output);
    printSuccess("Report generated based on Daily Summary.", $savePath);

} catch (Exception $e) {
    jsonError("Error: " . $e->getMessage());
}

// --- دوال مساعدة ---
function saveJsonFile($path, $data) {
    $json = json_encode($data, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
    file_put_contents($path, $json);
}
?>

File: ride/location/update.php

<?php

require_once __DIR__ . '/../../connect.php';

$driver_id = filterRequest("driver_id");
$latitude = filterRequest("latitude");
$longitude = filterRequest("longitude");
$status = filterRequest("status");
$heading = filterRequest("heading");
$speed = filterRequest("speed");
$distance = filterRequest("distance");
$updated_at = date("Y-m-d H:i:s");

// Basic validation
if (!$driver_id || !$latitude || !$longitude || $status === null) {
    http_response_code(400);
    // Use your custom printFailure function for consistency
    jsonError('Missing required fields');
    exit;
}

// Secure SQL using prepared statement
$sql = "INSERT INTO `car_locations` (
            `driver_id`, `latitude`, `longitude`, `heading`, `speed`, `distance`, `status`, `updated_at`
        ) VALUES (
            :driver_id, :latitude, :longitude, :heading, :speed, :distance, :status, :updated_at
        )
        ON DUPLICATE KEY UPDATE
            `latitude` = VALUES(`latitude`),
            `longitude` = VALUES(`longitude`),
            `heading` = VALUES(`heading`),
            `speed` = VALUES(`speed`),
            `distance` = VALUES(`distance`),
            `status` = VALUES(`status`),
            `updated_at` = VALUES(`updated_at`)";

try {
    $stmt = $con->prepare($sql);
    
    // The execute method returns true on success and false on failure.
    $success = $stmt->execute([
        ':latitude'   => $latitude,
        ':longitude'  => $longitude,
        ':heading'    => $heading,
        ':speed'      => $speed,
        ':distance'   => $distance,
        ':status'     => $status,
        ':updated_at' => $updated_at,
        ':driver_id'  => $driver_id
    ]);

    // The reliable way to check for success is if execute() returns true
    // and doesn't throw an exception. We no longer need rowCount().
    if ($success) {
        // Print a success message
        jsonSuccess(null, "Car location updated successfully");
    } else {
        // This case is rare but might happen if execute fails without an exception
        jsonError("Failed to update car location");
    }

} catch (PDOException $e) {
    // A real database error occurred.
    http_response_code(500);
    // You can log the detailed error for debugging
    // error_log('Database error: ' . $e->getMessage()); 
    jsonError('Database error occurred');
}
?>

File: ride/location/get.php

<?php
// get.php (Main Server)

// 1. تضمين ملف الاتصال والدوال المساعدة (مهم جداً)
require_once __DIR__ . '/../../connect.php'; 

// ضبط التوقيت (للسجلات فقط، قاعدة البيانات تبقى UTC)
// date_default_timezone_set('Asia/Amman');

try {
    // ==========================================
    // 1. استقبال الإحداثيات (دعم الطريقتين)
    // ==========================================
    $lat = filterRequest("lat");
    $lng = filterRequest("lng");

    // دعم Bounds القديم (تحويله لمركز وقطر)
    if (!$lat || !$lng) {
        $swLat = filterRequest("southwestLat"); $neLat = filterRequest("northeastLat");
        $swLon = filterRequest("southwestLon"); $neLon = filterRequest("northeastLon");

        if ($swLat && $neLat && $swLon && $neLon) {
            $lat = ($swLat + $neLat) / 2;
            $lng = ($swLon + $neLon) / 2;
        } else {
            jsonError("Invalid coordinates provided");
            exit;
        }
    }

    // ==========================================
    // 2. طلب الـ IDs والمواقع من سيرفر اللوكيشن (Redis API)
    // ==========================================
    $locationServerUrl = "https://location.intaleq.xyz/api_get_nearby.php";
    // تأكد من المسار الصحيح للمفتاح على السيرفر الرئيسي
    $INTERNAL_KEY = trim(file_get_contents('/home/siro-api/.internal_socket_key')); 

    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $locationServerUrl);
    curl_setopt($ch, CURLOPT_POST, 1);
    curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query([
        'lat' => $lat, 
        'lng' => $lng, 
        'radius' => 5, // 5 كم كافية للعرض
        'limit' => 50
    ]));
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_TIMEOUT, 3);
    curl_setopt($ch, CURLOPT_HTTPHEADER, ["x-internal-key: $INTERNAL_KEY"]);

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

    $redisDrivers = [];
    if ($httpCode == 200 && $response) {
        $json = json_decode($response, true);
        if (isset($json['status']) && $json['status'] === true) {
            $redisDrivers = $json['data'];
        }
    }

    if (empty($redisDrivers)) {
        jsonError("No drivers nearby");
        exit;
    }

    // تجهيز خريطة لدمج البيانات لاحقاً (ID => RedisData)
    $driversMap = [];
    $driverIds = [];
    foreach ($redisDrivers as $d) {
        $driverIds[] = $d['id'];
        $driversMap[$d['id']] = $d;
    }

    // ==========================================
    // 3. جلب التفاصيل الكاملة من MySQL (مثل الملف القديم تماماً)
    // ==========================================
    
    // تجهيز الـ Placeholders
    $placeholders = implode(',', array_fill(0, count($driverIds), '?'));

    // الاستعلام الشامل (نفس الحقول القديمة)
    $sql_drivers_info = "
        SELECT 
            d.id AS driver_id,
            d.phone, d.email, d.birthdate, d.first_name, d.last_name, d.gender, d.maritalStatus,
            cr.make, cr.car_plate, cr.model, cr.color, cr.vin, cr.color_hex, cr.year, cr.vehicle_category_id,
            dt.token,
            COALESCE(rdAvg.ratingDriver, 0) AS ratingDriver
        FROM driver d
        LEFT JOIN CarRegistration cr ON cr.driverID = d.id
        LEFT JOIN driverToken dt ON dt.captain_id = d.id
        LEFT JOIN (
            SELECT driver_id, AVG(rating) AS ratingDriver 
            FROM ratingDriver 
            GROUP BY driver_id
        ) rdAvg ON rdAvg.driver_id = d.id
        WHERE d.id IN ($placeholders)
          AND COALESCE(cr.year, 0) > 2000
          AND (cr.make NOT LIKE '%دراج%' AND cr.model NOT LIKE '%دراج%')
    ";

    $stmt = $con->prepare($sql_drivers_info);
    $stmt->execute($driverIds);
    $drivers_db = $stmt->fetchAll(PDO::FETCH_ASSOC);

    if (empty($drivers_db)) {
        jsonError("No matching drivers in DB");
        exit;
    }

    // ==========================================
    // 4. معالجة البيانات، الدمج، وفك التشفير
    // ==========================================
    
    $final_result = [];
    $serverNow = date('Y-m-d H:i:s');
    $fieldsToDecrypt = ['phone','email','gender','birthdate','first_name','last_name','token','car_plate','vin'];

    // الهاش الخاص بالإناث (لتحديد النوع لاحقاً إذا لزم الأمر)
    // $femaleHash = 'bQ6yWJ2EVXKZooHdGclvmFiDlZCM8UYeO+ILFjDUvpQ=';

    foreach ($drivers_db as $row) {
        $did = $row['driver_id'];

        // دمج بيانات الموقع الحية من الريدز (أهم خطوة)
        if (isset($driversMap[$did])) {
            $redisInfo = $driversMap[$did];
            $row['latitude']    = $redisInfo['lat'];
            $row['longitude']   = $redisInfo['lng'];
            $row['heading']     = $redisInfo['heading'];
            $row['speed']       = $redisInfo['speed'];
            // $row['distance'] = $redisInfo['distance']; // إذا أردت إضافتها
        } else {
            // حالة نادرة: السائق موجود في الاستعلام ولكن ليس في مصفوفة الريدز (لا يجب أن تحدث)
            continue; 
        }

        $row['serverNow'] = $serverNow;
        
        // فك التشفير (Decrypt)
        foreach ($fieldsToDecrypt as $field) {
            if (isset($row[$field]) && $row[$field] !== null && $row[$field] !== '') {
                try { 
                    $row[$field] = $encryptionHelper->decryptData($row[$field]); 
                } catch (Exception $e) { 
                    $row[$field] = null; 
                }
            }
        }

        // حساب العمر
        if (!empty($row['birthdate'])) {
            try {
                $birthdate  = new DateTime($row['birthdate']);
                $today      = new DateTime();
                $row['age'] = $today->diff($birthdate)->y;
            } catch (Exception $e) { $row['age'] = null; }
        } else {
            $row['age'] = null;
        }

        // إضافة نوع السيارة البسيط (اختياري، إذا كان التطبيق يعتمد عليه)
        /*
        $type = 'car';
        if ($row['vehicle_category_id'] == 2) $type = 'bike';
        elseif ($row['gender'] == 'female')   $type = 'lady'; // بعد فك التشفير تكون female
        $row['type'] = $type;
        */

        $final_result[] = $row;
    }

    // إرجاع النتيجة بنفس الهيكل القديم
    jsonSuccess($final_result);

} catch (PDOException $e) {
    jsonError("Database error: " . $e->getMessage());
} catch (Throwable $e) {
    jsonError("Internal error: " . $e->getMessage());
}
?>

File: ride/location/getPinkBike.php

<?php
require_once __DIR__ . '/../../connect.php';

try {
    $southwestLat = filterRequest("southwestLat");
    $southwestLon = filterRequest("southwestLon");
    $northeastLat = filterRequest("northeastLat");
    $northeastLon = filterRequest("northeastLon");

    if ($southwestLat === false || $southwestLon === false || $northeastLat === false || $northeastLon === false) {
        jsonError("Invalid coordinates provided");
        exit;
    }

    $sql = "
    SELECT
        cl.driver_id,
        cl.latitude,
        cl.longitude,
        cl.heading,
        cl.speed,
        cl.status,
        cl.created_at,
        cl.updated_at,
        d.phone,
        d.email,
        d.birthdate,
        d.first_name,
        d.last_name,
        d.gender,
        d.maritalStatus,
        cr.make,
        cr.car_plate,
        cr.model,
        cr.color,
        cr.vin,
        cr.color_hex,
        cr.year,
        dt.token,
        '' AS age,
        COALESCE(rdAvg.ratingDriver, 0) AS ratingDriver,
        rdAvg.ratingCount
    FROM
        car_locations cl
    LEFT JOIN driver d ON d.id = cl.driver_id
    LEFT JOIN CarRegistration cr ON cr.driverID = cl.driver_id
    LEFT JOIN driverToken dt ON dt.captain_id = cl.driver_id
    LEFT JOIN (
        SELECT driver_id, AVG(rating) AS ratingDriver, COUNT(id) AS ratingCount
        FROM ratingDriver
        GROUP BY driver_id
    ) rdAvg ON rdAvg.driver_id = cl.driver_id
    WHERE
        cl.latitude BETWEEN :southwestLat AND :northeastLat
        AND cl.longitude BETWEEN :southwestLon AND :northeastLon
        AND cl.status = 'off'
        AND cl.updated_at >= NOW() - INTERVAL 5 SECOND
        AND (cr.make LIKE '%دراجة%' OR cr.model LIKE '%دراجة%')
    GROUP BY cl.driver_id
    ORDER BY ratingDriver DESC, cl.updated_at DESC
    LIMIT 10;
    ";

    $stmt = $con->prepare($sql);
    $stmt->bindParam(':southwestLat', $southwestLat);
    $stmt->bindParam(':southwestLon', $southwestLon);
    $stmt->bindParam(':northeastLat', $northeastLat);
    $stmt->bindParam(':northeastLon', $northeastLon);
    $stmt->execute();

    $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);

    if ($rows) {
        $fieldsToDecrypt = [
            'phone', 'email', 'gender', 'birthdate',
            'first_name', 'last_name', 'maritalStatus', 'token',
            'make', 'car_plate', 'vin'
        ];

        $filteredRows = [];

        foreach ($rows as &$row) {
            foreach ($fieldsToDecrypt as $field) {
                if (isset($row[$field])) {
                    $row[$field] = $encryptionHelper->decryptData($row[$field]);
                }
            }

            // فلترة حسب الجنس
            if (strtolower($row['gender']) !== 'female') {
                continue;
            }

            // حساب العمر
            if (!empty($row['birthdate'])) {
                $birthDate = new DateTime($row['birthdate']);
                $today = new DateTime();
                $row['age'] = $today->diff($birthDate)->y;
            } else {
                $row['age'] = null;
            }

            $filteredRows[] = $row;
        }

        jsonSuccess($filteredRows);
    } else {
        jsonError("No car locations found");
    }
} catch (PDOException $e) {
    jsonError("Database error: " . $e->getMessage());
}

File: ride/location/get_location_area_links.php

<?php
require_once __DIR__ . '/../../connect.php';


// Use prepared statement to prevent SQL injection
$sql = "
SELECT * FROM `server_locations`
";

try {
    $stmt = $con->prepare($sql);
   
    $stmt->execute();
    
    $car_locations = $stmt->fetchAll(PDO::FETCH_ASSOC);
    
    if ($car_locations) {
        jsonSuccess($car_locations);
    } else {
        jsonError("No car locations found");
    }
} catch (PDOException $e) {
    jsonError("Database error: " . $e->getMessage());
}

File: ride/location/getLocationParents.php

<?php
// تأكد من أن ملف connect.php يقوم بتهيئة اتصالين:
// $con          -> يتصل بقاعدة البيانات الأساسية (driver, CarRegistration)
// $con_tracking -> يتصل بقاعدة بيانات التتبع (car_locations)
require_once __DIR__ . '/../../connect.php';

try {
    $driver_id = filterRequest("driver_id");

    if ($driver_id === false || empty($driver_id)) {
        jsonError("Invalid driver_id provided");
        exit;
    }

    // =================================================================
    // الخطوة 1: جلب آخر موقع للسائق من قاعدة بيانات التتبع
    // =================================================================
    // هذا الاستعلام يعمل على قاعدة بيانات التتبع السريعة
    // (ملاحظة: تم التغيير إلى ORDER BY updated_at لجلب آخر تحديث)
    $sql_location = "SELECT
                        id, 
                        driver_id, 
                        latitude, 
                        longitude, 
                        heading, 
                        speed, 
                        status, 
                        created_at, 
                        updated_at
                    FROM
                        car_locations
                    WHERE
                        driver_id = ?
                    ORDER BY
                        updated_at DESC
                    LIMIT 1";

    $stmt_location = $con_tracking->prepare($sql_location);
    $stmt_location->execute([$driver_id]);
    $location_data = $stmt_location->fetch(PDO::FETCH_ASSOC);

    // إذا لم نجد أي موقع، لا داعي لإكمال البحث
    if (empty($location_data)) {
        jsonError("No car locations found");
        exit;
    }

    // =================================================================
    // الخطوة 2: جلب البيانات الثابتة للسائق من القاعدة الأساسية
    // =================================================================
    // هذا الاستعلام يعمل على قاعدة البيانات الأساسية الهادئة
    // (ملاحظة: تم إصلاح الخطأ في جملة JOIN)
    $sql_driver_info = "SELECT
                            d.gender,
                            cr.model
                        FROM
                            driver d
                        LEFT JOIN CarRegistration cr ON d.id = cr.driverID
                        WHERE
                            d.id = ?";
    
    $stmt_driver_info = $con->prepare($sql_driver_info);
    $stmt_driver_info->execute([$driver_id]);
    $driver_info = $stmt_driver_info->fetch(PDO::FETCH_ASSOC);

    // =================================================================
    // الخطوة 3: دمج النتائج (Application-Side Join)
    // =================================================================
    
    // دمج بيانات الموقع مع بيانات السائق
    if (empty($driver_info)) {
        $driver_info = []; // اجعله مصفوفة فارغة لتجنب خطأ في الدمج
    }

    $final_result = array_merge($location_data, $driver_info);
    
    // السكربت الأصلي كان يستخدم fetchAll، لذا كان يرجع مصفوفة بداخلها عنصر واحد
    // [ [ ... بيانات ... ] ]
    // سنحافظ على نفس البنية لإرجاع البيانات
    jsonSuccess([$final_result]);


} catch (PDOException $e) {
    jsonError("Database error: " . $e->getMessage());
} catch (Throwable $e) {
    jsonError("Internal error: " . $e->getMessage());
}
?>

File: ride/location/getUpdatedLocationForAdmin.php

<?php
// =================================================================
// ملف: getUpdatedLocationForAdmin.php
// =================================================================

require_once __DIR__ . '/../../get_connect.php';

header("Access-Control-Allow-Origin: *");
header("Content-Type: application/json; charset=UTF-8");

// تفعيل إظهار الأخطاء لمعرفة مشكلة الكتابة
error_reporting(E_ALL);
ini_set('display_errors', 1);

try {
    $mode = isset($_GET['mode']) && $_GET['mode'] == 'day' ? 'day' : 'live';

    if ($mode == 'day') {
        $fileName = 'locations_day.json';
        $timeCondition = "DATE(created_at) = CURDATE()"; 
    } else {
        $fileName = 'locations_live.json';
        $freshSeconds = 1200; 
        $timeCondition = "created_at >= NOW() - INTERVAL $freshSeconds SECOND";
    }

    // تحديد المسار الكامل بدقة
    $savePath = __DIR__ . '/' . $fileName;

    // === فحص صلاحيات الكتابة ===
    if (!is_writable(__DIR__)) {
        // إذا لم تكن هناك صلاحية، سنطبع الخطأ ونوقف التنفيذ
        echo json_encode([
            "status" => "error", 
            "message" => "Permission Denied: Cannot write to directory. Please chmod 777 this folder.",
            "path" => __DIR__
        ]);
        exit;
    }

    // 1. جلب المواقع
    $sql_locations = "
    SELECT t.driver_id,
           t.latitude AS lat,
           t.longitude AS lon,
           t.heading,
           t.speed,
           t.created_at
    FROM car_tracks t
    INNER JOIN (
        SELECT driver_id, MAX(id) AS max_id
        FROM car_tracks
        WHERE $timeCondition
        GROUP BY driver_id
    ) latest
      ON t.id = latest.max_id
    ORDER BY t.created_at DESC
";
  	$stmt = $con_tracking->prepare($sql_locations);
    $stmt->execute();
    $locations = $stmt->fetchAll(PDO::FETCH_ASSOC);

    // 2. جلب بيانات السائقين
    $driver_ids = array_unique(array_column($locations, 'driver_id'));
    $drivers_info = [];

    if (!empty($driver_ids)) {
        $placeholders = implode(',', array_fill(0, count($driver_ids), '?'));
        $sql_drivers = "SELECT id, first_name, last_name, phone, 
                        (SELECT COUNT(*) FROM ride WHERE driver_id = driver.id AND status = 'Completed') as completed,
                        (SELECT COUNT(*) FROM ride WHERE driver_id = driver.id AND status = 'CancelFromDriverAfterApply') as cancelled
                        FROM driver WHERE id IN ($placeholders)";
        $stmt_drivers = $con->prepare($sql_drivers);
        $stmt_drivers->execute(array_values($driver_ids));
        foreach ($stmt_drivers->fetchAll(PDO::FETCH_ASSOC) as $row) {
            $drivers_info[$row['id']] = $row;
        }
    }

    // 3. الدمج
    $final_drivers = [];
    foreach ($locations as $loc) {
        $d_id = $loc['driver_id'];
        $merged = [
            'id' => $d_id,
            'lat' => $loc['lat'],
            'lon' => $loc['lon'],
            'heading' => $loc['heading'],
            'speed' => $loc['speed'],
            'name' => 'Unknown',
            'phone' => '',
            'completed' => 0,
            'cancelled' => 0
        ];

        if (isset($drivers_info[$d_id])) {
            $info = $drivers_info[$d_id];
            // فك التشفير البسيط (تأكد من عمل encryptionHelper)
            if (isset($encryptionHelper)) {
                try { $info['first_name'] = $encryptionHelper->decryptData($info['first_name']); } catch(Exception $e){}
                try { $info['last_name'] = $encryptionHelper->decryptData($info['last_name']); } catch(Exception $e){}
                try { $info['phone'] = $encryptionHelper->decryptData($info['phone']); } catch(Exception $e){}
            }
            
            $merged['name'] = trim(($info['first_name']??'') . ' ' . ($info['last_name']??''));
            $merged['phone'] = $info['phone'] ?? '';
            $merged['completed'] = $info['completed'] ?? 0;
            $merged['cancelled'] = $info['cancelled'] ?? 0;
        }
        $final_drivers[] = $merged;
    }

    // 4. الحفظ
    $jsonContent = json_encode(['drivers' => $final_drivers, 'last_updated' => date('Y-m-d H:i:s')], JSON_UNESCAPED_UNICODE);
    
    // محاولة الحفظ
    if (file_put_contents($savePath, $jsonContent) !== false) {
        echo json_encode(["status" => "success", "message" => "File written successfully to $savePath"]);
    } else {
        echo json_encode(["status" => "error", "message" => "Failed to write file. Check permissions."]);
    }

} catch (Exception $e) {
    echo json_encode(["status" => "error", "message" => $e->getMessage()]);
}
?>

File: ride/location/save_behavior.php

<?php
// تأكد من أن ملف connect.php يقوم بتهيئة اتصالين:
// $con          -> يتصل بقاعدة البيانات الأساسية
// $con_tracking -> يتصل بقاعدة بيانات التتبع (driver_behavior, car_locations)
require_once __DIR__ . '/../../connect.php';

try {
    // استلام البيانات من Flutter
    $driver_id = filterRequest("driver_id");
    $trip_id = filterRequest("trip_id");
    $max_speed = filterRequest("max_speed");
    $avg_speed = filterRequest("avg_speed");
    $hard_brakes = filterRequest("hard_brakes");
    $total_distance = filterRequest("total_distance");
    $behavior_score = filterRequest("behavior_score");

    // تحقق من القيم الأساسية
    if (empty($driver_id) || empty($trip_id)) {
        jsonError("Missing driver_id or trip_id");
        exit();
    }

    // إدخال البيانات في جدول driver_behavior باستخدام اتصال التتبع
    // تم تغيير $con إلى $con_tracking
    $stmt = $con_tracking->prepare("
        INSERT INTO driver_behavior (
            driver_id, trip_id, max_speed, avg_speed,
            hard_brakes, total_distance, behavior_score
        ) VALUES (?, ?, ?, ?, ?, ?, ?)
    ");

    $stmt->execute([
        $driver_id,
        $trip_id,
        $max_speed,
        $avg_speed,
        $hard_brakes,
        $total_distance,
        $behavior_score
    ]);

    // التحقق من نجاح العملية
    if ($stmt->rowCount() > 0) {
        jsonSuccess(null, "Behavior data saved");
    } else {
        // في حالة عدم حدوث خطأ، ولكن لم يتم إدخال صف (قد يحدث)، 
        // من الأفضل إرجاع رسالة فشل عامة.
        jsonError("Failed to save data (No rows affected)");
    }

} catch (PDOException $e) {
    jsonError("Database error: " . $e->getMessage());
} catch (Throwable $e) {
    jsonError("Internal error: " . $e->getMessage());
}

// تم حذف exit() من هنا ليتم التعامل معها داخل try/catch
?>

File: ride/location/getDriverCarsLocationToPassengerAfterApplied.php

<?php
// تأكد من أن ملف connect.php يقوم بتهيئة اتصالين:
// $con          -> يتصل بقاعدة البيانات الأساسية (driver, CarRegistration)
// $con_tracking -> يتصل بقاعدة بيانات التتبع (car_locations)
// وأنه يحتوي على كائن التشفير $encryptionHelper
require_once __DIR__ . '/../../connect.php';

try {
    $driver_id = filterRequest("driver_id");

    if ($driver_id === false || empty($driver_id)) {
        jsonError("Invalid driver_id provided");
        exit;
    }

    // =================================================================
    // الخطوة 1: جلب آخر موقع للسائق من قاعدة بيانات التتبع
    // =================================================================
    $sql_location = "SELECT
                        driver_id, 
                        latitude, 
                        longitude, 
                        heading, 
                        speed, 
                        status, 
                        created_at, 
                        updated_at
                    FROM
                        car_locations
                    WHERE
                        driver_id = ?
                    ORDER BY
                        updated_at DESC
                    LIMIT 1";

    $stmt_location = $con_tracking->prepare($sql_location);
    $stmt_location->execute([$driver_id]);
    $location_data = $stmt_location->fetch(PDO::FETCH_ASSOC);

    // إذا لم نجد أي موقع، لا داعي لإكمال البحث
    if (empty($location_data)) {
        jsonError("No car locations found");
        exit;
    }

    // =================================================================
    // الخطوة 2: جلب البيانات الثابتة للسائق من القاعدة الأساسية
    // =================================================================
    $sql_driver_info = "SELECT
                            d.gender,
                            cr.model
                        FROM
                            driver d
                        LEFT JOIN CarRegistration cr ON d.id = cr.driverID
                        WHERE
                            d.id = ?";
    
    $stmt_driver_info = $con->prepare($sql_driver_info);
    $stmt_driver_info->execute([$driver_id]);
    // نستخدم fetch وليس fetchAll لأننا نتوقع سائق واحد فقط
    $driver_info = $stmt_driver_info->fetch(PDO::FETCH_ASSOC);

    // =================================================================
    // الخطوة 2.5: فك تشفير الجندر (New Step)
    // =================================================================
    if (!empty($driver_info)) {
        // التحقق من وجود قيمة في حقل الجندر قبل فك تشفيرها
        if (isset($driver_info['gender']) && !empty($driver_info['gender'])) {
            $driver_info['gender'] = $encryptionHelper->decryptData($driver_info['gender']);
        }
    } else {
        $driver_info = []; // اجعله مصفوفة فارغة لتجنب خطأ في الدمج
    }

    // =================================================================
    // الخطوة 3: دمج النتائج (Application-Side Join)
    // =================================================================
    
    // دمج بيانات الموقع مع بيانات السائق (التي تم فك تشفيرها الآن)
    $final_result = array_merge($location_data, $driver_info);
    
    // إرجاع النتيجة داخل مصفوفة كما في السكربت الأصلي
    jsonSuccess([$final_result]);


} catch (PDOException $e) {
    jsonError("Database error: " . $e->getMessage());
} catch (Throwable $e) {
    jsonError("Internal error: " . $e->getMessage());
}
?>

File: ride/location/print.php

<?php
// ============================================================
// 1. DATA FETCHING (Dynamic from Server File)
// ============================================================

$source_file = 'active_drivers_cache.json';

// Check if file exists to avoid errors
if (!file_exists($source_file)) {
    die('<div style="font-family:sans-serif; text-align:center; padding:50px; color:#dc2626;">
            <h1>⚠️ Error: Data File Not Found</h1>
            <p>Please ensure <strong>'.$source_file.'</strong> exists in the same directory.</p>
         </div>');
}

// Get content
$json_data = file_get_contents($source_file);
$data = json_decode($json_data, true);

if (!$data) {
    die('Error decoding JSON data.');
}

$drivers = $data['data'];
$last_updated = $data['last_updated'] ?? date('Y-m-d H:i:s');

// ============================================================
// 2. DATA PROCESSING (Logic Layer)
// ============================================================

$processed_drivers = [];
$stats = [
    'total' => 0,
    'elite' => 0,     // +50 hours
    'stable' => 0,    // +20 hours
    'experimental' => 0, // +5 hours
    'inactive' => 0
];

foreach ($drivers as $driver) {
    // Parse Active Time String (e.g., "293 ساعة و 48 دقيقة")
    $timeStr = $driver['active_time'] ?? "0 ساعة و 0 دقيقة";
    preg_match('/(\d+)\s*ساعة/', $timeStr, $hoursMatch);
    preg_match('/(\d+)\s*دقيقة/', $timeStr, $minsMatch);
    
    $hours = isset($hoursMatch[1]) ? (int)$hoursMatch[1] : 0;
    $mins = isset($minsMatch[1]) ? (int)$minsMatch[1] : 0;
    $totalMinutes = ($hours * 60) + $mins;

    // Categorize Driver
    $category = 'inactive';
    $catLabel = 'خامل';
    $catClass = 'cat-inactive';

    if ($totalMinutes >= 3000) { // 50 hours
        $category = 'elite';
        $catLabel = 'نخبة';
        $catClass = 'cat-elite';
        $stats['elite']++;
    } elseif ($totalMinutes >= 1200) { // 20 hours
        $category = 'stable';
        $catLabel = 'مستقر';
        $catClass = 'cat-stable';
        $stats['stable']++;
    } elseif ($totalMinutes >= 300) { // 5 hours
        $category = 'experimental';
        $catLabel = 'تجريبي';
        $catClass = 'cat-experimental';
        $stats['experimental']++;
    } else {
        $stats['inactive']++;
    }

    $driver['total_minutes'] = $totalMinutes;
    $driver['category_label'] = $catLabel;
    $driver['category_class'] = $catClass;
    $processed_drivers[] = $driver;
}

$stats['total'] = count($processed_drivers);

// Sort by Active Time (High to Low)
usort($processed_drivers, function($a, $b) {
    return $b['total_minutes'] <=> $a['total_minutes'];
});

?>

<!DOCTYPE html>
<html lang="ar" dir="rtl">
<head>
    <meta charset="UTF-8">
    <title>تقرير السائقين - Siro</title>
    <link href="https://fonts.googleapis.com/css2?family=Tajawal:wght@400;500;700;800&display=swap" rel="stylesheet">
    <style>
        :root {
            --color-elite: #d97706;
            --color-stable: #059669;
            --color-exp: #2563eb;
            --color-inactive: #dc2626;
        }
        body {
            font-family: 'Tajawal', sans-serif;
            background: #e5e7eb; /* Grey bg for screen */
            margin: 0;
            padding: 20px;
            color: #1f2937;
        }
        .page {
            background: white;
            max-width: 210mm; /* A4 Width */
            margin: 0 auto;
            padding: 20px 40px;
            box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
            min-height: 297mm;
        }
        
        /* Header */
        .header {
            display: flex;
            justify-content: space-between;
            align-items: center;
            border-bottom: 2px solid #1f2937;
            padding-bottom: 20px;
            margin-bottom: 20px;
        }
        .header h1 { margin: 0; font-size: 24px; }
        .meta { font-size: 12px; color: #6b7280; }

        /* Stats Grid */
        .stats-grid {
            display: grid;
            grid-template-columns: repeat(4, 1fr);
            gap: 15px;
            margin-bottom: 30px;
        }
        .stat-box {
            border: 1px solid #e5e7eb;
            border-radius: 8px;
            padding: 15px;
            text-align: center;
        }
        .stat-value { font-size: 24px; font-weight: 800; display: block; }
        .stat-label { font-size: 12px; color: #6b7280; font-weight: bold; }

        /* Table */
        table { width: 100%; border-collapse: collapse; font-size: 12px; }
        th, td { border-bottom: 1px solid #e5e7eb; padding: 10px; text-align: right; }
        th { background-color: #f9fafb; font-weight: 800; color: #374151; border-top: 2px solid #374151; }
        tr:nth-child(even) { background-color: #fdfdfd; }
        
        /* Categories */
        .badge { padding: 2px 8px; border-radius: 4px; font-weight: bold; font-size: 10px; border: 1px solid; }
        .cat-elite { background: #fef3c7; color: var(--color-elite); border-color: #fcd34d; }
        .cat-stable { background: #d1fae5; color: var(--color-stable); border-color: #6ee7b7; }
        .cat-experimental { background: #dbeafe; color: var(--color-exp); border-color: #93c5fd; }
        .cat-inactive { background: #fee2e2; color: var(--color-inactive); border-color: #fca5a5; }

        /* Notes Column */
        .notes-col { width: 150px; border-left: 1px dashed #d1d5db; }

        /* Print Rules */
        @media print {
            body { background: white; padding: 0; }
            .page { box-shadow: none; max-width: 100%; padding: 0; margin: 0; }
            .no-print { display: none; }
            th { background-color: #f3f4f6 !important; -webkit-print-color-adjust: exact; }
            .badge { -webkit-print-color-adjust: exact; }
            tr { page-break-inside: avoid; }
        }
    </style>
</head>
<body>

    <div class="no-print" style="text-align: center; margin-bottom: 20px;">
        <button onclick="window.print()" style="padding: 10px 20px; background: #2563eb; color: white; border: none; border-radius: 5px; cursor: pointer; font-family: inherit; font-weight: bold; box-shadow: 0 2px 4px rgba(0,0,0,0.1);">
            🖨️ طباعة التقرير (PDF)
        </button>
        <button onclick="location.reload()" style="padding: 10px 20px; background: #4b5563; color: white; border: none; border-radius: 5px; cursor: pointer; font-family: inherit; margin-right: 10px;">
            🔄 تحديث البيانات
        </button>
    </div>

    <div class="page">
        <div class="header">
            <div>
                <h1>تقرير أداء السائقين</h1>
                <div class="meta">تاريخ الطباعة: <?php echo date('Y-m-d H:i'); ?></div>
            </div>
            <div style="text-align: left">
                <h2 style="margin:0; color: #2563eb;">Siro</h2>
                <div class="meta dir-ltr"><?php echo $last_updated; ?> :آخر تحديث بيانات</div>
            </div>
        </div>

        <div class="stats-grid">
            <div class="stat-box" style="border-bottom: 3px solid #374151;">
                <span class="stat-label">إجمالي السائقين</span>
                <span class="stat-value" style="color: #374151"><?php echo $stats['total']; ?></span>
            </div>
            <div class="stat-box" style="border-bottom: 3px solid var(--color-elite);">
                <span class="stat-label">النخبة (+50 ساعة)</span>
                <span class="stat-value" style="color: var(--color-elite)"><?php echo $stats['elite']; ?></span>
            </div>
            <div class="stat-box" style="border-bottom: 3px solid var(--color-stable);">
                <span class="stat-label">مستقرون (+20 ساعة)</span>
                <span class="stat-value" style="color: var(--color-stable)"><?php echo $stats['stable']; ?></span>
            </div>
            <div class="stat-box" style="border-bottom: 3px solid var(--color-inactive);">
                <span class="stat-label">يحتاجون متابعة</span>
                <span class="stat-value" style="color: var(--color-inactive)"><?php echo $stats['inactive']; ?></span>
            </div>
        </div>

        <table>
            <thead>
                <tr>
                    <th style="width: 5%">#</th>
                    <th style="width: 25%">اسم السائق</th>
                    <th style="width: 15%">رقم الهاتف</th>
                    <th style="width: 20%">ساعات النشاط</th>
                    <th style="width: 10%">الحالة</th>
                    <th style="width: 10%">تاريخ الانضمام</th>
                    <th class="notes-col">ملاحظات إدارية</th>
                </tr>
            </thead>
            <tbody>
                <?php $i = 1; foreach ($processed_drivers as $driver): ?>
                <tr>
                    <td><?php echo $i++; ?></td>
                    <td>
                        <strong><?php echo $driver['name_arabic'] ?? '---'; ?></strong>
                    </td>
                    <td style="direction: ltr; text-align: right; font-family: monospace;">
                        <?php echo $driver['phone']; ?>
                    </td>
                    <td>
                        <?php echo $driver['active_time']; ?>
                    </td>
                    <td>
                        <span class="badge <?php echo $driver['category_class']; ?>">
                            <?php echo $driver['category_label']; ?>
                        </span>
                    </td>
                    <td><?php echo isset($driver['created_at']) ? date('Y-m-d', strtotime($driver['created_at'])) : '-'; ?></td>
                    <td class="notes-col"></td>
                </tr>
                <?php endforeach; ?>
            </tbody>
        </table>
    </div>

</body>
</html>

File: ride/location/getTotalDriverDurationToday.php

<?php
require_once __DIR__ . '/../../connect.php';

$driver_id = filterRequest("driver_id");

// Get the current date.
$current_date = date('Y-m-d');

// Create a SQL query to select the total duration for the driver today.
$sql = "SELECT
  SEC_TO_TIME(COUNT(*) * 60) AS total_duration
FROM
  car_tracks
WHERE
  car_tracks.driver_id = '$driver_id'
  AND car_tracks.created_at >= '$current_date'
  AND car_tracks.created_at < DATE_ADD('$current_date', INTERVAL 1 DAY);";

$stmt = $con->prepare($sql);
$stmt->execute();
$car_locations = $stmt->fetchAll(PDO::FETCH_ASSOC);

if ($car_locations) {
  // Print the car location data as JSON
  jsonSuccess($car_locations);
} else {
  // Print a failure message
  jsonError($message = "No car locations found");
}

?>

File: ride/location/getCarsLocationByPassengerVan.php

<?php
require_once __DIR__ . '/../../connect.php'; // يفترض أن هذا الملف ينشئ $con و $con_tracking

try {
    // 1) قراءة والتحقق من الإحداثيات
    $southwestLat = filterRequest("southwestLat");
    $southwestLon = filterRequest("southwestLon");
    $northeastLat = filterRequest("northeastLat");
    $northeastLon = filterRequest("northeastLon");

    if ($southwestLat === false || $southwestLon === false || $northeastLat === false || $northeastLon === false) {
        jsonError("Invalid coordinates provided");
        exit;
    }

    $freshSeconds = 180; // 3 دقائق

    // =================================================================
    // الخطوة 1: جلب المواقع والمعرفات من قاعدة بيانات التتبع
    // =================================================================

    // استخدام التحسين الجغرافي ST_CONTAINS لأنه أسرع بمراحل
    $boundingBoxWKT = sprintf(
        'POLYGON((%f %f, %f %f, %f %f, %f %f, %f %f))',
        $southwestLon, $southwestLat,
        $northeastLon, $southwestLat,
        $northeastLon, $northeastLat,
        $southwestLon, $northeastLat,
        $southwestLon, $southwestLat
    );

    // جلب مجموعة من المرشحين المحتملين للفلترة والترتيب لاحقاً
    $sql_locations = "
        SELECT driver_id, latitude, longitude, heading, speed, status, updated_at
        FROM car_locations
        WHERE
            ST_CONTAINS(ST_GeomFromText(:boundingBox, 4326), location_point)
            AND status = 'off'
            AND updated_at >= NOW() - INTERVAL :freshSeconds SECOND
        ORDER BY updated_at DESC
        LIMIT 100; -- نجلب 100 مرشح محتمل
    ";

    $stmt_locations = $con_tracking->prepare($sql_locations);
    $stmt_locations->bindValue(':boundingBox', $boundingBoxWKT);
    $stmt_locations->bindValue(':freshSeconds', $freshSeconds, PDO::PARAM_INT);
    $stmt_locations->execute();
    $locations = $stmt_locations->fetchAll(PDO::FETCH_ASSOC);

    if (!$locations) {
        jsonError("No car locations found in the specified area.");
        exit;
    }

    // =================================================================
    // الخطوة 2: تجميع معرفات السائقين (driver_id)
    // =================================================================
    $driver_ids = array_column($locations, 'driver_id');

    // =================================================================
    // الخطوة 3: جلب البيانات الثابتة من القاعدة الأساسية وتطبيق الفلاتر الإضافية
    // =================================================================
    $drivers_info = [];
    if (!empty($driver_ids)) {
        $placeholders = implode(',', array_fill(0, count($driver_ids), '?'));

        // هنا نطبق الشروط الخاصة بهذا السكريبت (سيارات كهربائية فقط)
        $sql_drivers_info = "
            SELECT
                d.id AS driver_id, d.phone, d.email, d.birthdate, d.first_name, d.last_name,
                cr.make, cr.model, cr.color, cr.color_hex, cr.year, cr.fuel,
                dt.token,
                COALESCE(rdAvg.ratingDriver, 0) AS ratingDriver,
                COALESCE(rdAvg.ratingCount, 0) AS ratingCount
            FROM driver d
            LEFT JOIN CarRegistration cr ON cr.driverID = d.id
            LEFT JOIN driverToken dt ON dt.captain_id = d.id
            LEFT JOIN (
                SELECT driver_id, AVG(rating) AS ratingDriver, COUNT(*) AS ratingCount
                FROM ratingDriver
                GROUP BY driver_id
            ) rdAvg ON rdAvg.driver_id = d.id
            WHERE d.id IN ($placeholders)
              AND cr.make = 'Van'or cr.model='Van' 
          
        ";

        $stmt_drivers_info = $con->prepare($sql_drivers_info);
        $stmt_drivers_info->execute($driver_ids);
        $drivers_info_raw = $stmt_drivers_info->fetchAll(PDO::FETCH_ASSOC);

        // تحويل المصفوفة لتسهيل عملية الدمج لاحقاً
        foreach ($drivers_info_raw as $driver) {
            $drivers_info[$driver['driver_id']] = $driver;
        }
    }

    // =================================================================
    // الخطوة 4: دمج النتائج في PHP
    // =================================================================
    $final_results = [];
    foreach ($locations as $location) {
        $driver_id = $location['driver_id'];
        // ندمج فقط السائقين الذين طابقوا شروطنا في الاستعلام الثاني
        if (isset($drivers_info[$driver_id])) {
            $final_results[] = array_merge($location, $drivers_info[$driver_id]);
        }
    }

    // =================================================================
    // الخطوة 5: تطبيق الترتيب والحد النهائي في PHP
    // =================================================================
    usort($final_results, function ($a, $b) {
        if ($a['ratingDriver'] != $b['ratingDriver']) {
            return $b['ratingDriver'] <=> $a['ratingDriver'];
        }
        if ($a['ratingCount'] != $b['ratingCount']) {
            return $b['ratingCount'] <=> $a['ratingCount'];
        }
        return strtotime($b['updated_at']) <=> strtotime($a['updated_at']);
    });

    // وأخيراً، نأخذ أفضل 10 نتائج فقط
    $limited_results = array_slice($final_results, 0, 10);

    if (empty($limited_results)) {
        jsonError("No electric cars matching the criteria found.");
        exit;
    }

    // =================================================================
    // الخطوة 6: فك التشفير وحساب العمر (بدون تغيير)
    // =================================================================
    $fieldsToDecrypt = [ 'phone','email','gender','birthdate', 'first_name','last_name', 'token','car_plate','vin' ];
    foreach ($limited_results as &$row) {
        foreach ($fieldsToDecrypt as $field) {
            if (isset($row[$field]) && !empty($row[$field])) {
                try { $row[$field] = $encryptionHelper->decryptData($row[$field]); }
                catch (Exception $e) { $row[$field] = null; }
            }
        }
        if (!empty($row['birthdate'])) {
            try {
                $birthDate = new DateTime($row['birthdate']);
                $today = new DateTime();
                $row['age'] = $today->diff($birthDate)->y;
            } catch (Exception $e) { $row['age'] = null; }
        } else {
            $row['age'] = null;
        }
    }
    unset($row);

    jsonSuccess($limited_results);

} catch (PDOException $e) {
    jsonError("Database error: " . $e->getMessage());
} catch (Throwable $e) {
    jsonError("Internal error: " . $e->getMessage());
}

File: ride/location/getTotalDriverDuration.php

<?php
require_once __DIR__ . '/../../connect.php';

$driver_id = filterRequest("driver_id");

$current_month = date('m');
$current_year = date('Y');

// Get the first and last days of the current month.
$first_day_of_month = date('Y-m-d', strtotime($current_year . '-' . $current_month . '-01'));
$last_day_of_month = date('Y-m-d', strtotime($current_year . '-' . $current_month . '-' . cal_days_in_month(CAL_GREGORIAN, $current_month, $current_year)));

// Create a SQL query to select the total duration for the driver for each day in the current month.
$sql = "SELECT
  DATE(created_at) AS day,
  SEC_TO_TIME(COUNT(*) * 60) AS total_duration
FROM
  car_tracks
WHERE
  car_tracks.driver_id = :driver_id
  AND car_tracks.created_at >= :first_day_of_month
  AND car_tracks.created_at < :last_day_of_month
GROUP BY
  day
ORDER BY
  day ASC;";

$stmt = $con->prepare($sql);
$stmt->bindParam(':driver_id', $driver_id, PDO::PARAM_STR);
$stmt->bindParam(':first_day_of_month', $first_day_of_month, PDO::PARAM_STR);
$stmt->bindParam(':last_day_of_month', $last_day_of_month, PDO::PARAM_STR);
$stmt->execute();

$car_locations = $stmt->fetchAll(PDO::FETCH_ASSOC);

if ($car_locations) {
  // Print the car location data as JSON
  jsonSuccess($data = $car_locations);
} else {
  // Print a failure message
  jsonError($message = "No car locations found");
}

?>

File: ride/location/getComfort.php

<?php
require_once __DIR__ . '/../../connect.php'; // يفترض أن هذا الملف ينشئ $con و $con_tracking
//getComfort.php
try {
    // 1) قراءة والتحقق من الإحداثيات
    $southwestLat = filterRequest("southwestLat");
    $southwestLon = filterRequest("southwestLon");
    $northeastLat = filterRequest("northeastLat");
    $northeastLon = filterRequest("northeastLon");

    if ($southwestLat === false || $southwestLon === false || $northeastLat === false || $northeastLon === false) {
        jsonError("Invalid coordinates provided");
        exit;
    }

    $freshSeconds = 180; // 3 دقائق

    // =================================================================
    // الخطوة 1: جلب المواقع والمعرفات من قاعدة بيانات التتبع
    // =================================================================

    // استخدام التحسين الجغرافي ST_CONTAINS لأنه أسرع بمراحل
    $boundingBoxWKT = sprintf(
        'POLYGON((%f %f, %f %f, %f %f, %f %f, %f %f))',
        $southwestLon, $southwestLat,
        $northeastLon, $southwestLat,
        $northeastLon, $northeastLat,
        $southwestLon, $northeastLat,
        $southwestLon, $southwestLat
    );

    // جلب مجموعة من المرشحين المحتملين للفلترة والترتيب لاحقاً
    $sql_locations = "
        SELECT driver_id, latitude, longitude, heading, speed, status, updated_at
        FROM car_locations
        WHERE
            ST_CONTAINS(ST_GeomFromText(:boundingBox, 4326), location_point)
            AND status = 'off'
            AND updated_at >= NOW() - INTERVAL :freshSeconds SECOND
        ORDER BY updated_at DESC
        LIMIT 100; -- نجلب 100 مرشح محتمل
    ";

    $stmt_locations = $con_tracking->prepare($sql_locations);
    $stmt_locations->bindValue(':boundingBox', $boundingBoxWKT);
    $stmt_locations->bindValue(':freshSeconds', $freshSeconds, PDO::PARAM_INT);
    $stmt_locations->execute();
    $locations = $stmt_locations->fetchAll(PDO::FETCH_ASSOC);

    if (!$locations) {
        jsonError("No car locations found in the specified area.");
        exit;
    }

    // =================================================================
    // الخطوة 2: تجميع معرفات السائقين (driver_id)
    // =================================================================
    $driver_ids = array_column($locations, 'driver_id');

    // =================================================================
    // الخطوة 3: جلب البيانات الثابتة من القاعدة الأساسية وتطبيق الفلاتر الإضافية
    // =================================================================
    $drivers_info = [];
    if (!empty($driver_ids)) {
        $placeholders = implode(',', array_fill(0, count($driver_ids), '?'));

        // هنا نطبق الشروط الخاصة بهذا السكريبت (موديل السيارة > 2017)
        $sql_drivers_info = "
            SELECT 
                d.id AS driver_id, d.phone, d.email, d.birthdate, d.first_name, d.last_name, 
                cr.make, cr.model, cr.color, cr.color_hex, cr.year, 
                dt.token,
                COALESCE(rdAvg.ratingDriver, 0) AS ratingDriver,
                COALESCE(rdAvg.ratingCount, 0) AS ratingCount
            FROM driver d
            -- 1. تغيير LEFT JOIN إلى INNER JOIN لضمان عدم جلب سائق إلا إذا كانت بيانات سيارته مطابقة تماماً
            INNER JOIN CarRegistration cr ON cr.driverID = d.id 
            LEFT JOIN driverToken dt ON dt.captain_id = d.id
            LEFT JOIN (
                SELECT driver_id, AVG(rating) AS ratingDriver, COUNT(*) AS ratingCount
                FROM ratingDriver
                GROUP BY driver_id
            ) rdAvg ON rdAvg.driver_id = d.id
            WHERE d.id IN ($placeholders)
              -- 2. الفلترة الصارمة للسنة
              AND cr.year IS NOT NULL 
              AND TRIM(cr.year) != ''
              AND CAST(TRIM(cr.year) AS UNSIGNED) > 2017
              

              AND (cr.make NOT LIKE '%دراج%' AND cr.model NOT LIKE '%دراج%')
              AND (cr.model NOT LIKE '%Van%' AND cr.make NOT LIKE '%Van%')
        ";
        $stmt_drivers_info = $con->prepare($sql_drivers_info);
        $stmt_drivers_info->execute($driver_ids);
        $drivers_info_raw = $stmt_drivers_info->fetchAll(PDO::FETCH_ASSOC);

        // تحويل المصفوفة لتسهيل عملية الدمج لاحقاً
        foreach ($drivers_info_raw as $driver) {
            $drivers_info[$driver['driver_id']] = $driver;
        }
    }

    // =================================================================
    // الخطوة 4: دمج النتائج في PHP
    // =================================================================
    $final_results = [];
    foreach ($locations as $location) {
        $driver_id = $location['driver_id'];
        // ندمج فقط السائقين الذين طابقوا شروطنا في الاستعلام الثاني
        if (isset($drivers_info[$driver_id])) {
            $final_results[] = array_merge($location, $drivers_info[$driver_id]);
        }
    }

    // =================================================================
    // الخطوة 5: تطبيق الترتيب والحد النهائي في PHP
    // =================================================================
    // الآن بعد أن دمجنا كل البيانات، يمكننا تطبيق الترتيب المعقد
    usort($final_results, function ($a, $b) {
        // الترتيب الأول: حسب التقييم (تنازلي)
        if ($a['ratingDriver'] != $b['ratingDriver']) {
            return $b['ratingDriver'] <=> $a['ratingDriver'];
        }
        // الترتيب الثاني: حسب عدد التقييمات (تنازلي)
        if ($a['ratingCount'] != $b['ratingCount']) {
            return $b['ratingCount'] <=> $a['ratingCount'];
        }
        // الترتيب الثالث: حسب حداثة الموقع (تنازلي)
        return strtotime($b['updated_at']) <=> strtotime($a['updated_at']);
    });

    // وأخيراً، نأخذ أفضل 5 نتائج فقط
    $limited_results = array_slice($final_results, 0, 5);

    if (empty($limited_results)) {
        jsonError("No cars matching the specific criteria (year > 2017) found.");
        exit;
    }

    // =================================================================
    // الخطوة 6: فك التشفير وحساب العمر (بدون تغيير)
    // =================================================================
    $fieldsToDecrypt = [ 'phone','email','gender','birthdate', 'first_name','last_name', 'token','car_plate','vin' ];
    foreach ($limited_results as &$row) {
        foreach ($fieldsToDecrypt as $field) {
            if (isset($row[$field]) && !empty($row[$field])) {
                try { $row[$field] = $encryptionHelper->decryptData($row[$field]); }
                catch (Exception $e) { $row[$field] = null; }
            }
        }
        if (!empty($row['birthdate'])) {
            try {
                $birthDate = new DateTime($row['birthdate']);
                $today = new DateTime();
                $row['age'] = $today->diff($birthDate)->y;
            } catch (Exception $e) { $row['age'] = null; }
        } else {
            $row['age'] = null;
        }
    }
    unset($row);

    jsonSuccess($limited_results);

} catch (PDOException $e) {
    jsonError("Database error: " . $e->getMessage());
} catch (Throwable $e) {
    jsonError("Internal error: " . $e->getMessage());
}

File: ride/location/delete.php

<?

require_once __DIR__ . '/../../connect.php';

$driver_id = filterRequest("driver_id");

$sql = "DELETE FROM `car_locations` WHERE `driver_id` = $driver_id";

$stmt = $con->prepare($sql);
$stmt->execute();

if ($stmt->rowCount() > 0) {
    // Print a success message
    jsonSuccess($message = "Car location deleted successfully");
} else {
    // Print a failure message
    jsonError($message = "Failed to delete car location");
}

?>

File: ride/location/getBalash.php

<?php
require_once __DIR__ . '/../../connect.php'; // يفترض أن هذا الملف ينشئ $con و $con_tracking
//getBalash.php
try {
    // 1) قراءة والتحقق من الإحداثيات
    $southwestLat = filterRequest("southwestLat");
    $southwestLon = filterRequest("southwestLon");
    $northeastLat = filterRequest("northeastLat");
    $northeastLon = filterRequest("northeastLon");

    if ($southwestLat === false || $southwestLon === false || $northeastLat === false || $northeastLon === false) {
        jsonError("Invalid coordinates provided");
        exit;
    }

    $freshSeconds = 180; // 3 دقائق

    // =================================================================
    // الخطوة 1: جلب المواقع والمعرفات من قاعدة بيانات التتبع
    // =================================================================

    // إعادة استخدام التحسين الجغرافي ST_CONTAINS لأنه أسرع بمراحل
    $boundingBoxWKT = sprintf(
        'POLYGON((%f %f, %f %f, %f %f, %f %f, %f %f))',
        $southwestLon, $southwestLat,
        $northeastLon, $southwestLat,
        $northeastLon, $northeastLat,
        $southwestLon, $northeastLat,
        $southwestLon, $southwestLat
    );

    // ملاحظة: نزيل LIMIT 5 من هنا ونجلب مجموعة أكبر من المرشحين
    // لأن الترتيب النهائي يعتمد على بيانات من القاعدة الأخرى
    $sql_locations = "
        SELECT driver_id, latitude, longitude, heading, speed, status, updated_at
        FROM car_locations
        WHERE
            ST_CONTAINS(ST_GeomFromText(:boundingBox, 4326), location_point)
            AND status = 'off'
            AND updated_at >= NOW() - INTERVAL :freshSeconds SECOND
        ORDER BY updated_at DESC
        LIMIT 20; -- نجلب 100 مرشح محتمل للفلترة والترتيب لاحقاً
    ";

    $stmt_locations = $con_tracking->prepare($sql_locations);
    $stmt_locations->bindValue(':boundingBox', $boundingBoxWKT);
    $stmt_locations->bindValue(':freshSeconds', $freshSeconds, PDO::PARAM_INT);
    $stmt_locations->execute();
    $locations = $stmt_locations->fetchAll(PDO::FETCH_ASSOC);

    if (!$locations) {
        jsonError("No car locations found in the specified area.");
        exit;
    }

    // =================================================================
    // الخطوة 2: تجميع معرفات السائقين (driver_id)
    // =================================================================
    $driver_ids = array_column($locations, 'driver_id');

    // =================================================================
    // الخطوة 3: جلب البيانات الثابتة من القاعدة الأساسية وتطبيق الفلاتر الإضافية
    // =================================================================
    $drivers_info = [];
    if (!empty($driver_ids)) {
        $placeholders = implode(',', array_fill(0, count($driver_ids), '?'));

        // هنا نطبق الشروط الخاصة بهذا السكريبت (موديل السيارة < 2000)
        $sql_drivers_info = "
            SELECT
                d.id AS driver_id, d.phone, d.email, d.birthdate, d.first_name, d.last_name,
                cr.make, cr.model, cr.color, cr.color_hex, cr.year,
                dt.token,
                COALESCE(rdAvg.ratingDriver, 0) AS ratingDriver,
                COALESCE(rdAvg.ratingCount, 0) AS ratingCount
            FROM driver d
            LEFT JOIN CarRegistration cr ON cr.driverID = d.id
            LEFT JOIN driverToken dt ON dt.captain_id = d.id
            LEFT JOIN (
                SELECT driver_id, AVG(rating) AS ratingDriver, COUNT(id) AS ratingCount
                FROM ratingDriver
                GROUP BY driver_id
            ) rdAvg ON rdAvg.driver_id = d.id
            WHERE d.id IN ($placeholders)
              AND COALESCE(cr.year, 0) < 2000 -- ⭐ الشرط الخاص بهذا السكريبت
              AND (cr.make NOT LIKE '%دراج%' AND cr.model NOT LIKE '%دراج%')
              AND (cr.model NOT LIKE '%Van%' AND cr.make NOT LIKE '%Van%')
        ";

        $stmt_drivers_info = $con->prepare($sql_drivers_info);
        $stmt_drivers_info->execute($driver_ids);
        $drivers_info_raw = $stmt_drivers_info->fetchAll(PDO::FETCH_ASSOC);

        // تحويل المصفوفة لتسهيل عملية الدمج لاحقاً
        foreach ($drivers_info_raw as $driver) {
            $drivers_info[$driver['driver_id']] = $driver;
        }
    }

    // =================================================================
    // الخطوة 4: دمج النتائج في PHP
    // =================================================================
    $final_results = [];
    foreach ($locations as $location) {
        $driver_id = $location['driver_id'];
        // ندمج فقط السائقين الذين طابقوا شروطنا في الاستعلام الثاني
        if (isset($drivers_info[$driver_id])) {
            $final_results[] = array_merge($location, $drivers_info[$driver_id]);
        }
    }

    // =================================================================
    // الخطوة 5: تطبيق الترتيب والحد النهائي في PHP
    // =================================================================
    // الآن بعد أن دمجنا كل البيانات، يمكننا تطبيق الترتيب المعقد
    usort($final_results, function ($a, $b) {
        // الترتيب الأول: حسب التقييم (تنازلي)
        if ($a['ratingDriver'] != $b['ratingDriver']) {
            return $b['ratingDriver'] <=> $a['ratingDriver'];
        }
        // الترتيب الثاني: حسب عدد التقييمات (تنازلي)
        if ($a['ratingCount'] != $b['ratingCount']) {
            return $b['ratingCount'] <=> $a['ratingCount'];
        }
        // الترتيب الثالث: حسب حداثة الموقع (تنازلي)
        return strtotime($b['updated_at']) <=> strtotime($a['updated_at']);
    });

    // وأخيراً، نأخذ أفضل 5 نتائج فقط
    $limited_results = array_slice($final_results, 0, 5);

    if (empty($limited_results)) {
        jsonError("No cars matching the specific criteria (year < 2000) found.");
        exit;
    }

    // =================================================================
    // الخطوة 6: فك التشفير وحساب العمر (بدون تغيير)
    // =================================================================
    $fieldsToDecrypt = [ 'phone','email','gender','birthdate', 'first_name','last_name', 'token','car_plate','vin' ];
    foreach ($limited_results as &$row) {
        foreach ($fieldsToDecrypt as $field) {
            if (isset($row[$field]) && !empty($row[$field])) {
                try { $row[$field] = $encryptionHelper->decryptData($row[$field]); }
                catch (Exception $e) { $row[$field] = null; }
            }
        }
        if (!empty($row['birthdate'])) {
            try {
                $birthDate = new DateTime($row['birthdate']);
                $today = new DateTime();
                $row['age'] = $today->diff($birthDate)->y;
            } catch (Exception $e) { $row['age'] = null; }
        } else {
            $row['age'] = null;
        }
    }
    unset($row);

    jsonSuccess($limited_results);

} catch (PDOException $e) {
    jsonError("Database error: " . $e->getMessage());
} catch (Throwable $e) {
    jsonError("Internal error: " . $e->getMessage());
}

File: ride/location/getLatestLocationPassenger.php

<?php
require_once __DIR__ . '/../../connect.php';

$rideId = filterRequest("rideId");

$sql = "SELECT
    *
FROM
    `passengerlocation` pl
WHERE
    pl.rideId = :rideId
ORDER BY
     pl.createdAt
DESC
LIMIT 1";

$stmt = $con->prepare($sql);
$stmt->execute([':rideId' => $rideId]);
$car_locations = $stmt->fetchAll(PDO::FETCH_ASSOC);

if ($car_locations) {
    // Print the car location data as JSON
    jsonSuccess($data = $car_locations);
} else {
    // Print a failure message
    jsonError($message = "No car locations found");
}

?>

File: ride/location/getRidesDriverByDay.php

<?php
require_once __DIR__ . '/../../connect.php';
$driver_id = filterRequest("driver_id");
$current_month = date('m');
$current_year = date('Y');

// Get the first and last days of the current month.
$first_day_of_month = date('Y-m-d', strtotime($current_year . '-' . $current_month . '-01'));
$last_day_of_month = date('Y-m-d', strtotime($current_year . '-' . $current_month . '-' . cal_days_in_month(CAL_GREGORIAN, $current_month, $current_year)));

// Create a SQL query to select the total duration for the driver for each day in the current month.
$sql = "SELECT
    DATE(`ride`.created_at) AS day,
    COUNT(`ride`.`id`) AS countRide,
    SUM(`ride`.`price`) AS pricePerDay,
    (
        SELECT
            SUM(`ride`.`price`)
        FROM
            `ride`
        WHERE
            `ride`.`driver_id` = :driver_id_total AND `ride`.`created_at` >= :first_day_total AND `ride`.created_at < :last_day_total AND `ride`.`status` = 'Finished'
    ) AS totalPrice,
    (
        SELECT
            COUNT(`ride`.`id`)
        FROM
            `ride`
        WHERE
            `ride`.`driver_id` = :driver_id_count AND `ride`.`created_at` >= :first_day_count AND `ride`.created_at < :last_day_count AND `ride`.`status` = 'Finished'
    ) AS totalCount
FROM
    `ride`
WHERE
    `ride`.`driver_id` = :driver_id_main AND `ride`.`created_at` >= :first_day_main AND `ride`.created_at < :last_day_main AND `ride`.`status` = 'Finished'
GROUP BY
    day
ORDER BY
    day ASC;";
    
$stmt = $con->prepare($sql);

// Bind each parameter uniquely
$stmt->bindParam(':driver_id_total', $driver_id, PDO::PARAM_STR);
$stmt->bindParam(':first_day_total', $first_day_of_month, PDO::PARAM_STR);
$stmt->bindParam(':last_day_total', $last_day_of_month, PDO::PARAM_STR);

$stmt->bindParam(':driver_id_count', $driver_id, PDO::PARAM_STR);
$stmt->bindParam(':first_day_count', $first_day_of_month, PDO::PARAM_STR);
$stmt->bindParam(':last_day_count', $last_day_of_month, PDO::PARAM_STR);

$stmt->bindParam(':driver_id_main', $driver_id, PDO::PARAM_STR);
$stmt->bindParam(':first_day_main', $first_day_of_month, PDO::PARAM_STR);
$stmt->bindParam(':last_day_main', $last_day_of_month, PDO::PARAM_STR);

$stmt->execute();

$car_locations = $stmt->fetchAll(PDO::FETCH_ASSOC);
if ($car_locations) {
  // Print the car location data as JSON
  jsonSuccess($data = $car_locations);
} else {
  // Print a failure message
  jsonError($message = "No car locations found");
}
?>

File: ride/location/getFemalDriver.php

<?php
//getFemalDriver.php
require_once __DIR__ . '/../../connect.php'; // يفترض أن هذا الملف ينشئ $con و $con_tracking

try {
    // 1) قراءة والتحقق من الإحداثيات
    $southwestLat = filterRequest("southwestLat");
    $southwestLon = filterRequest("southwestLon");
    $northeastLat = filterRequest("northeastLat");
    $northeastLon = filterRequest("northeastLon");

    if ($southwestLat === false || $southwestLon === false || $northeastLat === false || $northeastLon === false) {
        jsonError("Invalid coordinates provided");
        exit;
    }

    $freshSeconds = 180; // 3 دقائق

    // =================================================================
    // الخطوة 1: جلب المواقع والمعرفات من قاعدة بيانات التتبع
    // =================================================================

    // استخدام التحسين الجغرافي ST_CONTAINS لأنه أسرع بمراحل
    $boundingBoxWKT = sprintf(
        'POLYGON((%f %f, %f %f, %f %f, %f %f, %f %f))',
        $southwestLon, $southwestLat,
        $northeastLon, $southwestLat,
        $northeastLon, $northeastLat,
        $southwestLon, $northeastLat,
        $southwestLon, $southwestLat
    );

    // جلب مجموعة من المرشحين المحتملين للفلترة والترتيب لاحقاً
    $sql_locations = "
        SELECT driver_id, latitude, longitude, heading, speed, status, updated_at
        FROM car_locations
        WHERE
            ST_CONTAINS(ST_GeomFromText(:boundingBox, 4326), location_point)
            AND status = 'off'
            AND updated_at >= NOW() - INTERVAL :freshSeconds SECOND
        ORDER BY updated_at DESC
        LIMIT 100; -- نجلب 100 مرشح محتمل
    ";

    $stmt_locations = $con_tracking->prepare($sql_locations);
    $stmt_locations->bindValue(':boundingBox', $boundingBoxWKT);
    $stmt_locations->bindValue(':freshSeconds', $freshSeconds, PDO::PARAM_INT);
    $stmt_locations->execute();
    $locations = $stmt_locations->fetchAll(PDO::FETCH_ASSOC);

    if (!$locations) {
        jsonError("No car locations found in the specified area.");
        exit;
    }

    // =================================================================
    // الخطوة 2: تجميع معرفات السائقين (driver_id)
    // =================================================================
    $driver_ids = array_column($locations, 'driver_id');

    // =================================================================
    // الخطوة 3: جلب البيانات الثابتة من القاعدة الأساسية وتطبيق الفلاتر الإضافية
    // =================================================================
    $drivers_info = [];
    if (!empty($driver_ids)) {
        $placeholders = implode(',', array_fill(0, count($driver_ids), '?'));

        // هنا نطبق الشروط الخاصة بهذا السكريبت (سائقات إناث فقط)
        $sql_drivers_info = "
            SELECT
                d.id AS driver_id, d.phone, d.email, d.birthdate, d.first_name, d.last_name, d.gender, d.maritalStatus,
                cr.make, cr.model, cr.color, cr.color_hex, cr.year,
                dt.token,
                COALESCE(AVG(rd.rating), 0) AS ratingDriver,
                COUNT(rd.id) AS ratingCount
            FROM driver d
            LEFT JOIN CarRegistration cr ON cr.driverID = d.id
            LEFT JOIN driverToken dt ON dt.captain_id = d.id
            LEFT JOIN ratingDriver rd ON rd.driver_id = d.id
            WHERE d.id IN ($placeholders)
              AND d.gender = 'Female' -- ⭐ الشرط الخاص بهذا السكريبت
              AND (cr.make NOT LIKE '%دراجة%' AND cr.model NOT LIKE '%دراجة%')
              AND (cr.model NOT LIKE '%Van%' AND cr.make NOT LIKE '%Van%')
            GROUP BY d.id -- تجميع النتائج حسب السائق لحساب التقييم بشكل صحيح
        ";

        $stmt_drivers_info = $con->prepare($sql_drivers_info);
        $stmt_drivers_info->execute($driver_ids);
        $drivers_info_raw = $stmt_drivers_info->fetchAll(PDO::FETCH_ASSOC);

        // تحويل المصفوفة لتسهيل عملية الدمج لاحقاً
        foreach ($drivers_info_raw as $driver) {
            $drivers_info[$driver['driver_id']] = $driver;
        }
    }

    // =================================================================
    // الخطوة 4: دمج النتائج في PHP
    // =================================================================
    $final_results = [];
    foreach ($locations as $location) {
        $driver_id = $location['driver_id'];
        // ندمج فقط السائقين الذين طابقوا شروطنا في الاستعلام الثاني (أنثى)
        if (isset($drivers_info[$driver_id])) {
            $final_results[] = array_merge($location, $drivers_info[$driver_id]);
        }
    }

    // =================================================================
    // الخطوة 5: تطبيق الترتيب والحد النهائي في PHP
    // =================================================================
    usort($final_results, function ($a, $b) {
        if ($a['ratingDriver'] != $b['ratingDriver']) {
            return $b['ratingDriver'] <=> $a['ratingDriver'];
        }
        if ($a['ratingCount'] != $b['ratingCount']) {
            return $b['ratingCount'] <=> $a['ratingCount'];
        }
        return strtotime($b['updated_at']) <=> strtotime($a['updated_at']);
    });

    // وأخيراً، نأخذ أفضل 10 نتائج فقط
    $limited_results = array_slice($final_results, 0, 10);

    if (empty($limited_results)) {
        jsonError("No female drivers matching the criteria found.");
        exit;
    }

    // =================================================================
    // الخطوة 6: فك التشفير وحساب العمر (بدون تغيير)
    // =================================================================
    $fieldsToDecrypt = [ 'phone','email','gender','birthdate', 'first_name','last_name', 'token','car_plate','vin' ];
    foreach ($limited_results as &$row) {
        foreach ($fieldsToDecrypt as $field) {
            if (isset($row[$field]) && !empty($row[$field])) {
                try { $row[$field] = $encryptionHelper->decryptData($row[
                $field]); }
                catch (Exception $e) { $row[$field] = null; }
            }
        }
        if (!empty($row['birthdate'])) {
            try {
                $birthDate = new DateTime($row['birthdate']);
                $today = new DateTime();
                $row['age'] = $today->diff($birthDate)->y;
            } catch (Exception $e) { $row['age'] = null; }
        } else {
            $row['age'] = null;
        }
    }
    unset($row);

    jsonSuccess($limited_results);

} catch (PDOException $e) {
    jsonError("Database error: " . $e->getMessage());
} catch (Throwable $e) {
    jsonError("Internal error: " . $e->getMessage());
}

File: ride/location/getDelivery.php

<?php
require_once __DIR__ . '/../../connect.php'; // يفترض أن هذا الملف ينشئ $con و $con_tracking
//getDelivery.php
try {
    // 1) قراءة والتحقق من الإحداثيات
    $southwestLat = filterRequest("southwestLat");
    $southwestLon = filterRequest("southwestLon");
    $northeastLat = filterRequest("northeastLat");
    $northeastLon = filterRequest("northeastLon");

    if ($southwestLat === false || $southwestLon === false || $northeastLat === false || $northeastLon === false) {
        jsonError("Invalid coordinates provided");
        exit;
    }

    $freshSeconds = 180; // 3 دقائق

    // =================================================================
    // الخطوة 1: جلب المواقع والمعرفات من قاعدة بيانات التتبع
    // =================================================================

    // استخدام التحسين الجغرافي ST_CONTAINS لأنه أسرع بمراحل
    $boundingBoxWKT = sprintf(
        'POLYGON((%f %f, %f %f, %f %f, %f %f, %f %f))',
        $southwestLon, $southwestLat,
        $northeastLon, $southwestLat,
        $northeastLon, $northeastLat,
        $southwestLon, $northeastLat,
        $southwestLon, $southwestLat
    );

    // جلب مجموعة من المرشحين المحتملين للفلترة والترتيب لاحقاً
    $sql_locations = "
        SELECT driver_id, latitude, longitude, heading, speed, status, updated_at
        FROM car_locations
        WHERE
            ST_CONTAINS(ST_GeomFromText(:boundingBox, 4326), location_point)
            AND status = 'off'
            AND updated_at >= NOW() - INTERVAL :freshSeconds SECOND
        ORDER BY updated_at DESC
        LIMIT 100; -- نجلب 100 مرشح محتمل
    ";

    $stmt_locations = $con_tracking->prepare($sql_locations);
    $stmt_locations->bindValue(':boundingBox', $boundingBoxWKT);
    $stmt_locations->bindValue(':freshSeconds', $freshSeconds, PDO::PARAM_INT);
    $stmt_locations->execute();
    $locations = $stmt_locations->fetchAll(PDO::FETCH_ASSOC);

    if (!$locations) {
        jsonError("No car locations found in the specified area.");
        exit;
    }

    // =================================================================
    // الخطوة 2: تجميع معرفات السائقين (driver_id)
    // =================================================================
    $driver_ids = array_column($locations, 'driver_id');

    // =================================================================
    // الخطوة 3: جلب البيانات الثابتة من القاعدة الأساسية وتطبيق الفلاتر الإضافية
    // =================================================================
    $drivers_info = [];
    if (!empty($driver_ids)) {
        $placeholders = implode(',', array_fill(0, count($driver_ids), '?'));

        // هنا نطبق الشروط الخاصة بهذا السكريبت (دراجات فقط)
        $sql_drivers_info = "
            SELECT
                d.id AS driver_id, d.phone, d.email, d.birthdate, d.first_name, d.last_name,
                cr.make, cr.model, cr.color, cr.color_hex, cr.year,
                dt.token,
                COALESCE(rdAvg.ratingDriver, 0) AS ratingDriver,
                COALESCE(rdAvg.ratingCount, 0) AS ratingCount
            FROM driver d
            LEFT JOIN CarRegistration cr ON cr.driverID = d.id
            LEFT JOIN driverToken dt ON dt.captain_id = d.id
            LEFT JOIN (
                SELECT driver_id, AVG(rating) AS ratingDriver, COUNT(*) AS ratingCount
                FROM ratingDriver
                GROUP BY driver_id
            ) rdAvg ON rdAvg.driver_id = d.id
            WHERE d.id IN ($placeholders)
              AND (cr.make LIKE '%دراج%' OR cr.model LIKE '%دراج%') -- ⭐ الشرط الخاص بهذا السكريبت
        ";

        $stmt_drivers_info = $con->prepare($sql_drivers_info);
        $stmt_drivers_info->execute($driver_ids);
        $drivers_info_raw = $stmt_drivers_info->fetchAll(PDO::FETCH_ASSOC);

        // تحويل المصفوفة لتسهيل عملية الدمج لاحقاً
        foreach ($drivers_info_raw as $driver) {
            $drivers_info[$driver['driver_id']] = $driver;
        }
    }

    // =================================================================
    // الخطوة 4: دمج النتائج في PHP
    // =================================================================
    $final_results = [];
    foreach ($locations as $location) {
        $driver_id = $location['driver_id'];
        // ندمج فقط السائقين الذين طابقوا شروطنا في الاستعلام الثاني
        if (isset($drivers_info[$driver_id])) {
            $final_results[] = array_merge($location, $drivers_info[$driver_id]);
        }
    }

    // =================================================================
    // الخطوة 5: تطبيق الترتيب والحد النهائي في PHP
    // =================================================================
    usort($final_results, function ($a, $b) {
        if ($a['ratingDriver'] != $b['ratingDriver']) {
            return $b['ratingDriver'] <=> $a['ratingDriver'];
        }
        if ($a['ratingCount'] != $b['ratingCount']) {
            return $b['ratingCount'] <=> $a['ratingCount'];
        }
        return strtotime($b['updated_at']) <=> strtotime($a['updated_at']);
    });

    // وأخيراً، نأخذ أفضل 10 نتائج فقط
    $limited_results = array_slice($final_results, 0, 10);

    if (empty($limited_results)) {
        jsonError("No motorcycles matching the criteria found.");
        exit;
    }

    // =================================================================
    // الخطوة 6: فك التشفير وحساب العمر (بدون تغيير)
    // =================================================================
    $fieldsToDecrypt = [ 'phone','email','gender','birthdate', 'first_name','last_name','maritalStatus', 'token','make','car_plate','vin' ];
    foreach ($limited_results as &$row) {
        foreach ($fieldsToDecrypt as $field) {
            if (isset($row[$field]) && !empty($row[$field])) {
                try { $row[$field] = $encryptionHelper->decryptData($row[$field]); }
                catch (Exception $e) { $row[$field] = null; }
            }
        }
        if (!empty($row['birthdate'])) {
            try {
                $birthDate = new DateTime($row['birthdate']);
                $today = new DateTime();
                $row['age'] = $today->diff($birthDate)->y;
            } catch (Exception $e) { $row['age'] = null; }
        } else {
            $row['age'] = null;
        }
    }
    unset($row);

    jsonSuccess($limited_results);

} catch (PDOException $e) {
    jsonError("Database error: " . $e->getMessage());
} catch (Throwable $e) {
    jsonError("Internal error: " . $e->getMessage());
}

File: ride/location/getElectric.php

<?php
require_once __DIR__ . '/../../connect.php'; // يفترض أن هذا الملف ينشئ $con و $con_tracking
//getElectric.php
try {
    // 1) قراءة والتحقق من الإحداثيات
    $southwestLat = filterRequest("southwestLat");
    $southwestLon = filterRequest("southwestLon");
    $northeastLat = filterRequest("northeastLat");
    $northeastLon = filterRequest("northeastLon");

    if ($southwestLat === false || $southwestLon === false || $northeastLat === false || $northeastLon === false) {
        jsonError("Invalid coordinates provided");
        exit;
    }

    $freshSeconds = 180; // 3 دقائق

    // =================================================================
    // الخطوة 1: جلب المواقع والمعرفات من قاعدة بيانات التتبع
    // =================================================================

    // استخدام التحسين الجغرافي ST_CONTAINS لأنه أسرع بمراحل
    $boundingBoxWKT = sprintf(
        'POLYGON((%f %f, %f %f, %f %f, %f %f, %f %f))',
        $southwestLon, $southwestLat,
        $northeastLon, $southwestLat,
        $northeastLon, $northeastLat,
        $southwestLon, $northeastLat,
        $southwestLon, $southwestLat
    );

    // جلب مجموعة من المرشحين المحتملين للفلترة والترتيب لاحقاً
    $sql_locations = "
        SELECT driver_id, latitude, longitude, heading, speed, status, updated_at
        FROM car_locations
        WHERE
            ST_CONTAINS(ST_GeomFromText(:boundingBox, 4326), location_point)
            AND status = 'off'
            AND updated_at >= NOW() - INTERVAL :freshSeconds SECOND
        ORDER BY updated_at DESC
        LIMIT 100; -- نجلب 100 مرشح محتمل
    ";

    $stmt_locations = $con_tracking->prepare($sql_locations);
    $stmt_locations->bindValue(':boundingBox', $boundingBoxWKT);
    $stmt_locations->bindValue(':freshSeconds', $freshSeconds, PDO::PARAM_INT);
    $stmt_locations->execute();
    $locations = $stmt_locations->fetchAll(PDO::FETCH_ASSOC);

    if (!$locations) {
        jsonError("No car locations found in the specified area.");
        exit;
    }

    // =================================================================
    // الخطوة 2: تجميع معرفات السائقين (driver_id)
    // =================================================================
    $driver_ids = array_column($locations, 'driver_id');

    // =================================================================
    // الخطوة 3: جلب البيانات الثابتة من القاعدة الأساسية وتطبيق الفلاتر الإضافية
    // =================================================================
    $drivers_info = [];
    if (!empty($driver_ids)) {
        $placeholders = implode(',', array_fill(0, count($driver_ids), '?'));

        // هنا نطبق الشروط الخاصة بهذا السكريبت (سيارات كهربائية فقط)
        $sql_drivers_info = "
            SELECT
                d.id AS driver_id, d.phone, d.email, d.birthdate, d.first_name, d.last_name,
                cr.make, cr.model, cr.color, cr.color_hex, cr.year, cr.fuel,
                dt.token,
                COALESCE(rdAvg.ratingDriver, 0) AS ratingDriver,
                COALESCE(rdAvg.ratingCount, 0) AS ratingCount
            FROM driver d
            LEFT JOIN CarRegistration cr ON cr.driverID = d.id
            LEFT JOIN driverToken dt ON dt.captain_id = d.id
            LEFT JOIN (
                SELECT driver_id, AVG(rating) AS ratingDriver, COUNT(*) AS ratingCount
                FROM ratingDriver
                GROUP BY driver_id
            ) rdAvg ON rdAvg.driver_id = d.id
            WHERE d.id IN ($placeholders)
              AND cr.fuel = 'كهربائي' 
              AND (cr.make NOT LIKE '%دراج%' AND cr.model NOT LIKE '%دراج%')
              AND (cr.model NOT LIKE '%Van%' AND cr.make NOT LIKE '%Van%')
        ";

        $stmt_drivers_info = $con->prepare($sql_drivers_info);
        $stmt_drivers_info->execute($driver_ids);
        $drivers_info_raw = $stmt_drivers_info->fetchAll(PDO::FETCH_ASSOC);

        // تحويل المصفوفة لتسهيل عملية الدمج لاحقاً
        foreach ($drivers_info_raw as $driver) {
            $drivers_info[$driver['driver_id']] = $driver;
        }
    }

    // =================================================================
    // الخطوة 4: دمج النتائج في PHP
    // =================================================================
    $final_results = [];
    foreach ($locations as $location) {
        $driver_id = $location['driver_id'];
        // ندمج فقط السائقين الذين طابقوا شروطنا في الاستعلام الثاني
        if (isset($drivers_info[$driver_id])) {
            $final_results[] = array_merge($location, $drivers_info[$driver_id]);
        }
    }

    // =================================================================
    // الخطوة 5: تطبيق الترتيب والحد النهائي في PHP
    // =================================================================
    usort($final_results, function ($a, $b) {
        if ($a['ratingDriver'] != $b['ratingDriver']) {
            return $b['ratingDriver'] <=> $a['ratingDriver'];
        }
        if ($a['ratingCount'] != $b['ratingCount']) {
            return $b['ratingCount'] <=> $a['ratingCount'];
        }
        return strtotime($b['updated_at']) <=> strtotime($a['updated_at']);
    });

    // وأخيراً، نأخذ أفضل 10 نتائج فقط
    $limited_results = array_slice($final_results, 0, 10);

    if (empty($limited_results)) {
        jsonError("No electric cars matching the criteria found.");
        exit;
    }

    // =================================================================
    // الخطوة 6: فك التشفير وحساب العمر (بدون تغيير)
    // =================================================================
    $fieldsToDecrypt = [ 'phone','email','gender','birthdate', 'first_name','last_name', 'token','car_plate','vin' ];
    foreach ($limited_results as &$row) {
        foreach ($fieldsToDecrypt as $field) {
            if (isset($row[$field]) && !empty($row[$field])) {
                try { $row[$field] = $encryptionHelper->decryptData($row[$field]); }
                catch (Exception $e) { $row[$field] = null; }
            }
        }
        if (!empty($row['birthdate'])) {
            try {
                $birthDate = new DateTime($row['birthdate']);
                $today = new DateTime();
                $row['age'] = $today->diff($birthDate)->y;
            } catch (Exception $e) { $row['age'] = null; }
        } else {
            $row['age'] = null;
        }
    }
    unset($row);

    jsonSuccess($limited_results);

} catch (PDOException $e) {
    jsonError("Database error: " . $e->getMessage());
} catch (Throwable $e) {
    jsonError("Internal error: " . $e->getMessage());
}

File: ride/location/addpassengerLocation.php

<?php
require_once __DIR__ . '/../../connect.php';

$passengerId = filterRequest("passengerId");
$lat = filterRequest("lat");
$lng = filterRequest("lng");
$rideId = filterRequest("rideId");

// Validate the latitude and longitude
if ($lat === '' || $lng === '') {
    jsonError("Latitude and longitude cannot be empty");
    exit;
}

// Prepare an SQL statement with placeholders
$sql = "INSERT INTO `passengerlocation`( `passengerId`, `lat`, `lng`, `rideId`) VALUES (:passengerId, :lat, :lng, :rideId)";

$stmt = $con->prepare($sql);

// Bind the parameters to the SQL query
$stmt->bindParam(':passengerId', $passengerId);
$stmt->bindParam(':lat', $lat);
$stmt->bindParam(':lng', $lng);
$stmt->bindParam(':rideId', $rideId);

// Execute the statement
if ($stmt->execute()) {
    // Print a success message
    jsonSuccess(null, "Passenger location saved successfully");
} else {
    // Print a failure message
    jsonError("Failed to save passenger location");
}
?>

File: ride/payment/add.php

<?php

require_once __DIR__ . '/../../connect.php';

$amount = filterRequest("amount");
$payment_method = filterRequest("payment_method");
$passengerID = filterRequest("passengerID");
$rideId = filterRequest("rideId");
$driverID = filterRequest("driverID");
$token = filterRequest("token");


// Retrieve token details from the database
$stmt = $con->prepare("SELECT * FROM payment_tokens WHERE token = :token AND isUsed = FALSE");
$stmt->execute(array(
    ':token' => $token
));

$tokenData = $stmt->fetch();

if ($tokenData) {

$sql = "INSERT INTO `payments` (`id`,`amount`, `payment_method`, `passengerID`, `rideId`, `driverID`) 
        VALUES ( SHA2(UUID(), 256),'$amount', '$payment_method', '$passengerID', '$rideId', '$driverID')";
$stmt = $con->prepare($sql);
$stmt->execute();

if ($stmt->rowCount() > 0) {
    // Print a success message
    jsonSuccess(null, "Payment record created successfully");
    // Mark the token as used in the database
        $stmt = $con->prepare("UPDATE payment_tokens SET isUsed = TRUE WHERE id = :tokenID");
        $stmt->execute(array(
            ':tokenID' => $tokenData['id']
        ));
    } else {
        // Print a failure message
        jsonError("Failed to save record");
    }
} else {
    jsonError("Invalid or already used token");
}

File: ride/payment/update.php

<?php
require_once __DIR__ . '/../../connect.php';

$id = filterRequest("id");

// Create an empty array to store the column-value pairs
$columnValues = array();

// Check if each column is set in the request and add it to the array
if (isset($_POST["amount"])) {
    $amount = filterRequest("amount");
    $columnValues[] = "`amount` = '$amount'";
}

if (isset($_POST["payment_method"])) {
    $payment_method = filterRequest("payment_method");
    $columnValues[] = "`payment_method` = '$payment_method'";
}

if (isset($_POST["passengerID"])) {
    $passengerID = filterRequest("passengerID");
    $columnValues[] = "`passengerID` = '$passengerID'";
}

if (isset($_POST["rideId"])) {
    $rideId = filterRequest("rideId");
    $columnValues[] = "`rideId` = '$rideId'";
}

if (isset($_POST["driverID"])) {
    $driverID = filterRequest("driverID");
    $columnValues[] = "`driverID` = '$driverID'";
}

if (isset($_POST["created_at"])) {
    $created_at = filterRequest("created_at");
    $columnValues[] = "`created_at` = '$created_at'";
}

if (isset($_POST["updated_at"])) {
    $updated_at = filterRequest("updated_at");
    $columnValues[] = "`updated_at` = '$updated_at'";
}

if (isset($_POST["isGiven"])) {
    $isGiven = filterRequest("isGiven");
    $columnValues[] = "`isGiven` = '$isGiven'";
}

// Construct the SET clause of the update query using the column-value pairs
$setClause = implode(", ", $columnValues);

$sql = "UPDATE `payments` SET $setClause WHERE `id` = '$id'";

$stmt = $con->prepare($sql);
$stmt->execute();

if ($stmt->rowCount() > 0) {
    // Print a success message
    jsonSuccess($message = "Payment data updated successfully");
} else {
    // Print a failure message
    jsonError($message = "Failed to update payment data");
}
?>

File: ride/payment/get.php

<?php
require_once __DIR__ . '/../../connect.php';
$driverID = filterRequest("driverID");

$sql = "SELECT
  p1.id,
  p1.amount,
  p2.total_amount,
  p1.payment_method,
  p1.isGiven,
  p1.passengerID,
  p1.rideId,
  p1.driverID,
  (
    SELECT SUM(amount)
    FROM payments
    WHERE driverID = '$driverID'
      AND DATE(created_at) = CURDATE()
  ) AS todayAmount,
  p1.created_at,
  p1.updated_at,
  (
    SELECT ROUND(AVG(CAST(rating AS DECIMAL(4,2))), 2)
    FROM ratingDriver
    WHERE driver_id = '$driverID'
  ) AS rating
FROM payments p1
JOIN (
  SELECT driverID, SUM(amount) AS total_amount
  FROM payments
  WHERE isGiven = 'waiting'
  GROUP BY driverID
) p2 ON p1.driverID = p2.driverID
WHERE p1.isGiven = 'waiting'
  AND p1.driverID = '$driverID'
  AND DATE(p1.created_at) = CURDATE(); ";
$stmt = $con->prepare($sql);
$stmt->execute();

if ($stmt->rowCount() > 0) {
    // Fetch the record
    $row = $stmt->fetchAll(PDO::FETCH_ASSOC);
    $count = $stmt->rowCount();
    
    // $response = array(
       
    //     "message" => "Payment data saved successfully",
    //     "id" => "0",
    //     "count" => $count,
    //     "data" => $rows
    // );

    // echo json_encode($response);
    jsonSuccess($row);
    
}
    else{
    // Print a failure message
    jsonError($message = "No wallet record found");
}
?>

File: ride/payment/getAllPayment.php

<?php
require_once __DIR__ . '/../../connect.php';
$driverID = filterRequest("driverID");

$sql = "SELECT
    (
    SELECT
        COUNT(*)
    FROM
        `ride`
    WHERE
        `ride`.`status` = 'Finished'
        AND `ride`.`created_at` BETWEEN CURRENT_DATE() + INTERVAL 7 HOUR AND CURRENT_DATE() + INTERVAL 10 HOUR
        AND `ride`.`driver_id` = '$driverID'
    ) AS morning_count,
    (
    SELECT
        COUNT(*)
    FROM
        `ride`
    WHERE
        `ride`.`status` = 'Finished'
        AND `ride`.`created_at` BETWEEN CURRENT_DATE() + INTERVAL 15 HOUR AND CURRENT_DATE() + INTERVAL 18 HOUR
        AND `ride`.`driver_id` = '$driverID'
    ) AS afternoon_count,
    (
    SELECT
        COALESCE(SUM(amount), 0) AS total_amount
    FROM
        payments
    WHERE
        isGiven = 'waiting' AND `driverID` = '$driverID'
    ) AS driver_total,
    (
    SELECT
        COALESCE(SUM(price), 0) AS total_amount
    FROM
        ride
    WHERE
        `driver_id` = '$driverID'
        AND `ride`.`status` = 'Finished'
        AND `ride`.`created_at` > CURRENT_DATE() - INTERVAL 1 WEEK
    ) AS total_amount_last_week
FROM
    dual
LIMIT 1;


     ";
$stmt = $con->prepare($sql);
$stmt->execute();

if ($stmt->rowCount() > 0) {
    // Fetch the record
    $row = $stmt->fetchAll(PDO::FETCH_ASSOC);

    jsonSuccess($row);
    
}
    else{
    // Print a failure message
    jsonError($message = "No wallet record found");
}
?>

File: ride/payment/getAllPaymentVisa.php

<?php
require_once __DIR__ . '/../../connect.php';
$driverID = filterRequest("driverID");

$sql = "SELECT
    driverID,
    COALESCE(SUM(amount), 0) AS total_amount,
    COALESCE(SUM(amount), 0) + COALESCE(
        (
        SELECT
            SUM(`amount`)
        FROM
            `paymentsDriverPoints`
        WHERE
            `payment_method` = 'fromBudgetToPoints' AND `driverID` = '$driverID'
    ),
    0
    ) AS diff
FROM
    payments
WHERE
    isGiven = 'waiting'
    AND `payment_method` IN ('visa-in', 'visa', 'visaRide', 'TransferFrom', 'payout', 'TransferTo')
    AND `driverID` = '$driverID'";
$stmt = $con->prepare($sql);
$stmt->execute();

if ($stmt->rowCount() > 0) {
    // Fetch the record
    $row = $stmt->fetchAll(PDO::FETCH_ASSOC);

    jsonSuccess($row);
    
}
    else{
    // Print a failure message
    jsonError($message = "No wallet record found");
}
?>

File: ride/payment/getCountRide.php

<?php
require_once __DIR__ . '/../../connect.php';
$driver_id = filterRequest("driver_id");

$sql = "SELECT
  COUNT(id) AS count
FROM
  `ride`
WHERE
  `ride`.`status` = 'Finished'
  AND driver_id = '$driver_id'
  AND created_at >= CURDATE();
";
$stmt = $con->prepare($sql);
$stmt->execute();

if ($stmt->rowCount() > 0) {
    // Fetch the record
    $row = $stmt->fetchAll(PDO::FETCH_ASSOC);
    

    jsonSuccess($row);
    
}
    else{
    // Print a failure message
    jsonError($message = "No wallet record found");
}
?>

File: ride/payment/updatePaymetToPaid.php

<?php
require_once __DIR__ . '/../../connect.php';

$driverID = filterRequest("driverID");


$sql = "UPDATE `payments` SET `isGiven`='Paid' WHERE driverID='$driverID'";

$stmt = $con->prepare($sql);
$stmt->execute();

if ($stmt->rowCount() > 0) {
    // Print a success message
    jsonSuccess($message = "Payment data updated successfully");
} else {
    // Print a failure message
    jsonError($message = "Failed to update payment data");
}
?>

File: ride/payment/delete.php


File: ride/places/add.php

<?php
require_once __DIR__ . '/../../connect.php'; // Include the database connection

// Get the data from the request (e.g., from Flutter client)
$latitude = filterRequest("latitude");
$longitude = filterRequest("longitude");
$name = filterRequest("name");
$rate = filterRequest("rate");

// Assuming the `created_at` column is of type TIMESTAMP with the default value CURRENT_TIMESTAMP
$sql = "
  INSERT IGNORE INTO `places`(`latitude`, `longitude`, `name`, `rate`) 
  VALUES ('$latitude', '$longitude', '$name', '$rate')
";

$stmt = $con->prepare($sql);
$stmt->execute();

if ($stmt->rowCount() > 0) {
    // Print a success message
    jsonSuccess($message = 'Place inserted successfully');
} else {
    // Print a failure message for duplicate
    jsonSuccess($message = 'Duplicate place, no new entry added');
}
?>

File: ride/cancelRide/add.php

<?php
require_once __DIR__ . '/../../connect.php';

// استقبال المتغيرات
$driverID    = filterRequest("driverID");
$passengerID = filterRequest("passengerID");
$rideID      = filterRequest("rideID");
$note        = filterRequest("note");

// تنفيذ الإدخال بطريقة آمنة
$sql = "INSERT INTO `canecl` (`driverID`, `passengerID`, `rideID`, `note`) 
        VALUES (:driverID, :passengerID, :rideID, :note)";
$stmt = $con->prepare($sql);
$stmt->bindParam(':driverID', $driverID);
$stmt->bindParam(':passengerID', $passengerID);
$stmt->bindParam(':rideID', $rideID);
$stmt->bindParam(':note', $note);
$stmt->execute();

if ($stmt->rowCount() > 0) {
    jsonSuccess(null, "Record inserted successfully");
} else {
    jsonError("Failed to insert record");
}
?>

File: ride/cancelRide/update.php

<?php
require_once __DIR__ . '/../../connect.php';

$id = filterRequest("id");

// تهيئة المتغيرات
$columnValues = [];
$params = [];

// التعامل مع كل حقل ديناميكيًا
if (isset($_POST["driverID"])) {
    $columnValues[] = "`driverID` = :driverID";
    $params[':driverID'] = filterRequest("driverID");
}

if (isset($_POST["passengerID"])) {
    $columnValues[] = "`passengerID` = :passengerID";
    $params[':passengerID'] = filterRequest("passengerID");
}

if (isset($_POST["rideID"])) {
    $columnValues[] = "`rideID` = :rideID";
    $params[':rideID'] = filterRequest("rideID");
}

if (isset($_POST["note"])) {
    $columnValues[] = "`note` = :note";
    $params[':note'] = filterRequest("note");
}

// تأكد من وجود بيانات لتحديثها
if (empty($columnValues)) {
    jsonError("No data provided to update");
    exit;
}

// بناء الاستعلام النهائي
$setClause = implode(", ", $columnValues);
$sql = "UPDATE `canecl` SET $setClause WHERE `id` = :id";
$params[':id'] = $id;

// تنفيذ الاستعلام
$stmt = $con->prepare($sql);
$stmt->execute($params);

// التحقق من النتيجة
if ($stmt->rowCount() > 0) {
    jsonSuccess(null, "Data updated successfully");
} else {
    jsonError("Failed to update data or no changes made");
}
?>

File: ride/cancelRide/get.php

<?php
require_once __DIR__ . '/../../connect.php';

$sql = "SELECT * FROM `canecl`";
$stmt = $con->prepare($sql);
$stmt->execute();

$result = $stmt->fetchAll(PDO::FETCH_ASSOC);

if ($stmt->rowCount() > 0) {
    jsonSuccess($result);
} else {
    jsonError("No records found");
}
?>

File: ride/cancelRide/addCancelTripFromDriverAfterApplied.php

<?php
/*
require_once __DIR__ . '/../../connect.php';

// 🚀 تسجيل بداية العملية المدمجة
error_log("🚀 [cancelRideAndLog.php] Request Started: Cancel Ride + Log Driver Action.");

// 1. استقبال كافة البيانات المطلوبة للعمليتين
$rideId   = filterRequest("id");       // معرف الرحلة
$driverID = filterRequest("driver_id");// معرف السائق
$note     = filterRequest("notes");    // ملاحظات الإلغاء

// التحقق من البيانات الأساسية
if (!$rideId || !$driverID) {
    error_log("❌ [cancelRideAndLog.php] Missing ID or Driver ID.");
    jsonError("Missing Required Data (id or driver_id)");
    exit;
}

// إعدادات عملية الإلغاء
$newStatus = "cancelRideFromDriver"; 
// الحالات المسموح بالإلغاء فيها (تأكد من مطابقتها لقاعدة البيانات)
$allowedStatuses = "'wait', 'waiting', 'Apply'"; 

$sqlCancel = "UPDATE `ride` 
              SET `status` = '$newStatus', `updated_at` = CURRENT_TIMESTAMP 
              WHERE `id` = :id 
              AND `status` IN ($allowedStatuses)";

$params = [':id' => $rideId];

try {
    // =================================================================================
    // المرحلة الأولى: إلغاء الرحلة (نفس منطق السكريبت الأول)
    // =================================================================================
    
    // 1. التحديث على سيرفر التتبع (Remote DB)
    error_log("🔄 [Step 1] Attempting to cancel on REMOTE Tracking DB...");
    $stmtRemote = $con_ride->prepare($sqlCancel);
    $stmtRemote->execute($params);
    $count = $stmtRemote->rowCount();

    // إذا نجح التحديث في السيرفر البعيد (أو لم ينجح نتحقق من المحلي أيضا لضمان التزامن)
    // لكن المنطق الأساسي يعتمد على أن الرحلة قابلة للتعديل
    if ($count > 0) {
        
        // 2. التحديث على السيرفر المحلي (Local DB)
        error_log("🔄 [Step 1] Remote success. Cancelling on LOCAL Main DB...");
        $stmtLocal = $con->prepare($sqlCancel);
        $stmtLocal->execute($params);
        
        error_log("✅ [Step 1] Ride cancelled successfully on database.");

        // =================================================================================
        // المرحلة الثانية: تسجيل الطلب وتنظيف البيانات (نفس منطق السكريبت الثاني)
        // لن يتم الدخول هنا إلا إذا نجح الإلغاء فعلياً
        // =================================================================================
        
        error_log("🔄 [Step 2] Inserting into driver_orders and cleaning background tasks...");

        // أ. إضافة سجل في driver_orders
        $orderStatus = 'pending'; // كما في السكريبت الثاني
        $sqlInsertOrder = "INSERT INTO driver_orders (driver_id, order_id, notes, status) 
                           VALUES (?, ?, ?, ?)";
        $stmtInsert = $con->prepare($sqlInsertOrder);
        $stmtInsert->execute([$driverID, $rideId, $note, $orderStatus]);

        // ب. حذف آخر سجل من write_argument_after_applied_from_background
        // نستخدم نفس الاستعلام الفرعي الذي كنت تستخدمه
        $sqlDelete = "DELETE FROM write_argument_after_applied_from_background
                      WHERE id = (
                          SELECT id FROM (
                              SELECT id 
                              FROM write_argument_after_applied_from_background
                              WHERE driver_id = ?
                              ORDER BY time_of_order DESC
                              LIMIT 1
                          ) AS t
                      )";
        $stmtDelete = $con->prepare($sqlDelete);
        $stmtDelete->execute([$driverID]);

        error_log("✅ [Step 2] Driver order logged and background task cleaned.");

        // =================================================================================
        // النهاية: إرجاع رسالة النجاح
        // =================================================================================
        jsonSuccess(null, "Ride cancelled and driver log updated successfully");

    } else {
        // فشل الإلغاء (الرحلة غير موجودة أو حالتها لا تسمح)
        error_log("⚠️ [cancelRideAndLog.php] Failed to cancel. Status might be started/completed or ID invalid.");
        jsonError("Cannot cancel ride. Status might be started or already completed.");
    }

} catch (PDOException $e) {
    error_log("❌ [cancelRideAndLog.php] Database Error: " . $e->getMessage());
    jsonError("Database Error: " . $e->getMessage());
*/

require_once __DIR__ . '/../../connect.php'; 

$rideId   = filterRequest("id");
$driverID = filterRequest("driver_id");
$note     = filterRequest("notes");
$status   = "cancelRideFromDriver"; 

if (!$rideId || !$driverID) {
    jsonError("Missing Data");
    exit;
}

try {
    // 1. محاولة الإلغاء في السيرفر البعيد
    $stmtRemote = $con_ride->prepare("UPDATE `ride` SET `status` = ?, `updated_at` = NOW() WHERE `id` = ? AND `status` IN ('wait', 'waiting', 'Apply', 'accepted')");
    $stmtRemote->execute([$status, $rideId]);
    
    if ($stmtRemote->rowCount() > 0) {
        // 2. التحديث المحلي
        $con->prepare("UPDATE `ride` SET `status` = ?, `updated_at` = NOW() WHERE `id` = ?")->execute([$status, $rideId]);
        
        // 3. تسجيل اللوج (كما في ملفك)
        $con->prepare("INSERT INTO driver_orders (driver_id, order_id, notes, status) VALUES (?, ?, ?, 'pending')")->execute([$driverID, $rideId, $note]);
        
        // تنظيف الخلفية (اختياري حسب الحاجة)
        // ... كود التنظيف ...

        // 4. 🔥 إشعار الراكب بالإلغاء 🔥
        $stmtPas = $con->prepare("SELECT passenger_id FROM ride WHERE id = ?");
        $stmtPas->execute([$rideId]);
        $passenger_id = $stmtPas->fetchColumn();

        if ($passenger_id) {
            notifyPassengerOnRideServer($passenger_id, [
                'ride_id' => $rideId,
                'status'  => 'cancelled',
                'msg'     => 'نعتذر، قام السائق بإلغاء الرحلة'
            ]);
        }

        jsonSuccess(null, "Ride Cancelled");
    } else {
        jsonError("Cannot cancel ride (Status might be started or finished)");
    }

} catch (PDOException $e) {
    jsonError("DB Error: " . $e->getMessage());
}
?>
?>

File: ride/cancelRide/delete.php

<?php
require_once __DIR__ . '/../../connect.php';

$id = filterRequest("id");

$sql = "DELETE FROM `canecl` WHERE `id` = :id";
$stmt = $con->prepare($sql);
$stmt->bindParam(":id", $id, PDO::PARAM_INT); // تأكيد أن id رقم
$stmt->execute();

if ($stmt->rowCount() > 0) {
    jsonSuccess(null, "Record deleted successfully");
} else {
    jsonError("Failed to delete record");
}
?>

File: ride/helpCenter/add.php

<?php

require_once __DIR__ . '/../../connect.php';

$driverID      = filterRequest("driverID");
$helpQuestion  = filterRequest("helpQuestion");

$sql = "INSERT INTO `helpCenter` (`driverID`, `helpQuestion`) VALUES (:driverID, :helpQuestion)";
$stmt = $con->prepare($sql);
$stmt->bindParam(':driverID', $driverID);
$stmt->bindParam(':helpQuestion', $helpQuestion);
$stmt->execute();

if ($stmt->rowCount() > 0) {
    jsonSuccess(null, "Help question saved successfully");
} else {
    jsonError("Failed to save help question");
}
?>

File: ride/helpCenter/update.php

<?php

require_once __DIR__ . '/../../connect.php';

$helpID = filterRequest("id");
$newHelpQuestion = filterRequest("newHelpQuestion");

$sql = "UPDATE `helpCenter` SET `helpQuestion` = :helpQuestion WHERE `id` = :id";
$stmt = $con->prepare($sql);
$stmt->bindParam(':helpQuestion', $newHelpQuestion);
$stmt->bindParam(':id', $helpID, PDO::PARAM_INT);
$stmt->execute();

if ($stmt->rowCount() > 0) {
    jsonSuccess(null, "Help question updated successfully");
} else {
    jsonError("Failed to update help question");
}
?>

File: ride/helpCenter/get.php

<?php
require_once __DIR__ . '/../../connect.php';

$driverID = filterRequest("driverID");

$sql = "SELECT
    `id`,
    `driverID`,
    `helpQuestion`,
    `datecreated`
FROM
    `helpCenter`
WHERE
    `driverID` = :driverID
ORDER BY
    `datecreated` DESC";

$stmt = $con->prepare($sql);
$stmt->bindParam(':driverID', $driverID, PDO::PARAM_STR);
$stmt->execute();

if ($stmt->rowCount() > 0) {
    $record = $stmt->fetchAll(PDO::FETCH_ASSOC);
    jsonSuccess($record);
} else {
    jsonError("Help question not found");
}
?>

File: ride/helpCenter/getById.php

<?php

require_once __DIR__ . '/../../connect.php';

$helpID = filterRequest("id");

$sql = "SELECT * FROM `helpCenter` WHERE `id` = :id";
$stmt = $con->prepare($sql);
$stmt->bindParam(':id', $helpID, PDO::PARAM_INT);
$stmt->execute();

if ($stmt->rowCount() > 0) {
    $record = $stmt->fetch(PDO::FETCH_ASSOC);
    jsonSuccess($record);
} else {
    jsonError("Help question not found");
}
?>

File: ride/helpCenter/delete.php

<?php

require_once __DIR__ . '/../../connect.php';

$helpID = filterRequest("id");

$sql = "DELETE FROM `helpCenter` WHERE `id` = :id";
$stmt = $con->prepare($sql);
$stmt->bindParam(':id', $helpID, PDO::PARAM_INT);
$stmt->execute();

if ($stmt->rowCount() > 0) {
    jsonSuccess(null, "Help question deleted successfully");
} else {
    jsonError("Failed to delete help question");
}
?>

File: ride/feedBack/add.php

<?php
require_once __DIR__ . '/../../connect.php';

$passengerId = filterRequest("passengerId");
$feedBack = filterRequest("feedBack");

$feedBack = $encryptionHelper->encryptData($feedBack);

$sql = "INSERT INTO `feedBack`( `passengerId`, `feedBack`, `datecreated`) VALUES (
  
  :passengerId,
  :feedBack,
  NOW()
)";

$stmt = $con->prepare($sql);
$stmt->bindParam(':passengerId', $passengerId);
$stmt->bindParam(':feedBack', $feedBack);
$stmt->execute();


if ($stmt->rowCount() > 0) {
    // Success response
    echo json_encode([
        "status" => "success",
        "message" => "Feedback data saved successfully"
    ]);
} else {
    // Failure response
    echo json_encode([
        "status" => "failure",
        "message" => "Failed to save feedback data"
    ]);
}
?>

File: ride/feedBack/update.php


File: ride/feedBack/get.php

<?php
require_once __DIR__ . '/../../connect.php';


$passengerId = filterRequest("passengerId"); 

$sql = "SELECT
    r.id AS id,
    r.start_location,
    r.end_location,
    r.date,
    r.price,
    r.status,
    r.paymentMethod,
    r.distance,
    r.carType,
    r.rideTimeFinish,
    r.rideTimeStart,
    r.DriverIsGoingToPassenger,
    COUNT(rp.id) AS countRateFromPassengerToDrivers,
    COUNT(rd.id) AS countRateFromDriverToPassengers,
    MAX(rp.rating) AS rateFromPassengerToDriver,
    MAX(rd.rating) AS rateFromDriversToPassengers,
    MAX(rp.comment) AS commentFromPassengerToDriver,
    MAX(rd.comment) AS commentFromDriverToPassenger
FROM
    ride r
LEFT JOIN ratingPassenger rp ON
    rp.passenger_id = r.passenger_id
LEFT JOIN ratingDriver rd ON
    rd.driver_id = r.driver_id
WHERE
    r.passenger_id = :passengerId
GROUP BY
    r.id,
    r.start_location,
    r.end_location,
    r.date,
    r.price,
    r.status,
    r.paymentMethod,
    r.distance,
    r.carType,
    r.rideTimeFinish,
    r.rideTimeStart,
    r.DriverIsGoingToPassenger
ORDER BY
    r.date
DESC
LIMIT 1;
    ";

$stmt = $con->prepare($sql);
$stmt->bindParam(':passengerId', $passengerId, PDO::PARAM_STR);
$stmt->execute();
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);

if ($result) {
    // Print all promo records
    jsonSuccess($result);
} else {
    // Print a failure message
    jsonError($message = "Failed to retrieve promo records");
   
}
?>

File: ride/feedBack/delete.php


File: ride/feedBack/add_solve_all.php

<?php
// --- معالجة الشكوى من جهة الخادم (Backend) ---

// 1. تضمين ملف الاتصال والدوال المساعدة
// ! تأكد من أن هذا المسار صحيح بالنسبة لهيكل مشروعك
require_once __DIR__ . '/../../connect.php';

// --- إعدادات النظام ---
$geminiApiKey = getenv("GEMINI_API_KEY");
$customerServiceWhatsapp = getenv("SERVICE_PHONE1"); // يُفترض أن هذا مُعرّف في connect.php أو متغيرات البيئة

// التحقق من وجود مفتاح Gemini API
if (!$geminiApiKey) {
    error_log("CRITICAL: Gemini API Key is not configured on the server."); // ⚠️ تسجيل الخطأ
    jsonError("Gemini API Key is not configured on the server.");
    exit;
}

// --- 2. استقبال البيانات والتحقق منها ---
$rideId = filterRequest("ride_id");
$complaintText = filterRequest("complaint_text");
$audioLink = filterRequest("audio_link");

if (empty($rideId)) {
    error_log("WARNING: Complaint request failed. Ride ID is missing."); // ⚠️ تسجيل الخطأ
    jsonError("Ride ID is required.");
    exit;
}

// --- 3. جلب البيانات المفصلة من قاعدة البيانات ---
global $con, $encryptionHelper; // تم افتراض أن هذه المتغيرات global ومتاحة في هذا النطاق

// جلب تفاصيل الرحلة الأساسية والتحقق من حالتها
$stmt = $con->prepare("SELECT * FROM ride WHERE id = ? AND (status = 'Finished' OR status = 'Begin')");
$stmt->execute([$rideId]);
$ride = $stmt->fetch(PDO::FETCH_ASSOC);


if (!$ride) {
    // رسالة خطأ أوضح للمستخدم
    error_log("WARNING: Complaint filing failed for ride ID: $rideId. Ride not found or status is invalid."); // ⚠️ تسجيل الخطأ
    jsonError("Complaint cannot be filed for this ride. It may not have been completed or started.");
    exit;
}

$passengerId = $ride['passenger_id'];
$driverId = $ride['driver_id'];

// --- دوال مساعدة لجلب البيانات (تم افتراض أن الدوال تصل إلى $con و $encryptionHelper عبر النطاق global أو تمريرها كـ arguments) ---

/**
 * جلب بيانات ومعلومات تقييم السائق
 */
function getDriverFullProfile($con, $encryptionHelper, $driverId) {
    $profile = ['info' => null, 'ratings' => null, 'comments' => []];
    
    // جلب معلومات السائق الأساسية
    $stmt = $con->prepare("SELECT id, first_name, last_name, created_at FROM driver WHERE id = ?");
    $stmt->execute([$driverId]);
    $driverInfo = $stmt->fetch(PDO::FETCH_ASSOC);

    // فك تشفير البيانات الحساسة
    if ($driverInfo) {
        // التحقق من وجود ودوال فك التشفير قبل الاستخدام
        if (isset($encryptionHelper) && method_exists($encryptionHelper, 'decryptData')) {
             $decryptedFirstName = $encryptionHelper->decryptData($driverInfo['first_name']);
             $decryptedLastName = $encryptionHelper->decryptData($driverInfo['last_name']);
             $driverInfo['full_name'] = trim($decryptedFirstName . ' ' . $decryptedLastName);
        } else {
             $driverInfo['full_name'] = 'Decryption Failed';
        }
        
        unset($driverInfo['first_name'], $driverInfo['last_name']); // إزالة الحقول المشفرة
        $profile['info'] = $driverInfo;
    }

    // جلب ملخص التقييمات والتعليقات
    $stmt = $con->prepare("SELECT AVG(rating) as avg_rating, COUNT(id) as total_ratings FROM ratingDriver WHERE driver_id = ?");
    $stmt->execute([$driverId]);
    $profile['ratings'] = $stmt->fetch(PDO::FETCH_ASSOC);

    $stmt = $con->prepare("SELECT comment FROM ratingDriver WHERE driver_id = ? AND comment IS NOT NULL AND comment != '' ORDER BY created_at DESC LIMIT 5");
    $stmt->execute([$driverId]);
    $profile['comments'] = $stmt->fetchAll(PDO::FETCH_COLUMN);
    
    return $profile;
}

/**
 * جلب بيانات ومعلومات تقييم الراكب
 */
function getPassengerFullProfile($con, $encryptionHelper, $passengerId) {
    $profile = ['info' => null, 'ratings' => null, 'comments' => []];

    $stmt = $con->prepare("SELECT id, first_name, last_name, created_at FROM passengers WHERE id = ?");
    $stmt->execute([$passengerId]);
    $passengerInfo = $stmt->fetch(PDO::FETCH_ASSOC);

    // فك تشفير البيانات الحساسة
    if ($passengerInfo) {
        if (isset($encryptionHelper) && method_exists($encryptionHelper, 'decryptData')) {
            $decryptedFirstName = $encryptionHelper->decryptData($passengerInfo['first_name']);
            $decryptedLastName = $encryptionHelper->decryptData($passengerInfo['last_name']);
            $passengerInfo['full_name'] = trim($decryptedFirstName . ' ' . $decryptedLastName);
        } else {
             $passengerInfo['full_name'] = 'Decryption Failed';
        }
        
        unset($passengerInfo['first_name'], $passengerInfo['last_name']);
        $profile['info'] = $passengerInfo;
    }

    $stmt = $con->prepare("SELECT AVG(rating) as avg_rating, COUNT(id) as total_ratings FROM ratingPassenger WHERE passenger_id = ?");
    $stmt->execute([$passengerId]);
    $profile['ratings'] = $stmt->fetch(PDO::FETCH_ASSOC);
    
    $stmt = $con->prepare("SELECT comment FROM ratingPassenger WHERE passenger_id = ? AND comment IS NOT NULL AND comment != '' ORDER BY created_at DESC LIMIT 5");
    $stmt->execute([$passengerId]);
    $profile['comments'] = $stmt->fetchAll(PDO::FETCH_COLUMN);

    return $profile;
}

/**
 * جلب بيانات سلوك السائق في الرحلة المحددة
 */
function getDriverBehavior($con, $rideId, $driverId) {
    $stmt = $con->prepare("SELECT max_speed, avg_speed, hard_brakes, behavior_score FROM driver_behavior WHERE trip_id = ? AND driver_id = ?");
    $stmt->execute([$rideId, $driverId]);
    return $stmt->fetch(PDO::FETCH_ASSOC) ?: null;
}

// استدعاء الدوال لجلب البيانات
$passengerProfile = getPassengerFullProfile($con, $encryptionHelper, $passengerId);
$driverProfile = getDriverFullProfile($con, $encryptionHelper, $driverId);
$driverBehavior = getDriverBehavior($con, $rideId, $driverId);

// --- 4. بناء الـ Prompt وإرساله إلى Gemini ---
$prompt = "
أنت خبير في حل النزاعات في خدمات نقل الركاب لتطبيق intaleqapp.com. قم بتحليل الشكوى التالية بين راكب وسائق بناءً على البيانات الشاملة التالية:

**1. تفاصيل الرحلة:**
" . json_encode($ride, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) . "

**2. ملف الراكب:**
" . json_encode($passengerProfile, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) . "

**3. ملف السائق:**
" . json_encode($driverProfile, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) . "

**4. بيانات سلوك السائق (في هذه الرحلة):**
" . json_encode($driverBehavior, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) . "

**5. الشكوى نفسها:**
- نص الشكوى من الراكب: '" . $complaintText . "'
- رابط تسجيل صوتي للشكوى (إن وجد): " . $audioLink . "

**مهمتك هي:**
1. تحليل جميع البيانات المتاحة لتحديد الطرف المخطئ على الأرجح.
2. تحديد ما إذا كانت الشكوى كيدية أم حقيقية.
3. **تصنيف الشكوى** (مثال: سلوك السائق، مشكلة في الأجرة، مسار الرحلة، حالة السيارة، أخرى).
4. اقتراح حلين واضحين ومختلفين لفريق خدمة العملاء.
5. كتابة تقرير موجز ومناسب للراكب.
6. كتابة تقرير موجز ومناسب للسائق.

**الخرج المطلوب:**
أعد الرد بصيغة JSON فقط، بدون أي نصوص إضافية، وباللغة العربية (لهجة مصرية)، بالهيكل التالي:
{
  \"customerServiceSolutions\": [\"الحل المقترح الأول\", \"الحل المقترح الثاني\"],
  \"passengerReport\": { \"title\": \"بخصوص شكوتك في رحلة Siro\", \"body\": \"رسالة واضحة للراكب بنتيجة الشكوى\" },
  \"driverReport\": { \"title\": \"بخصوص بلاغ رحلتك الأخيرة في Siro\", \"body\": \"رسالة واضحة للسائق بنتيجة الشكوى\" },
  \"fault_determination\": \"الطرف المخطئ (الراكب/السائق/كلاهما/غير واضح)\",
  \"complaint_nature\": \"طبيعة الشكوى (حقيقية/كيدية/نزاع بسيط)\",
  \"complaint_type\": \"تصنيف الشكوى الذي حددته\"
}
";

// استخدام نموذج Gemini 1.5 Flash Lite
$apiURL = "https://generativelanguage.googleapis.com/v1beta/models/gemini-flash-lite-latest:generateContent?key=$geminiApiKey";
$headers = ["Content-Type: application/json"];
$payload = ['contents' => [['parts' => [['text' => $prompt]]]]];

error_log("INFO: Submitting complaint analysis to Gemini for ride ID: $rideId."); //  تسجيل الحدث

$ch = curl_init($apiURL);
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST => true,
    CURLOPT_HTTPHEADER => $headers,
    CURLOPT_POSTFIELDS => json_encode($payload),
    CURLOPT_TIMEOUT => 60
]);
$response = curl_exec($ch);

if (curl_errno($ch)) {
    $errorMsg = curl_error($ch);
    error_log("ERROR: AI Service Curl Error for ride $rideId: $errorMsg"); // ⚠️ تسجيل الخطأ
    jsonError("AI Service Error: " . $errorMsg);
    curl_close($ch);
    exit;
}
curl_close($ch);

$data = json_decode($response, true);
$analysisResultText = $data['candidates'][0]['content']['parts'][0]['text'] ?? '';
$analysisResultJson = trim(preg_replace('/```json|```/', '', $analysisResultText));
$analysisResult = json_decode($analysisResultJson, true);

if (json_last_error() !== JSON_ERROR_NONE || !isset($analysisResult['passengerReport']) || !isset($analysisResult['driverReport'])) {
    error_log("ERROR: Failed to parse AI response for ride $rideId. Raw Response: " . substr($response, 0, 500)); // ⚠️ تسجيل الخطأ
    jsonError("Failed to parse AI response. Please try again later.");
    exit;
}

error_log("INFO: Gemini analysis successful for ride $rideId. Type: " . ($analysisResult['complaint_type'] ?? 'N/A')); //  تسجيل الحدث

// --- 5. تنفيذ الإجراءات بناءً على التحليل ---

// تجميع الوصف الكامل للشكوى
$fullDescription = $complaintText;
if (!empty($audioLink)) {
    $fullDescription .= "\n\n[رابط صوتي مرفق: " . $audioLink . "]";
}

// ** التعديل: تم تحديث جملة الحفظ لتشمل جميع مخرجات التحليل **
$stmt = $con->prepare("
    INSERT INTO complaint (
        ride_id, passenger_id, driver_id, complaint_type, description, 
        date_filed, statusComplaint, resolution, passenger_report, driver_report, 
        cs_solutions, fault_determination, complaint_nature, date_resolved
    ) 
    VALUES (?, ?, ?, ?, ?, NOW(), ?, ?, ?, ?, ?, ?, ?, NOW())
");

try {
    $success = $stmt->execute([
        $rideId, 
        $passengerId, 
        $driverId, 
        $analysisResult['complaint_type'] ?? 'General',
        $fullDescription,
        'Resolved', // statusComplaint
        $analysisResultJson, // resolution (الـ JSON الكامل)
        json_encode($analysisResult['passengerReport'] ?? null, JSON_UNESCAPED_UNICODE), // passenger_report
        json_encode($analysisResult['driverReport'] ?? null, JSON_UNESCAPED_UNICODE), // driver_report
        json_encode($analysisResult['customerServiceSolutions'] ?? null, JSON_UNESCAPED_UNICODE), // cs_solutions
        $analysisResult['fault_determination'] ?? 'N/A', // fault_determination
        $analysisResult['complaint_nature'] ?? 'N/A' // complaint_nature
    ]);

    if (!$success) {
        // يمكنك تسجيل رسالة الخطأ من PDO إذا كانت متاحة (للتصحيح فقط وليس للإنتاج)
        error_log("CRITICAL: Failed to save complaint to DB for ride $rideId. PDO Error Info: " . json_encode($stmt->errorInfo())); // ⚠️ تسجيل الخطأ
    }

    $complaintId = $con->lastInsertId();
    error_log("SUCCESS: Complaint ID $complaintId processed and saved for ride $rideId."); // ✅ تسجيل النجاح

} catch (PDOException $e) {
    error_log("CRITICAL: PDO Exception when saving complaint for ride $rideId: " . $e->getMessage()); // ⚠️ تسجيل خطأ قاعدة البيانات
    jsonError("A database error occurred while saving the complaint.");
    exit;
}

// إرسال رسالة WhatsApp لخدمة العملاء
if (function_exists('sendWhatsAppFromServer') && !empty($customerServiceWhatsapp)) {
    $csMessage = "*شكوى جديدة (رقم $complaintId)*\n" .
                "*- الرحلة:* $rideId\n" .
                "*- تصنيف الشكوى:* " . ($analysisResult['complaint_type'] ?? 'غير محدد') . "\n" .
                "*- المخطئ (تقدير النظام):* " . $analysisResult['fault_determination'] . "\n" .
                "*- طبيعة الشكوى:* " . $analysisResult['complaint_nature'] . "\n\n" .
                "*حلول مقترحة:*\n1. " . ($analysisResult['customerServiceSolutions'][0] ?? 'N/A') . "\n" .
                "2. " . ($analysisResult['customerServiceSolutions'][1] ?? 'N/A');
    sendWhatsAppFromServer($customerServiceWhatsapp, $csMessage);
    error_log("INFO: WhatsApp notification sent to customer service for complaint ID $complaintId."); //  تسجيل الحدث
}


// --- 6. إرسال الرد النهائي للتطبيق ---
printSuccess([
    'message' => 'Complaint processed successfully.',
    'passenger_response' => $analysisResult['passengerReport'],
    'driver_response' => $analysisResult['driverReport']
]);

?>

File: ride/driverPayment/add.php

<?php
require_once __DIR__ . '/../../connect.php';

$amount = filterRequest("amount");
$paymentMethod = filterRequest("payment_method");
$driverID = filterRequest("driverID");

$sql = "INSERT INTO `paymentsDriverPoints` (`amount`, `payment_method`, `driverID`) 
        VALUES ('$amount', '$paymentMethod', '$driverID')";

$stmt = $con->prepare($sql);
$stmt->execute();

if ($stmt->rowCount() > 0) {
    
    $insertedID = $con->lastInsertId(); // Get the last inserted ID
    jsonSuccess($message =  $insertedID);
} else {
    $response = array(
        "success" => false,
        "message" => "Failed to save payment data"
    );
    echo json_encode($response);
}
?>

File: ride/driverPayment/update.php

<?php
require_once __DIR__ . '/../../connect.php';

$id = filterRequest("id");
$amount = filterRequest("amount");
$paymentMethod = filterRequest("paymentMethod");
$driverID = filterRequest("driverID");

$sql = "UPDATE `paymentsDriverPoints` SET `amount` = '$amount', `payment_method` = '$paymentMethod', 
        `driverID` = '$driverID' WHERE `id` = '$id'";

$stmt = $con->prepare($sql);
$stmt->execute();

if ($stmt->rowCount() > 0) {
    // Print a success message
    echo "Record updated successfully";
} else {
    // Print a failure message
    echo "Failed to update the record";
}
?>

File: ride/driverPayment/get.php

<?php
require_once __DIR__ . '/../../connect.php';

$sql = "SELECT `id`, `amount`, `payment_method`, `driverID`, `created_at`, `updated_at` 
        FROM `paymentsDriverPoints`";

$stmt = $con->prepare($sql);
$stmt->execute();

if ($stmt->rowCount() > 0) {
    // Fetch the record
    $row = $stmt->fetchAll(PDO::FETCH_ASSOC);

    jsonSuccess($row);
    
} else {
    // No records found
    echo "No records found.";
}
?>

File: ride/driverPayment/delete.php

<?php
require_once __DIR__ . '/../../connect.php';

$id = filterRequest("id");

$sql = "DELETE FROM `paymentsDriverPoints` WHERE `id` = '$id'";

$stmt = $con->prepare($sql);
$stmt->execute();

if ($stmt->rowCount() > 0) {
    // Print a success message
    echo "Record deleted successfully";
} else {
    // Print a failure message
    echo "Failed to delete the record";
}
?>

File: ride/kazan/add.php

<?php
require_once __DIR__ . '/../../connect.php';

$kazan = filterRequest("kazan");
$adminId = filterRequest("adminId");
$latePrice = filterRequest("latePrice");
$heavyPrice = filterRequest("heavyPrice");
$naturePrice = filterRequest("naturePrice");
$comfortPrice = filterRequest("comfortPrice");
$speedPrice = filterRequest("speedPrice");
$deliveryPrice = filterRequest("deliveryPrice");
$freePrice = filterRequest("freePrice");
$country = filterRequest("country");
$fuelPrice = filterRequest("fuelPrice");

// Prepare an SQL statement with placeholders for the values
$sql = "INSERT INTO `kazan`( `country`,`kazan`, `comfortPrice`, `speedPrice`, `deliveryPrice`, `freePrice`, `latePrice`, `heavyPrice`, `adminId`, `naturePrice`, `fuelPrice`) VALUES (:country,:kazan, :comfortPrice, :speedPrice, :deliveryPrice, :freePrice, :latePrice, :heavyPrice, :adminId, :naturePrice,:fuelPrice)";

$stmt = $con->prepare($sql);

// Bind the parameters to the SQL query
$stmt->bindParam(':kazan', $kazan);
$stmt->bindParam(':comfortPrice', $comfortPrice);
$stmt->bindParam(':speedPrice', $speedPrice);
$stmt->bindParam(':deliveryPrice', $deliveryPrice);
$stmt->bindParam(':freePrice', $freePrice);
$stmt->bindParam(':latePrice', $latePrice);
$stmt->bindParam(':heavyPrice', $heavyPrice);
$stmt->bindParam(':adminId', $adminId);
$stmt->bindParam(':naturePrice', $naturePrice);
$stmt->bindParam(':country', $country);
$stmt->bindParam(':fuelPrice', $fuelPrice);

// Execute the statement
if ($stmt->execute()) {
    // Print a success message
    jsonSuccess(null, "Kazan saved successfully");
} else {
    // Print a failure message
    jsonError("Failed to save Kazan");
}

// Close the statement
$stmt->close();
?>

File: ride/kazan/update.php

<?php
require_once __DIR__ . '/../../connect.php';

$id = filterRequest("id");

$allowedFields = [
    "kazan", "comfortPrice", "speedPrice", "deliveryPrice",
    "freePrice", "latePrice", "heavyPrice", "adminId", "createdAt", "naturePrice"
];

$setParts = [];
$params = [];

foreach ($allowedFields as $field) {
    if (isset($_POST[$field])) {
        $value = filterRequest($field);
        $setParts[] = "`$field` = :$field";
        $params[":$field"] = $value;
    }
}

if (empty($setParts)) {
    jsonError("No valid fields to update.");
    exit;
}

$sql = "UPDATE `kazan` SET " . implode(", ", $setParts) . " WHERE `id` = :id";
$params[":id"] = $id;

$stmt = $con->prepare($sql);
$stmt->execute($params);

if ($stmt->rowCount() > 0) {
    jsonSuccess(null, "Kazan data updated successfully");
} else {
    jsonError("Failed to update kazan data");
}
?>

File: ride/kazan/get.php

<?php
require_once __DIR__ . '/../../connect.php';

$country = filterRequest("country");

$sql = "SELECT * FROM `kazan` WHERE `country` = :country";
$stmt = $con->prepare($sql);
$stmt->bindParam(':country', $country, PDO::PARAM_STR);
$stmt->execute();

$row = $stmt->fetchAll(PDO::FETCH_ASSOC);

if ($row) {
    jsonSuccess($row);
} else {
    jsonError("No Kazan record found");
}
?>

File: ride/kazan/delete.php


File: ride/apiKey/add.php


File: ride/apiKey/update.php


File: ride/apiKey/get.php

<?php

require_once __DIR__ . '/../../connect.php';

// Load the .env file and set environment variables
$env_file = __DIR__ . '/../../.env'; // Ensure the .env file exists and is named correctly
if (file_exists($env_file)) {
    $lines = file($env_file, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
    foreach ($lines as $line) {
        if (strpos(trim($line), '#') === 0) {
            continue; // Skip comments
        }
        putenv(trim($line));
    }
}

// Get the specific key name from the request
$keyName = filterRequest('keyName');

// Fetch the specific environment variable
$envValue = getenv($keyName);

// Include the specific environment key in the output
$output = [];
if ($keyName && $envValue !== false) {
    $output[$keyName] = $envValue;
    jsonSuccess($output);
} else {
    $apiKeys = getApiKeys($con);
    if ($apiKeys) {
        jsonSuccess($apiKeys);
    } else {
        jsonError("No records found or invalid key name");
    }
}

function getApiKeys($con) {
    $sql = "SELECT `id`, `name`, `hashed_key` FROM `api_keys`";

    $stmt = $con->prepare($sql);
    $stmt->execute();
    $result = $stmt->fetchAll(PDO::FETCH_ASSOC);

    return $result;
}


?>

File: ride/apiKey/delete.php


File: ride/firebase/addToken.php

<?php

require_once __DIR__ . '/../../connect.php';

// استقبال المتغيرات
$token        = filterRequest("token");         // نص عادي ➜ سيتم تشفيره
$passengerID  = filterRequest("passengerID");   // ID عادي
$fingerPrint  = filterRequest("fingerPrint");   // مشفّر مسبقًا من Flutter ➜ لا يتم تشفيره هنا

// تشفير التوكن فقط
$tokenEncrypted = $encryptionHelper->encryptData($token);

// التحقق مما إذا كان السجل موجودًا
$sqlCheck = "SELECT * FROM `tokens` WHERE `passengerID` = :passengerID";
$stmtCheck = $con->prepare($sqlCheck);
$stmtCheck->bindParam(':passengerID', $passengerID);
$stmtCheck->execute();

$result = $stmtCheck->fetch(PDO::FETCH_ASSOC);

if ($result) {
    // تحديث السجل الموجود
    $sqlUpdate = "UPDATE `tokens` SET `token` = :token, `fingerPrint` = :fingerPrint WHERE `passengerID` = :passengerID";
    $stmtUpdate = $con->prepare($sqlUpdate);
    $stmtUpdate->bindParam(':token', $tokenEncrypted);
    $stmtUpdate->bindParam(':fingerPrint', $fingerPrint); // بدون تشفير إضافي
    $stmtUpdate->bindParam(':passengerID', $passengerID);
    $stmtUpdate->execute();

    jsonSuccess(null, "Token updated successfully");

} else {
    // إدخال سجل جديد
    $sqlInsert = "INSERT INTO `tokens` (`token`, `passengerID`, `fingerPrint`) VALUES (:token, :passengerID, :fingerPrint)";
    $stmtInsert = $con->prepare($sqlInsert);
    $stmtInsert->bindParam(':token', $tokenEncrypted);
    $stmtInsert->bindParam(':passengerID', $passengerID);
    $stmtInsert->bindParam(':fingerPrint', $fingerPrint); // بدون تشفير إضافي
    $stmtInsert->execute();

    if ($stmtInsert->rowCount() > 0) {
        jsonSuccess(null, "Token inserted successfully");
    } else {
        jsonError("Failed to insert token");
    }
}
?>

File: ride/firebase/add.php

<?php

require_once __DIR__ . '/../../connect.php';

// استقبال المتغيرات
$token        = filterRequest("token");         // نص عادي ➜ سيتم تشفيره
$passengerID  = filterRequest("passengerID");   // ID عادي
$fingerPrint  = filterRequest("fingerPrint");   // مشفّر مسبقًا من Flutter ➜ لا يتم تشفيره هنا

// تشفير التوكن فقط
$tokenEncrypted = $encryptionHelper->encryptData($token);

// التحقق مما إذا كان السجل موجودًا
$sqlCheck = "SELECT * FROM `tokens` WHERE `passengerID` = :passengerID";
$stmtCheck = $con->prepare($sqlCheck);
$stmtCheck->bindParam(':passengerID', $passengerID);
$stmtCheck->execute();

$result = $stmtCheck->fetch(PDO::FETCH_ASSOC);

if ($result) {
    // تحديث السجل الموجود
    $sqlUpdate = "UPDATE `tokens` SET `token` = :token, `fingerPrint` = :fingerPrint WHERE `passengerID` = :passengerID";
    $stmtUpdate = $con->prepare($sqlUpdate);
    $stmtUpdate->bindParam(':token', $tokenEncrypted);
    $stmtUpdate->bindParam(':fingerPrint', $fingerPrint); // بدون تشفير إضافي
    $stmtUpdate->bindParam(':passengerID', $passengerID);
    $stmtUpdate->execute();

    jsonSuccess(null, "Token updated successfully");

} else {
    // إدخال سجل جديد
    $sqlInsert = "INSERT INTO `tokens` (`token`, `passengerID`, `fingerPrint`) VALUES (:token, :passengerID, :fingerPrint)";
    $stmtInsert = $con->prepare($sqlInsert);
    $stmtInsert->bindParam(':token', $tokenEncrypted);
    $stmtInsert->bindParam(':passengerID', $passengerID);
    $stmtInsert->bindParam(':fingerPrint', $fingerPrint); // بدون تشفير إضافي
    $stmtInsert->execute();

    if ($stmtInsert->rowCount() > 0) {
        jsonSuccess(null, "Token inserted successfully");
    } else {
        jsonError("Failed to insert token");
    }
}
?>

File: ride/firebase/get.php

<?php
require_once __DIR__ . '/../../connect.php';

$passengerID = filterRequest("passengerID");

// جلب السجل حسب passengerID
$sql = "SELECT * FROM `tokens` WHERE `passengerID` = :passengerID";
$stmt = $con->prepare($sql);
$stmt->bindParam(':passengerID', $passengerID, PDO::PARAM_STR);
$stmt->execute();

$data = $stmt->fetch(PDO::FETCH_ASSOC);

if ($data) {
    // فك تشفير التوكن فقط
    $data['token'] = $encryptionHelper->decryptData($data['token']);
	jsonSuccess($data);
   
} else {
    jsonError("No token found for this passenger");
}
?>

File: ride/firebase/getTokensPassenger.php

<?php
require_once __DIR__ . '/../../connect.php';

$passengerID = filterRequest("passengerID");

// جلب السجل حسب passengerID
$sql = "SELECT * FROM `tokens` WHERE `passengerID` = :passengerID";
$stmt = $con->prepare($sql);
$stmt->bindParam(':passengerID', $passengerID, PDO::PARAM_STR);
$stmt->execute();

$data = $stmt->fetch(PDO::FETCH_ASSOC);

if ($data) {
    // فك تشفير التوكن فقط
    $data['token'] = $encryptionHelper->decryptData($data['token']);
	jsonSuccess($data);
   
} else {
    jsonError("No token found for this passenger");
}
?>

File: ride/firebase/fcm_fun.php

<?php
// fcm_functions.php
// مكتبة مركزية لإرسال إشعارات FCM (استدعاء داخلي - بدون HTTP)

// ============================================================================
// دالة Base64 URL-Safe Encoding
// ============================================================================
function base64UrlEncode($data) {
    return rtrim(strtr(base64_encode($data), '+/', '-_'), '=');
}

// ============================================================================
// دالة الحصول على Access Token من Google OAuth2
// ============================================================================
function getFCMAccessToken($serviceAccountPath = null) {
    if (!$serviceAccountPath) {
        $serviceAccountPath = __DIR__ . '/service-account.json';
    }
    
    if (!file_exists($serviceAccountPath)) {
        error_log("❌ FCM: service-account.json not found at: $serviceAccountPath");
        return null;
    }
    
    $credentials = json_decode(file_get_contents($serviceAccountPath), true);
    $clientEmail = $credentials['client_email'];
    $privateKey  = $credentials['private_key'];
    
    $now = time();
    $header = base64UrlEncode(json_encode(['alg' => 'RS256', 'typ' => 'JWT']));
    $claim = base64UrlEncode(json_encode([
        'iss' => $clientEmail,
        'scope' => 'https://www.googleapis.com/auth/firebase.messaging',
        'aud' => 'https://oauth2.googleapis.com/token',
        'exp' => $now + 3600,
        'iat' => $now
    ]));
    
    $signature = '';
    openssl_sign("$header.$claim", $signature, $privateKey, 'SHA256');
    $jwt = "$header.$claim." . base64UrlEncode($signature);
    
    $ch = curl_init("https://oauth2.googleapis.com/token");
    curl_setopt($ch, CURLOPT_POST, 1);
    curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query([
        'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer',
        'assertion' => $jwt
    ]));
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_TIMEOUT, 10);
    
    $res = curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);
    
    if ($httpCode != 200) {
        error_log("❌ FCM OAuth Error ($httpCode): $res");
        return null;
    }
    
    return json_decode($res, true)['access_token'] ?? null;
}

// ============================================================================
// 🔥 الدالة الرئيسية: إرسال إشعار FCM (داخلي - بدون HTTP)
// ============================================================================
function sendFCMNotification($params) {
    // استخراج البارامترات
    $token       = $params['token'] ?? null;
    $title       = $params['title'] ?? '';
    $body        = $params['body'] ?? '';
    $category    = $params['category'] ?? '';
    $data        = $params['data'] ?? [];
    $tone        = $params['tone'] ?? 'default';
    $isTopic     = $params['isTopic'] ?? false;
    $serviceAccountPath = $params['service_account_path'] ?? __DIR__ . '/service-account.json';
    
    // التحقق من البيانات الأساسية
    if (empty($token) || empty($title) || empty($body)) {
        error_log("❌ FCM: Missing required fields (token, title, or body)");
        return [
            'success' => false,
            'error' => 'Missing required parameters',
            'http_code' => 400
        ];
    }
    
    // الحصول على Access Token
    $accessToken = getFCMAccessToken($serviceAccountPath);
    if (!$accessToken) {
        return [
            'success' => false,
            'error' => 'Failed to get Access Token',
            'http_code' => 500
        ];
    }
    
    // جلب Project ID
    $creds = json_decode(file_get_contents($serviceAccountPath), true);
    $projectId = $creds['project_id'];
    $fcmUrl = "https://fcm.googleapis.com/v1/projects/$projectId/messages:send";
    
    // بناء الـ Payload
    $messagePayload = [
        'message' => [
            'notification' => [
                'title' => $title,
                'body'  => $body
            ],
            'android' => [
                'priority' => 'HIGH',
                'notification' => [
                    'sound' => $tone,
                    'channel_id' => 'high_importance_channel'
                ]
            ],
            'apns' => [
                'headers' => ['apns-priority' => '10'],
                'payload' => [
                    'aps' => [
                        'sound' => $tone . '.caf',
                        'content-available' => 1
                    ]
                ]
            ]
        ]
    ];
    
    // تحديد الهدف
    if ($isTopic) {
        $messagePayload['message']['topic'] = $token;
    } else {
        $messagePayload['message']['token'] = $token;
    }
    
    // إضافة الـ Data Payload
    $customData = ['category' => (string)$category];
    if (is_array($data) && !empty($data)) {
        $customData = array_merge($customData, $data);
    }
    
    // تحويل كل القيم إلى String (FCM requirement)
    $processedData = [];
    foreach ($customData as $key => $val) {
        if (is_array($val) || is_object($val)) {
            $processedData[$key] = json_encode($val, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
        } else {
            $processedData[$key] = (string)$val;
        }
    }
    $messagePayload['message']['data'] = $processedData;
    
    // الإرسال إلى FCM
    $ch = curl_init($fcmUrl);
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_HTTPHEADER, [
        'Authorization: Bearer ' . $accessToken,
        'Content-Type: application/json; charset=UTF-8'
    ]);
    curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($messagePayload, JSON_UNESCAPED_UNICODE));
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_TIMEOUT, 10);
    
    $result = curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    $curlError = curl_error($ch);
    curl_close($ch);
    
    // معالجة النتيجة
    if ($httpCode == 200) {
        error_log("✅ FCM Sent: Category=$category, Token=" . substr($token, 0, 15) . "...");
        return [
            'success' => true,
            'http_code' => $httpCode,
            'response' => json_decode($result, true)
        ];
    } else {
        error_log("❌ FCM Error ($httpCode): $result | CURL: $curlError");
        return [
            'success' => false,
            'http_code' => $httpCode,
            'error' => json_decode($result, true),
            'curl_error' => $curlError
        ];
    }
}

// ============================================================================
// 🎯 دوال مُساعدة جاهزة للاستخدام المباشر
// ============================================================================

/**
 * إرسال إشعار "وصول السائق"
 */
function notifyDriverArrival($passengerToken, $driverName, $rideId) {
    return sendFCMNotification([
        'token' => $passengerToken,
        'title' => "السائق وصل إليك 📍",
        'body' => "$driverName في انتظارك الآن.",
        'category' => 'Arrive Ride',
        'tone' => 'tone1',
        'data' => [
            'ride_id' => (string)$rideId,
            'timestamp' => date('Y-m-d H:i:s')
        ]
    ]);
}

/**
 * إرسال إشعار "بدأت الرحلة"
 */
function notifyTripBegin($passengerToken, $driverName, $rideId) {
    return sendFCMNotification([
        'token' => $passengerToken,
        'title' => "بدأت الرحلة 🚗",
        'body' => "السائق $driverName بدأ رحلتك الآن.",
        'category' => 'Trip is Begin',
        'tone' => 'start',
        'data' => [
            'ride_id' => (string)$rideId,
            'start_time' => date('Y-m-d H:i:s')
        ]
    ]);
}

/**
 * إرسال إشعار "قبول الطلب"
 */
function notifyRideAccepted($passengerToken, $driverInfo, $rideId) {
    return sendFCMNotification([
        'token' => $passengerToken,
        'title' => "تم قبول الطلب 🚖",
        'body' => "الكابتن {$driverInfo['driverName']} قادم إليك.",
        'category' => 'Accepted Ride',
        'tone' => 'start',
        'data' => [
            'ride_id' => (string)$rideId,
            'driver_id' => (string)$driverInfo['driverId'],
            'driver_info' => $driverInfo // سيتم تحويلها لـ JSON تلقائياً
        ]
    ]);
}

/**
 * إرسال إشعار "إلغاء الرحلة من السائق"
 */
function notifyRideCancelled($passengerToken, $rideId, $reason = '') {
    return sendFCMNotification([
        'token' => $passengerToken,
        'title' => "تم إلغاء الرحلة ❌",
        'body' => "السائق اعتذر عن إكمال الرحلة.",
        'category' => 'Cancel Trip from driver',
        'tone' => 'cancel',
        'data' => [
            'ride_id' => (string)$rideId,
            'reason' => $reason,
            'cancelled_at' => date('Y-m-d H:i:s')
        ]
    ]);
}

/**
 * إرسال إشعار "انتهاء الرحلة"
 */
function notifyTripFinished($passengerToken, $tripData) {
    return sendFCMNotification([
        'token' => $passengerToken,
        'title' => "انتهت الرحلة 🏁",
        'body' => "شكرًا لاستخدامك تطبيق Tripz",
        'category' => 'Driver Finish Trip',
        'tone' => 'default',
        'data' => [
            'DriverList' => $tripData // Array سيتم تحويلها لـ JSON
        ]
    ]);
}
?>

File: ride/firebase/getTokenParent.php

<?php
require_once __DIR__ . '/../../connect.php';

$phone = filterRequest("phone");

// 🔐 تشفير رقم الهاتف قبل البحث (لأنه مشفّر في قاعدة البيانات)
$phoneEncrypted = $encryptionHelper->encryptData($phone);

// 1⃣ جلب passengerID بناءً على رقم الهاتف
$sql = "SELECT `id` FROM `passengers` WHERE `phone` = :phone";
$stmt = $con->prepare($sql);
$stmt->bindParam(':phone', $phoneEncrypted);
$stmt->execute();
$data = $stmt->fetch(PDO::FETCH_ASSOC);

if ($data) {
    $passengerID = $data['id'];
} else {
    jsonError("No passenger found for the given phone number");
    exit;
}

// 2⃣ جلب التوكنات المرتبطة بـ passengerID
$sql1 = "SELECT * FROM `tokens` WHERE `passengerID` = :passengerID";
$stmt = $con->prepare($sql1);
$stmt->bindParam(':passengerID', $passengerID);
$stmt->execute();
$data = $stmt->fetchAll(PDO::FETCH_ASSOC);

if ($data) {
    // فك تشفير التوكن فقط
    foreach ($data as &$row) {
        $row['token'] = $encryptionHelper->decryptData($row['token']);
        // fingerPrint يبقى كما هو
    }

    echo json_encode([
        'status' => 'success',
        'count' => count($data),
        'data' => $data
    ]);
} else {
    jsonError("No tokens found for the passenger");
}
?>

File: ride/firebase/addDriver.php

<?php

require_once __DIR__ . '/../../connect.php';

$token        = filterRequest("token");       // نص عادي ➜ سيتم تشفيره
$captain_id   = filterRequest("captain_id");  // ID
$fingerPrint  = filterRequest("fingerPrint"); // مشفّر مسبقًا من Flutter

// تشفير التوكن فقط
$tokenEncrypted = $encryptionHelper->encryptData($token);

// التحقق مما إذا كان السجل موجودًا
$sqlCheck = "SELECT * FROM `driverToken` WHERE `captain_id` = :captain_id";
$stmtCheck = $con->prepare($sqlCheck);
$stmtCheck->bindParam(':captain_id', $captain_id);
$stmtCheck->execute();

$result = $stmtCheck->fetch(PDO::FETCH_ASSOC);

if ($result) {
    // تحديث السجل
    $sqlUpdate = "UPDATE `driverToken` SET `token` = :token, `fingerPrint` = :fingerPrint WHERE `captain_id` = :captain_id";
    $stmtUpdate = $con->prepare($sqlUpdate);
    $stmtUpdate->bindParam(':token', $tokenEncrypted);
    $stmtUpdate->bindParam(':fingerPrint', $fingerPrint); // بدون إعادة تشفير
    $stmtUpdate->bindParam(':captain_id', $captain_id);
    $stmtUpdate->execute();

    jsonSuccess(null, "Token updated successfully");

} else {
    // إدخال سجل جديد
    $sqlInsert = "INSERT INTO `driverToken` (`token`, `captain_id`, `fingerPrint`) VALUES (:token, :captain_id, :fingerPrint)";
    $stmtInsert = $con->prepare($sqlInsert);
    $stmtInsert->bindParam(':token', $tokenEncrypted);
    $stmtInsert->bindParam(':captain_id', $captain_id);
    $stmtInsert->bindParam(':fingerPrint', $fingerPrint); // بدون إعادة تشفير
    $stmtInsert->execute();

    if ($stmtInsert->rowCount() > 0) {
        jsonSuccess(null, "Token inserted successfully");
    } else {
        jsonError("Failed to insert token");
    }
}
?>

File: ride/firebase/notify_driver_arrival.php

<?php
// simple_fcm_test.php
// تجربة إرسال إشعار بسيط جداً (بدون قاعدة بيانات)

header('Content-Type: text/plain; charset=utf-8');

// 1. تضمين ملف الدوال (الذي يحتوي على sendFCM_Internal)
if (file_exists("../../functions.php")) {
    include "../../functions.php";
} else {
    die("❌ Error: functions.php not found!");
}

// =================================================================
// 🟢🟢 ضع التوكن الخاص بك هنا (بين علامات التنصيص) 🟢🟢
// =================================================================
$myToken = "dd35hHkHSOirLLu8luXGKz:APA91bHiW-HpEFMLAZB8nDKV5cT3IplNOYNSbQeIyieZ1KaEkjM1CjeQ8CY9JQcCNqdC8StoUAQGpn-birQiZz1xSndLObXox6O52bxgsUV_dCzr-7BOoR8"; 
// =================================================================


if ($myToken == "PASTE_YOUR_TOKEN_HERE") {
    die("⚠️ الرجاء وضع التوكن الخاص بك داخل ملف السكريبت في السطر 15");
}

//echo "🚀 جاري إرسال الإشعار...\n";
//echo "إلى: " . substr($myToken, 0, 20) . "...\n\n";

// 2. استدعاء دالة الإرسال
$result = sendFCM_Internal(
    $myToken,           // الهدف
    "تنبيه تجريبي 🔔",    // العنوان
    "أنا وصلت للموقع 📍", // الرسالة (كما طلبت)
    ['type' => 'test'], // بيانات إضافية بسيطة
    "General"           // التصنيف
);

// 3. طباعة النتيجة
//echo "النتيجة:\n";
print_r($result);

?>

File: ride/firebase/getAllTokenPassengers.php

<?php
require_once __DIR__ . '/../../connect.php';

$sql = "SELECT * FROM `tokens`";
$stmt = $con->prepare($sql);
$stmt->execute();
$data = $stmt->fetchAll(PDO::FETCH_ASSOC);

if ($data) {
    // فك تشفير token فقط
    foreach ($data as &$item) {
        $item['token'] = $encryptionHelper->decryptData($item['token']);
        // fingerPrint يبقى كما هو (مشفّر من التطبيق)
    }

    echo json_encode([
        'status' => 'success',
        'data' => $data
    ]);
} else {
    jsonError("No token records found");
}
?>

File: ride/firebase/delete.php

<?php

require_once __DIR__ . '/../../connect.php';

$id = filterRequest("id");

$sql = "DELETE FROM `tokens` WHERE `id` = :id";
$stmt = $con->prepare($sql);
$stmt->bindParam(':id', $id, PDO::PARAM_INT);
$stmt->execute();

if ($stmt->rowCount() > 0) {
    jsonSuccess(null, "Token deleted successfully");
} else {
    jsonError("Failed to delete token");
}
?>

File: ride/firebase/getDriverToken.php

<?php
require_once __DIR__ . '/../../connect.php';

$captain_id = filterRequest("captain_id");

$sql = "SELECT * FROM `driverToken` WHERE `captain_id` = :captain_id";
$stmt = $con->prepare($sql);
$stmt->bindParam(':captain_id', $captain_id, PDO::PARAM_STR);
$stmt->execute();
$data = $stmt->fetchAll(PDO::FETCH_ASSOC);

if ($data) {
    // فك تشفير token فقط
    foreach ($data as &$item) {
        $item['token'] = $encryptionHelper->decryptData($item['token']);
        // fingerPrint يبقى كما هو
    }

    echo json_encode([
        'status' => 'success',
        'data' => $data
    ]);
} else {
    jsonError("No driver token found");
}
?>

File: ride/firebase/send_fcm.php

<?php
// send_fcm.php - FCM HTTP v1 Sender
header('Content-Type: application/json; charset=utf-8');

$serviceAccountFile = __DIR__ . '/service-account.json';

// السماح فقط بـ POST
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
    http_response_code(405);
    echo json_encode(['status' => 'error', 'message' => 'Only POST allowed.']);
    exit;
}

// استقبال البيانات
$json_input = file_get_contents('php://input');
$requestData = json_decode($json_input, true);

$target  = $requestData['target'] ?? null;
$title   = $requestData['title'] ?? null;
$body    = $requestData['body'] ?? null;
$isTopic = $requestData['isTopic'] ?? false;
$tone    = $requestData['tone'] ?? 'default';
$customData = $requestData['data'] ?? [];

if (!$target) {
    http_response_code(400);
    echo json_encode(['status' => 'error', 'message' => 'Missing: target, title, or body.']);
    exit;
}

// ============================================================================
// دالة Base64 URL-Safe Encoding (ضرورية للـ JWT)
// ============================================================================
function base64UrlEncode($data) {
    return rtrim(strtr(base64_encode($data), '+/', '-_'), '=');
}

// ============================================================================
// دالة المصادقة (Google OAuth2)
// ============================================================================
function getAccessToken($credentialsPath) {
    if (!file_exists($credentialsPath)) return null;
    
    $credentials = json_decode(file_get_contents($credentialsPath), true);
    $clientEmail = $credentials['client_email'];
    $privateKey  = $credentials['private_key'];
    
    $now = time();
    $header = base64UrlEncode(json_encode(['alg' => 'RS256', 'typ' => 'JWT']));
    $claim = base64UrlEncode(json_encode([
        'iss' => $clientEmail,
        'scope' => 'https://www.googleapis.com/auth/firebase.messaging',
        'aud' => 'https://oauth2.googleapis.com/token',
        'exp' => $now + 3600,
        'iat' => $now
    ]));
    
    $signature = '';
    openssl_sign("$header.$claim", $signature, $privateKey, 'SHA256');
    $jwt = "$header.$claim." . base64UrlEncode($signature);
    
    $ch = curl_init("https://oauth2.googleapis.com/token");
    curl_setopt($ch, CURLOPT_POST, 1);
    curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query([
        'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer',
        'assertion' => $jwt
    ]));
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    $res = curl_exec($ch);
    curl_close($ch);
    
    return json_decode($res, true)['access_token'] ?? null;
}

// الحصول على Access Token
$accessToken = getAccessToken($serviceAccountFile);
if (!$accessToken) {
    http_response_code(500);
    echo json_encode(['status' => 'error', 'message' => 'Failed to get Access Token.']);
    exit;
}

// جلب Project ID
$creds = json_decode(file_get_contents($serviceAccountFile), true);
$projectId = $creds['project_id'];
$fcmUrl = "https://fcm.googleapis.com/v1/projects/$projectId/messages:send";

// ============================================================================
// بناء هيكل الرسالة
// ============================================================================
$messagePayload = [
    'message' => [
        'notification' => [
            'title' => $title,
            'body'  => $body
        ],
        'android' => [
            'priority' => 'HIGH',
            'notification' => [
                'sound' => $tone,
                'channel_id' => 'high_importance_channel' // تأكد من تطابقه مع Android
            ]
        ],
        'apns' => [
            'headers' => ['apns-priority' => '10'],
            'payload' => [
                'aps' => [
                    'sound' => $tone . '.caf',
                    'content-available' => 1
                ]
            ]
        ]
    ]
];

// تحديد الهدف (Topic أو Token)
if ($isTopic) {
    $messagePayload['message']['topic'] = $target;
} else {
    $messagePayload['message']['token'] = $target;
}

// ============================================================================
// 🔥 معالجة Data Payload (يجب أن تكون String: String فقط)
// ============================================================================
if (!empty($customData)) {
    $processedData = [];
    foreach ($customData as $key => $val) {
        if (is_array($val) || is_object($val)) {
            // تحويل المصفوفات/الكائنات إلى JSON String
            $processedData[$key] = json_encode($val, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
        } else {
            // تحويل أي قيمة أخرى إلى String
            $processedData[$key] = (string)$val;
        }
    }
    $messagePayload['message']['data'] = $processedData;
}

// ============================================================================
// الإرسال الفعلي إلى FCM
// ============================================================================
$ch = curl_init($fcmUrl);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Authorization: Bearer ' . $accessToken,
    'Content-Type: application/json; charset=UTF-8'
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($messagePayload, JSON_UNESCAPED_UNICODE));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

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

// الرد
if ($httpCode == 200) {
    echo json_encode([
        'status' => 'success',
        'message' => 'Notification sent successfully',
        'fcm_response' => json_decode($result)
    ], JSON_UNESCAPED_UNICODE);
} else {
    http_response_code($httpCode);
    echo json_encode([
        'status' => 'error',
        'message' => 'FCM request failed',
        'fcm_response' => json_decode($result)
    ], JSON_UNESCAPED_UNICODE);
}
?>

File: ride/firebase/getALlTokenDrivers.php

<?php
require_once __DIR__ . '/../../connect.php';

$sql = "SELECT * FROM `driverToken`";
$stmt = $con->prepare($sql);
$stmt->execute();
$data = $stmt->fetchAll(PDO::FETCH_ASSOC);

if ($data) {
    // فك تشفير token فقط لكل سجل
    foreach ($data as &$item) {
        $item['token'] = $encryptionHelper->decryptData($item['token']);
        // لا يتم فك تشفير fingerPrint لأنه مشفّر من Flutter
    }

    echo json_encode([
        'status' => 'success',
        'data' => $data
    ]);
} else {
    jsonError("No driver tokens found");
}
?>

File: ride/RegisrationCar/add.php

<?php
require_once __DIR__ . '/../../connect.php';

/* ───── 1) جلب الحقول من طلب POST ───── */
$driverID        = filterRequest("driverID");
$vin             = filterRequest("vin");
$carPlate        = filterRequest("car_plate");
$make            = filterRequest("make");
$model           = filterRequest("model");
$year            = filterRequest("year");
$expirationDate  = filterRequest("expiration_date");
$color           = filterRequest("color");
$owner           = filterRequest("owner");
$colorHex        = filterRequest("color_hex");
$fuel            = filterRequest("fuel");

/* ───── 2) التحقق من الحقول الأساسية ───── */
$required = [
  'driverID'       => $driverID,
  'vin'            => $vin,
  'car_plate'      => $carPlate,
  'make'           => $make,
  'model'          => $model,
  'year'           => $year,
  'expirationDate' => $expirationDate,
  'color'          => $color,
  'owner'          => $owner,
  'colorHex'       => $colorHex,
  'fuel'           => $fuel,
];

foreach ($required as $field => $val) {
    if ($val === null || $val === '') {
        jsonError("Missing required field: $field");
        exit;
    }
}

/* ───── 3) تشفير الحقول الحساسة ───── */
$vin      = $encryptionHelper->encryptData($vin);
$carPlate = $encryptionHelper->encryptData($carPlate);
$owner    = $encryptionHelper->encryptData($owner);

/* ───── 4) هل لدى السائق مركبة مُسجلة سابقًا؟ ───── */
$hasCar = $con->prepare("SELECT 1 FROM CarRegistration WHERE driverID = :d LIMIT 1");
$hasCar->execute([':d' => $driverID]);
$isDefault = $hasCar->rowCount() === 0 ? 1 : 0;

/* ───── 5) إدراج السجل ───── */
$sql = "
  INSERT INTO CarRegistration (
    driverID, vin, car_plate, make, model, year, expiration_date,
    color, owner, color_hex, fuel, isDefault, created_at, status
  ) VALUES (
    :driverID, :vin, :carPlate, :make, :model, :year, :expirationDate,
    :color, :owner, :colorHex, :fuel, :isDefault, NOW(), 'yet'
  )
";

$ins = $con->prepare($sql);
$ins->execute([
  ':driverID'       => $driverID,
  ':vin'            => $vin,
  ':carPlate'       => $carPlate,
  ':make'           => $make,
  ':model'          => $model,
  ':year'           => $year,
  ':expirationDate' => $expirationDate,
  ':color'          => $color,
  ':owner'          => $owner,
  ':colorHex'       => $colorHex,
  ':fuel'           => $fuel,
  ':isDefault'      => $isDefault,
]);

if ($ins->rowCount() > 0) {
    jsonSuccess(null, "Car registration saved.");
} else {
    jsonError("Failed to save car registration.");
}

File: ride/RegisrationCar/selectDriverAndCarForMishwariTrip.php

<?php
require_once __DIR__ . '/../../connect.php';

try {
    $swLat = floatval(filterRequest("southwestLat"));
    $neLat = floatval(filterRequest("northeastLat"));
    $swLon = floatval(filterRequest("southwestLon"));
    $neLon = floatval(filterRequest("northeastLon"));
    $yearMin = 2022;
    $yearMax = 2025;

    if (!is_numeric($swLat) || !is_numeric($neLat) || !is_numeric($swLon) || !is_numeric($neLon)) {
        throw new Exception("Invalid coordinate values provided");
    }

    $sql = "
    WITH LatestLocations AS (
        SELECT
            cl.driver_id,
            cl.latitude,
            cl.longitude,
            cl.heading,
            cl.speed,
            cl.status,
            cl.created_at,
            d.phone,
            d.email,
            d.first_name,
            d.last_name,
            d.gender,
            d.maritalStatus,
            d.education,
            cr.make,
            cr.car_plate,
            cr.model,
            cr.color,
            cr.color_hex,
            cr.year,
            dt.token,
            ROW_NUMBER() OVER(
                PARTITION BY cl.driver_id
                ORDER BY cl.created_at DESC
            ) AS row_num
        FROM car_locations cl
        JOIN driver d ON d.id = cl.driver_id
        LEFT JOIN CarRegistration cr ON cr.driverID = cl.driver_id
        LEFT JOIN driverToken dt ON dt.captain_id = cl.driver_id
        WHERE cl.latitude BETWEEN ? AND ?
        AND cl.longitude BETWEEN ? AND ?
        AND cr.year BETWEEN ? AND ?
        AND cl.created_at >= NOW() - INTERVAL 1 DAY
        AND cr.make NOT LIKE '%دراج%'
        AND cr.model NOT LIKE '%دراج%'
    )
    SELECT 
        d.id AS driver_id,
        d.phone,
        d.gender,
        d.name_arabic  AS name_arabic,
        d.name_english,
        d.address,
        ll.latitude,
        ll.longitude,
        FLOOR(DATEDIFF(CURDATE(), STR_TO_DATE(CONCAT(d.birthdate, '-01-01'), '%Y-%m-%d')) / 365.25) AS age,
        c.car_plate,
        c.make,
        c.model,
        c.year,
        c.color,
        c.fuel,
        c.displacement,
        c.color_hex,
        dt.token,
        COALESCE(avg_rating.rating, 5) AS rating,
        COALESCE(ride_count.count, 0) AS ride_count
    FROM driver d
    JOIN CarRegistration c ON c.driverID = d.id
    JOIN LatestLocations ll ON ll.driver_id = d.id AND ll.row_num = 1
    LEFT JOIN driverToken dt ON dt.captain_id = d.id
    LEFT JOIN (
        SELECT driver_id, AVG(rating) AS rating
        FROM ratingDriver
        GROUP BY driver_id
    ) avg_rating ON avg_rating.driver_id = d.id
    LEFT JOIN (
        SELECT driver_id, COUNT(*) AS count
        FROM ride
        WHERE status = 'Finished'
        GROUP BY driver_id
    ) ride_count ON ride_count.driver_id = d.id
    WHERE c.year BETWEEN ? AND ?
    ORDER BY rating DESC, c.year DESC, ride_count DESC
    LIMIT 10";

    $stmt = $con->prepare($sql);
    $stmt->execute([
        $swLat, $neLat, $swLon, $neLon,
        $yearMin, $yearMax,
        $yearMin, $yearMax
    ]);

    $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);

    // فك التشفير عن الحقول الحساسة
    foreach ($rows as &$row) {
        $row['phone']         = $encryptionHelper->decryptData($row['phone']);
        $row['gender']        = $encryptionHelper->decryptData($row['gender']);
        $row['name_arabic']   = $encryptionHelper->decryptData($row['name_arabic']);
        $row['name_english']  = $encryptionHelper->decryptData($row['name_english']);
        $row['address']       = $encryptionHelper->decryptData($row['address']);
        $row['car_plate']     = $encryptionHelper->decryptData($row['car_plate']);
        $row['token']         = $encryptionHelper->decryptData($row['token']);
    }

    if (count($rows) > 0) {
        jsonSuccess($rows);
    } else {
        jsonError("No drivers found in the specified area");
    }

} catch (PDOException $e) {
    jsonError("Database error: " . $e->getMessage());
} catch (Exception $e) {
    jsonError("Error: " . $e->getMessage());
}

File: ride/RegisrationCar/update.php

<?php
require_once __DIR__ . '/../../connect.php';

$id = filterRequest("id");
$driverID = filterRequest("driverID");

// الحقول التي تحتاج لتشفير
$encryptedFields = ['vin', 'car_plate', 'owner'];

// جميع الحقول المسموح بتحديثها
$columns = ['vin', 'car_plate', 'make', 'model', 'year', 'expiration_date', 'color', 'owner', 'isDefault', 'registration_date'];

$columnValues = [];

// تحقق من القيم وأضفها إلى التحديث
foreach ($columns as $column) {
    if (isset($_POST[$column])) {
        $value = filterRequest($column);
        if (!empty($value)) {
            // تشفير الحقول الحساسة
            if (in_array($column, $encryptedFields)) {
                $value = $encryptionHelper->encryptData($value);
            }
            $columnValues[$column] = $value;
        }
    }
}

// بناء جملة SET للتحديث
$setClause = [];
foreach ($columnValues as $column => $value) {
    $setClause[] = "`$column` = :$column";
}
$setClause = implode(", ", $setClause);

// التحقق من وجود بيانات للتحديث
if (empty($setClause)) {
    jsonError("No data provided to update.");
    exit();
}

// ✅ تأكد من اسم الجدول الصحيح
$sql = "UPDATE `CarRegistration` SET $setClause WHERE `driverID` = :driverID AND `id` = :id";

$stmt = $con->prepare($sql);

// ربط القيم بالاستعلام
foreach ($columnValues as $column => $value) {
    $stmt->bindValue(":$column", $value);
}
$stmt->bindValue(':driverID', $driverID);
$stmt->bindValue(':id', $id);

$stmt->execute();

if ($stmt->rowCount() > 0) {
    jsonSuccess(null, "Car registration data updated successfully");
} else {
    jsonError("Failed to update car registration data");
}
?>

File: ride/RegisrationCar/get.php


File: ride/RegisrationCar/makeDefaultCar.php

<?php
require_once __DIR__ . '/../../connect.php';

$id = filterRequest("id");
$driverID = filterRequest("driverID");

try {
    // أولاً: إعادة تعيين isDefault = 0 لكل سيارات السائق
    $sql1 = "UPDATE `CarRegistration` SET `isDefault` = 0 WHERE `driverID` = :driverID";
    $stmt1 = $con->prepare($sql1);
    $stmt1->bindParam(':driverID', $driverID);
    $stmt1->execute();

    // ثانياً: تعيين السيارة المحددة كافتراضية
    $sql2 = "UPDATE `CarRegistration` SET `isDefault` = 1 WHERE `id` = :id";
    $stmt2 = $con->prepare($sql2);
    $stmt2->bindParam(':id', $id);
    $stmt2->execute();

    if ($stmt2->rowCount() > 0) {
        jsonSuccess(null, "Default car updated successfully.");
    } else {
        jsonError("Failed to update default car.");
    }
} catch (PDOException $e) {
    error_log("DB Error: " . $e->getMessage());
    jsonError("Database error occurred.");
}
?>

File: ride/RegisrationCar/delete.php


File: ride/videos_driver/get.php

<?php
require_once __DIR__ . '/../../connect.php';

$sql = "SELECT * FROM `videos`";
$stmt = $con->prepare($sql);
$stmt->execute();
$data = $stmt->fetchAll(PDO::FETCH_ASSOC);

if ($data) {
    jsonSuccess($data);
} else {
    jsonError("No video records found");
}
?>

File: ride/egyptPhones/add.php

<?php
require_once __DIR__ . '/../../connect.php';

// Get the values from the request
$phones = filterRequest("phones");
$name = filterRequest("name");
$phones2 = filterRequest("phones2");

// Check if required fields are provided
if (empty($phones)) {
    jsonError($message = "Phone number is required.");
    exit();
}

// Prepare the SQL query to insert data into contactEgypt
$sql = "INSERT INTO `contactEgypt`(`phones`, `name`, `phones2`) VALUES (
  :phones,
  :name,
  :phones2
)";

$stmt = $con->prepare($sql);
$stmt->bindParam(':phones', $phones);
$stmt->bindParam(':name', $name);
$stmt->bindParam(':phones2', $phones2);

try {
    $stmt->execute();
    if ($stmt->rowCount() > 0) {
        // Print a success message
        jsonSuccess($message = "Contact data saved successfully");
    } else {
        // Print a failure message
        jsonError($message = "Failed to save contact data");
    }
} catch (PDOException $e) {
    // Print error message
    jsonError($message = "Database error: " . $e->getMessage());
}
?>

File: ride/egyptPhones/syrianAdd.php

<?php
require_once __DIR__ . '/../../connect.php'; // تأكد من أن هذا المسار صحيح

// --- استقبال البيانات من التطبيق ---
$driverId = filterRequest("driverId");
$name = filterRequest("name");
$phone = filterRequest("phone");

// --- التحقق من وجود البيانات الضرورية ---
if (empty($driverId) || empty($phone)) {
    jsonError("Driver ID and Phone number are required.");
    exit();
}

// --- إعداد استعلام SQL ---
// نستخدم "INSERT IGNORE" لتجنب إدخال سجلات مكررة بناءً على المفتاح الفريد (driverId, phone)
// إذا كان السجل موجوداً مسبقاً، سيتجاهله الاستعلام ببساطة
$sql = "INSERT IGNORE INTO `contactSyria`(`driverId`, `name`, `phone`) VALUES (:driverId, :name, :phone)";

$stmt = $con->prepare($sql);
$stmt->bindParam(':driverId', $driverId);
$stmt->bindParam(':name', $name);
$stmt->bindParam(':phone', $phone);

try {
    $stmt->execute();
    // rowCount() ستكون 1 عند إضافة سجل جديد، و 0 عند تجاهل سجل مكرر
    if ($stmt->rowCount() > 0) {
        jsonSuccess(null, "New contact saved successfully");
    } else {
        jsonSuccess(null, "Contact already exists for this driver.");
    }
} catch (PDOException $e) {
    // إرجاع رسالة خطأ في حال حدوث مشكلة في قاعدة البيانات
    jsonError("Database error: " . $e->getMessage());
}
?>

File: ride/egyptPhones/get.php


File: ride/profile/updateDriverEmail.php

<?php
require_once __DIR__ . '/../../connect.php';

$id    = filterRequest("id");
$email = filterRequest("email");

// التحقق من وجود البيانات
if (empty($id) || empty($email)) {
    jsonError("Missing required parameters");
    exit;
}

// تشفير الإيميل
$encryptedEmail = $encryptionHelper->encryptData($email);

// تنفيذ التحديث
$sql = "UPDATE driver SET email = :email WHERE id = :id";
$stmt = $con->prepare($sql);
$success = $stmt->execute([
    ":email" => $encryptedEmail,
    ":id"    => $id
]);

if ($success && $stmt->rowCount() > 0) {
    jsonSuccess(null, "Email updated successfully");
} else {
    jsonError("Failed to update email");
}
?>

File: ride/profile/update.php

<?php
require_once __DIR__ . '/../../connect.php';

$id = filterRequest("id");

$fields = [];
$params = [":id" => $id];

$encryptedFields = [
    "phone", "sosPhone", "birthdate", "site", "gender",
    "first_name", "last_name", "education", "employmentType", "maritalStatus"
];

foreach ($encryptedFields as $field) {
    if (isset($_POST[$field]) && !empty($_POST[$field])) {
        $value = filterRequest($field);
        $encryptedValue = $encryptionHelper->encryptData($value);
        $fields[] = "`$field` = :$field";
        $params[":$field"] = $encryptedValue;
    }
}

if (!empty($fields)) {
    $setClause = implode(", ", $fields);
    $sql = "UPDATE `passengers` SET $setClause WHERE `id` = :id";
    $stmt = $con->prepare($sql);
    $stmt->execute($params);

    if ($stmt->rowCount() > 0) {
        jsonSuccess(null, "Passenger data updated successfully");
    } else {
        jsonError("Failed to update passenger data");
    }
} else {
    jsonError("No fields to update");
}
?>

File: ride/profile/get.php

<?php
require_once __DIR__ . '/../../connect.php';

$id = filterRequest("id");

$sql = "SELECT * FROM `passengers` WHERE `id` = :id";
$stmt = $con->prepare($sql);
$stmt->bindParam(':id', $id, PDO::PARAM_STR);
$stmt->execute();
$result = $stmt->fetch(PDO::FETCH_ASSOC);

if ($result) {
    unset($result['password']); // إخفاء الباسورد

    // فك تشفير الحقول الحساسة
    $fieldsToDecrypt = [
        'phone', 'email', 'gender', 'birthdate', 'site',
        'first_name', 'last_name', 'sosPhone',
        'education', 'employmentType', 'maritalStatus'
    ];

    foreach ($fieldsToDecrypt as $field) {
        if (isset($result[$field])) {
            $result[$field] = $encryptionHelper->decryptData($result[$field]);
        }
    }

    echo json_encode([
        "status" => "success",
        "data" => $result
    ]);
} else {
    jsonError("Failed to retrieve passenger data");
}
?>

File: ride/profile/getCaptainProfile.php

<?php
require_once __DIR__ . '/../../connect.php';  // يوفر $con و $encryptionHelper

$id = filterRequest("id");

$sql = "SELECT
    d.phone,
    d.email,
    d.gender,
    d.birthdate,          -- مشفّر
    d.site,
    d.first_name,
    d.last_name,
    d.accountBank,
    d.created_at   AS driver_created_at,
    d.updated_at   AS driver_updated_at,
    v.id           AS vehicle_id,
    v.driverID,
    v.make,
    v.model,
    v.car_plate,
    v.year,
    v.expiration_date,
    v.vin,
    v.color,
    (
        SELECT COUNT(*)
        FROM ratingDriver rd
        WHERE rd.driver_id = d.id
    ) AS ratingCount,
    (
        SELECT ROUND(AVG(rd.rating), 2)
        FROM ratingDriver rd
        WHERE rd.driver_id = d.id
    ) AS ratingDriver
FROM driver d
LEFT JOIN CarRegistration v
    ON d.id = v.driverID
WHERE d.id = :id";

$stmt = $con->prepare($sql);
$stmt->bindParam(':id', $id, PDO::PARAM_STR);
$stmt->execute();
$result = $stmt->fetch(PDO::FETCH_ASSOC);

if (!$result) {
    jsonError("Failed to retrieve driver data");
    exit;
}

// فك تشفير حقل birthdate أولاً لحساب العمر
if (!empty($result['birthdate'])) {
    $result['birthdate'] = $encryptionHelper->decryptData($result['birthdate']);

    try {
        $dob = new DateTime($result['birthdate']);
        $today = new DateTime();
        $age = $today->diff($dob)->y;
    } catch (Exception $e) {
        $age = null;
    }
} else {
    $age = null;
}
$result['age'] = $age;

// فك تشفير بقية الحقول
$driverFieldsToDecrypt = [
    'phone', 'email', 'gender', 'site',
    'first_name', 'last_name'
];

foreach ($driverFieldsToDecrypt as $field) {
    if (!empty($result[$field])) {
        $result[$field] = $encryptionHelper->decryptData($result[$field]);
    }
}

// فك تشفير حقول السيارة
$vehicleFieldsToDecrypt = ['vin', 'car_plate'];
foreach ($vehicleFieldsToDecrypt as $field) {
    if (!empty($result[$field])) {
        $result[$field] = $encryptionHelper->decryptData($result[$field]);
    }
}

jsonSuccess($result);
?>

File: ride/driver_order/add.php

<?php

require_once __DIR__ . '/../../connect.php';

// استقبال المتغيرات
$driver_id = filterRequest("driver_id");
$order_id  = filterRequest("order_id");
$status    = filterRequest("status");

// التحقق من وجود order_id مسبقًا
$checkSql = "SELECT `order_id` FROM `driver_orders` WHERE `order_id` = ?";
$checkStmt = $con->prepare($checkSql);
$checkStmt->execute([$order_id]);

if ($checkStmt->rowCount() > 0) {
    // تحديث السجل إذا كان موجودًا
    $updateSql = "UPDATE `driver_orders` SET `driver_id` = ?, `status` = ?, `created_at` = NOW() WHERE `order_id` = ?";
    $updateStmt = $con->prepare($updateSql);
    $updateStmt->execute([$driver_id, $status, $order_id]);

    if ($updateStmt->rowCount() > 0) {
        jsonSuccess(null, "Driver order data updated successfully");
    } else {
        jsonError("Failed to update driver order data");
    }
} else {
    // إدخال سجل جديد إذا لم يكن موجودًا
    $insertSql = "INSERT INTO `driver_orders` (`driver_id`, `order_id`, `created_at`, `status`) VALUES (?, ?, NOW(), ?)";
    $insertStmt = $con->prepare($insertSql);
    $insertStmt->execute([$driver_id, $order_id, $status]);

    if ($insertStmt->rowCount() > 0) {
        jsonSuccess(null, "Driver order data saved successfully");
    } else {
        jsonError("Failed to save driver order data");
    }
}
?>

File: ride/driver_order/update.php

<?php
require_once __DIR__ . '/../../connect.php';

// استقبال المتغيرات
$order_id = filterRequest("order_id");
$status   = filterRequest("status");
$notes    = filterRequest("notes");

// ---------------------------------------------------------
// التحقق من الملاحظات: إذا كانت فارغة نضع قيمة افتراضية
// ---------------------------------------------------------
if (empty($notes)) {
    $notes = "Nothing"; // أو يمكنك كتابة "لا توجد ملاحظات"
}

// تصحيح جملة SQL: يجب استخدام الفاصلة (,) للفصل بين الحقول وليس (and)
$sql = "UPDATE `driver_orders` SET `status` = :status, `notes` = :notes WHERE `order_id` = :order_id";

$stmt = $con->prepare($sql);
$stmt->bindParam(":status", $status);
$stmt->bindParam(":order_id", $order_id);
$stmt->bindParam(":notes", $notes);

$stmt->execute();

// التحقق من النتيجة
if ($stmt->rowCount() > 0) {
    jsonSuccess(null, "Driver order data updated successfully");
} else {
    jsonError("Failed to update driver order data"); // أو لم يحدث تغيير في البيانات
}
?>

File: ride/driver_order/getOrderCancelStatus.php

<?php
require_once __DIR__ . '/../../connect.php';

$order_id = filterRequest("order_id");

$sql = "SELECT `id`, `driver_id`, `order_id`, `created_at`, `status` FROM `driver_orders` WHERE `order_id` = :order_id";

$stmt = $con->prepare($sql);
$stmt->bindParam(":order_id", $order_id, PDO::PARAM_STR);
$stmt->execute();

$row = $stmt->fetch(PDO::FETCH_ASSOC);

if ($row) {
    echo json_encode([
        "status" => "success",
        "data" => $row
    ]);
} else {
    echo json_encode([
        "status" => "failure",
        "message" => "No driver order data found for the specified order_id"
    ]);
}
?>

File: ride/driver_order/get.php

<?php

require_once __DIR__ . '/../../connect.php';

$driver_id = filterRequest("driver_id");
$order_id  = filterRequest("order_id");

if ($driver_id != null) {

    // 1. First, get the statistics for the driver
    $stats_sql = "
        SELECT
            COUNT(*) AS total_rides,
            SUM(CASE WHEN status = 'Apply' THEN 1 ELSE 0 END) AS total_applied,
            SUM(CASE WHEN status = 'Refused' THEN 1 ELSE 0 END) AS total_refused
        FROM driver_orders
        WHERE
            driver_id = :driver_id
            AND MONTH(created_at) = MONTH(CURRENT_DATE())
            AND YEAR(created_at) = YEAR(CURRENT_DATE())
    ";
    $stats_stmt = $con->prepare($stats_sql);
    $stats_stmt->execute([':driver_id' => $driver_id]);
    $stats = $stats_stmt->fetch(PDO::FETCH_ASSOC);

    // Calculate the average
    if ($stats && $stats['total_rides'] > 0) {
        $stats['averageApplied'] = $stats['total_applied'] / $stats['total_rides'];
    } else {
        $stats['averageApplied'] = 0;
    }


    // 2. Second, get the actual order history
    $orders_sql = "
        SELECT * FROM driver_orders
        WHERE
            driver_id = :driver_id
            AND MONTH(created_at) = MONTH(CURRENT_DATE())
            AND YEAR(created_at) = YEAR(CURRENT_DATE())
        ORDER BY created_at DESC
    ";
    $orders_stmt = $con->prepare($orders_sql);
    $orders_stmt->execute([':driver_id' => $driver_id]);
    $orders = $orders_stmt->fetchAll(PDO::FETCH_ASSOC);

    // 3. Combine the results into one response
   

    jsonSuccess($orders);


} elseif ($order_id != null) {
    // This part remains the same, but let's ensure it's correct
    $sql = "
        SELECT * FROM driver_orders
        WHERE order_id = :order_id
          AND MONTH(created_at) = MONTH(CURRENT_DATE())
          AND YEAR(created_at) = YEAR(CURRENT_DATE())
    ";
    $stmt = $con->prepare($sql);
    $stmt->execute([':order_id' => $order_id]);
    $result = $stmt->fetchAll(PDO::FETCH_ASSOC);

    if ($stmt->rowCount() > 0) {
        jsonSuccess($result);
    } else {
        jsonError("No driver order data found for this order_id");
    }

} else {
    jsonError("No driver_id or order_id provided");
}

?>

File: ride/driver_order/delete.php


File: ride/tips/add.php

<?php
require_once __DIR__ . '/../../connect.php';

// استلام المتغيرات
$passengerID = filterRequest("passengerID");
$driverID    = filterRequest("driverID");
$rideID      = filterRequest("rideID");
$tipAmount   = filterRequest("tipAmount");

// تحقق من صحة قيمة البقشيش
if (!is_numeric($tipAmount) || $tipAmount < 0 || $tipAmount > 99999999.99) {
    jsonError("Invalid tip amount.");
    exit();
}

// إدراج بيانات البقشيش
$sql = "INSERT INTO `tips` (`driverID`, `passengerID`, `rideID`, `tipAmount`) 
        VALUES (:driverID, :passengerID, :rideID, :tipAmount)";

$stmt = $con->prepare($sql);
$stmt->bindParam(':driverID', $driverID);
$stmt->bindParam(':passengerID', $passengerID);
$stmt->bindParam(':rideID', $rideID);
$stmt->bindParam(':tipAmount', $tipAmount);

// تنفيذ العملية
if ($stmt->execute() && $stmt->rowCount() > 0) {
    jsonSuccess(null, "Tip inserted successfully");
} else {
    jsonError("Failed to save tip information");
}
?>

File: ride/tips/get.php

<?php
require_once __DIR__ . '/../../connect.php';

// فلترة البيانات
$driverID      = filterRequest("driverID");
$passengerID   = filterRequest("passendgerID"); // إذا كان الاسم كذلك في قاعدة البيانات

// إعداد SQL آمن باستخدام bindParam
$sql = "
SELECT
    `id`,
    `driverID`,
    `passendgerID`,
    `rideID`,
    `tipAmount`
FROM
    `tips`
WHERE
    (`driverID` = :driverID OR `passendgerID` = :passengerID)
";

$stmt = $con->prepare($sql);
$stmt->bindParam(':driverID', $driverID);
$stmt->bindParam(':passengerID', $passengerID);

$stmt->execute();
$data = $stmt->fetchAll(PDO::FETCH_ASSOC);

// فحص النتائج
if ($data) {
    jsonSuccess($data);
} else {
    jsonError("No tips records found");
}
?>

File: ride/driver_scam/add.php

<?php
require_once __DIR__ . '/../../connect.php';

// استقبال البيانات
$driverID              = filterRequest("driverID");
$passengerID           = filterRequest("passengerID");
$rideID                = filterRequest("rideID");
$isDriverCallPassenger = filterRequest("isDriverCallPassenger");


// If the value is missing or empty, force it to '0' (False)
if ($isDriverCallPassenger === null || $isDriverCallPassenger === "") {
    $isDriverCallPassenger = "0"; 
}

// استخدام التاريخ الحالي
$dateCreated = date("Y-m-d H:i:s");

// تجهيز الاستعلام الآمن
$sql = "INSERT INTO `driver_ride_scam` (
    `driverID`,
    `passengerID`,
    `rideID`,
    `isDriverCallPassenger`,
    `dateCreated`
) VALUES (
    :driverID,
    :passengerID,
    :rideID,
    :isDriverCallPassenger,
    :dateCreated
)";

$stmt = $con->prepare($sql);
$stmt->bindParam(":driverID", $driverID);
$stmt->bindParam(":passengerID", $passengerID);
$stmt->bindParam(":rideID", $rideID);
$stmt->bindParam(":isDriverCallPassenger", $isDriverCallPassenger);
$stmt->bindParam(":dateCreated", $dateCreated);

// تنفيذ الإدخال
$stmt->execute();

if ($stmt->rowCount() > 0) {
    jsonSuccess(null, "Driver ride scam data saved successfully");
} else {
    jsonError("Failed to save driver ride scam data");
}
?>

File: ride/driver_scam/update.php


File: ride/driver_scam/get.php

<?php
require_once __DIR__ . '/../../connect.php';

$driverID = filterRequest("driverID");

// Safety check: ensure driverID is not empty to prevent SQL errors
if (!$driverID) {
    jsonError("Driver ID is required");
    exit();
}

$sql = "SELECT 
    DATE(driver_ride_scam.dateCreated) AS date,
    CAST(COUNT(driver_ride_scam.id) AS CHAR) AS count 
FROM 
    driver_ride_scam
LEFT JOIN 
    ride ON ride.id = driver_ride_scam.rideID 
        AND ride.status = 'Cancel'
WHERE 
    driver_ride_scam.driverID = :driverID
    AND driver_ride_scam.dateCreated >= CURDATE()
    AND driver_ride_scam.dateCreated < DATE_ADD(CURDATE(), INTERVAL 1 DAY)
GROUP BY 
    DATE(driver_ride_scam.dateCreated)
ORDER BY 
    date DESC";

try {
    $stmt = $con->prepare($sql);
    $stmt->bindParam(':driverID', $driverID);
    $stmt->execute();
    
    $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);

    if (!empty($rows)) {
        // --- FIX IS HERE ---
        // Your Flutter app looks for d['message']. 
        // We manually create the array with the key "message" to match your app.
        echo json_encode(array("status" => "success", "message" => $rows));
    } else {
        jsonError("No ride scam record found");
    }

} catch (PDOException $e) {
    jsonError("Database Error: " . $e->getMessage());
}
?>

File: ride/driver_scam/delete.php


File: ride/passengerWallet/add.php

<?php
require_once __DIR__ . '/../../connect.php';
$passenger_id = filterRequest("passenger_id");
$balance = filterRequest("balance");
$token = filterRequest("token");


// Retrieve token details from the database
$stmt = $con->prepare("SELECT * FROM payment_tokens_passenger WHERE token = :token AND isUsed = FALSE");
$stmt->execute([':token' => $token]);

$tokenData = $stmt->fetch();

if ($tokenData) {
    // Insert into passengerWallet securely using prepared statements
    $sql = "INSERT INTO `passengerWallet` (`passenger_id`, `balance`) VALUES (:passenger_id, :balance)";
    $stmt = $con->prepare($sql);
    $stmt->execute([':passenger_id' => $passenger_id, ':balance' => $balance]);

    if ($stmt->rowCount() > 0) {
        // Mark the token as used
        $updateTokenStmt = $con->prepare("UPDATE payment_tokens_passenger SET isUsed = TRUE WHERE token = :token");
        $updateTokenStmt->execute([':token' => $token]);
        
        jsonSuccess(null, "Wallet record created successfully");
    } else {
        jsonError("Failed to create wallet record");
    }
} else {
    jsonError("Invalid or already used token");
}
?>

File: ride/passengerWallet/update.php


<?php
require_once __DIR__ . '/../../connect.php';
$id = filterRequest("id");
$balance = filterRequest("balance");

$sql = "UPDATE `passengerWallet` SET `balance` = '$balance' WHERE `id` = '$id'";
$stmt = $con->prepare($sql);
$stmt->execute();

if ($stmt->rowCount() > 0) {
    // Print a success message
    jsonSuccess($message = "Wallet record updated successfully");
} else {
    // Print a failure message
    jsonError($message = "Failed to update wallet record");
}
?>

File: ride/passengerWallet/get.php

<?php
require_once __DIR__ . '/../../connect.php';
$passenger_id = filterRequest("passenger_id");

$sql = "SELECT
    passengerWallet.`id`,
    passengerWallet.`passenger_id`,
    SUM(passengerWallet.balance) AS total,
    passengers.first_name,
    passengers.last_name,
    passengers.phone,
    passengers.email
FROM
    `passengerWallet`
LEFT JOIN passengers ON passengers.id = passengerWallet.passenger_id
GROUP BY
    passenger_id";
$stmt = $con->prepare($sql);
$stmt->execute();

if ($stmt->rowCount() > 0) {
    // Fetch the record
    $row = $stmt->fetchAll(PDO::FETCH_ASSOC);

    jsonSuccess($row);
    
}
    else{
    // Print a failure message
    jsonError($message = "No wallet record found");
}
?>

File: ride/passengerWallet/addPaymentTokenPassenger.php

<?php
require_once __DIR__ . '/../../connect.php';

$passengerId = filterRequest("passengerId");
$amount = filterRequest("amount");

// Check if required fields are present
if ($passengerId === null || $amount === null) {
    jsonError("Missing required fields: passengerId and amount must be provided");
    exit;
}

// Generate the token using current time
$token = generateSecureToken($passengerId, $amount, date('Y-m-d H:i:s', time()));

// Store the token in the database, using NOW() for dateCreated
$stmt = $con->prepare("INSERT INTO payment_tokens_passenger (token, passengerId, dateCreated, amount) VALUES (?, ?, NOW(), ?)");

try {
    $stmt->execute([$token, $passengerId, $amount]);
    if ($stmt->rowCount() > 0) {
        jsonSuccess($token);
    } else {
        jsonError("Failed to save record");
    }
} catch (PDOException $e) {
    jsonError("Database error: " . $e->getMessage());
}

// Rest of your code including the generateSecureToken function...

// Rest of your code including the generateSecureToken function...

function generateSecureToken($passengerId, $amount, $dateCreated) {
    global $secretKey;
    // Concatenate the parameters
    $data = $passengerId . $amount . $dateCreated;

    // Add the secret key from the environment variable
    $data .= $secretKey;

    // Generate a hash
    $hash = hash('sha256', $data);

    // Add some randomness
    $randomBytes = bin2hex(random_bytes(16));

    // Combine hash and random bytes
    $token = $hash . $randomBytes;

    // Truncate to a reasonable length (e.g., 64 characters)
    return substr($token, 0, 64);
}

File: ride/passengerWallet/getPassengerWalletArchive.php

<?php
require_once __DIR__ . '/../../connect.php';
$passenger_id = filterRequest("passenger_id");

$sql = "SELECT
    passengerWallet.`id`,
    passengerWallet.balance,
    passengerWallet.`created_at`
FROM
    `passengerWallet`
WHERE
    passenger_id = '$passenger_id'AND created_at >= DATE_SUB(NOW(), INTERVAL 1 MONTH)
ORDER BY
    `passengerWallet`.`id`
DESC";
$stmt = $con->prepare($sql);
$stmt->execute();

if ($stmt->rowCount() > 0) {
    // Fetch the record
    $row = $stmt->fetchAll(PDO::FETCH_ASSOC);

    jsonSuccess($row);
    
}
    else{
    // Print a failure message
    jsonError($message = "No wallet record found");
}
?>

File: ride/passengerWallet/getWalletByPassenger.php

<?php
require_once __DIR__ . '/../../connect.php';
$passenger_id = filterRequest("passenger_id");

$sql = "SELECT 
    COALESCE(pw.`id`, 0) AS id,
    COALESCE(pw.`passenger_id`, '$passenger_id') AS passenger_id,
    COALESCE(SUM(pw.balance), 0) AS total,
    COALESCE(p.first_name, '') AS first_name,
    COALESCE(p.last_name, '') AS last_name,
    COALESCE(p.phone, '') AS phone
FROM 
    (SELECT '$passenger_id' AS passenger_id) AS dummy
LEFT JOIN `passengerWallet` pw ON pw.passenger_id = dummy.passenger_id
LEFT JOIN passengers p ON p.id = pw.passenger_id
GROUP BY 
    dummy.passenger_id, pw.id, p.first_name, p.last_name, p.phone
LIMIT 0, 25;
";
$stmt = $con->prepare($sql);
$stmt->execute();

if ($stmt->rowCount() > 0) {
    // Fetch the record
    $row = $stmt->fetchAll(PDO::FETCH_ASSOC);

    jsonSuccess($row);
    
}
    else{
    // Print a failure message
    jsonError($message = "No wallet record found");
}
?>

File: ride/passengerWallet/getAllPassengerTransaction.php

<?php
require_once __DIR__ . '/../../connect.php';
$passenger_id = filterRequest("passenger_id");

$sql = "SELECT
    `id`,
    `passenger_id`,
    `balance`,
    `created_at`,
    `updated_at`,
    (
    SELECT
        SUM(balance)
    FROM
        passengerWallet
    WHERE
        passenger_id = '$passenger_id'
) AS total
FROM
    `passengerWallet`
WHERE
    passenger_id = '$passenger_id'
GROUP BY
    `passenger_id`,
    `id`;";
$stmt = $con->prepare($sql);
$stmt->execute();

if ($stmt->rowCount() > 0) {
    // Fetch the record
    $row = $stmt->fetchAll(PDO::FETCH_ASSOC);

    jsonSuccess($row);
    
}
    else{
    // Print a failure message
    jsonError($message = "No wallet record found");
}
?>

File: ride/passengerWallet/delete.php

<?php
require_once __DIR__ . '/../../connect.php';

$id = filterRequest("id");

$sql = "DELETE FROM `passengerWallet` WHERE `id` = '$id'";
$stmt = $con->prepare($sql);
$stmt->execute();

if ($stmt->rowCount() > 0) {
    // Print a success message
    jsonSuccess($message = "Wallet record deleted successfully");
} else {
    // Print a failure message
    jsonError($message = "Failed to delete wallet record");
}
?>

File: ride/driver_behavior/get_driver_behavior.php

<?php
require_once __DIR__ . '/../../connect.php';

try {
    $driver_id = filterRequest("driver_id");

    // ✅ أولاً: حساب متوسط السلوك لجميع الرحلات
    $sql_average = "SELECT COALESCE(AVG(behavior_score), 100) AS overall_behavior_score
                    FROM driver_behavior
                    WHERE driver_id = :driver_id";

    $stmt_avg = $con->prepare($sql_average);
    $stmt_avg->bindParam(':driver_id', $driver_id);
    $stmt_avg->execute();
    $average = $stmt_avg->fetch(PDO::FETCH_ASSOC);

    // ✅ ثانياً: جلب آخر 10 رحلات
    $sql_last10 = "SELECT id, trip_id, max_speed, avg_speed, hard_brakes, total_distance, behavior_score, created_at
                   FROM driver_behavior
                   WHERE driver_id = :driver_id
                   ORDER BY id DESC
                   LIMIT 10";

    $stmt_last10 = $con->prepare($sql_last10);
    $stmt_last10->bindParam(':driver_id', $driver_id);
    $stmt_last10->execute();
    $last10 = $stmt_last10->fetchAll(PDO::FETCH_ASSOC);

    // ✅ تجهيز الاستجابة النهائية
    $response = [
        'overall_behavior_score' => $average['overall_behavior_score'],
        'last_10_trips' => $last10
    ];

    jsonSuccess($response);

} catch (PDOException $e) {
    jsonError("Database error: " . $e->getMessage());
}
?>

File: ride/invitor/add.php

<?php

require_once __DIR__ . '/../../connect.php';

function generateUniqueCode($con, $length = 7) {
    while (true) {
        $letters = substr(str_shuffle("ABCDEFGHIJKLMNOPQRSTUVWXYZ"), 0, 4);
        $numbers = substr(str_shuffle("0123456789"), 0, 3);
        $code = $letters . $numbers;

        $stmt = $con->prepare("SELECT COUNT(*) FROM invites WHERE inviteCode = ?");
        $stmt->execute([$code]);

        if ($stmt->fetchColumn() == 0) {
            return $code;
        }
    }
}

$driverId = filterRequest("driverId");
$inviterDriverPhone = filterRequest("inviterDriverPhone");

// 🔐 تشفير رقم الهاتف
$inviterDriverPhoneEncrypted = $encryptionHelper->encryptData($inviterDriverPhone);

// تحقق من وجود رقم الهاتف مسبقًا
$checkSql = "SELECT `id`, `inviteCode`, `isInstall` FROM `invites` WHERE `inviterDriverPhone` = :inviterDriverPhone";
$checkStmt = $con->prepare($checkSql);
$checkStmt->bindParam(':inviterDriverPhone', $inviterDriverPhoneEncrypted, PDO::PARAM_STR);
$checkStmt->execute();

if ($checkStmt->rowCount() > 0) {
    $existingInvite = $checkStmt->fetch(PDO::FETCH_ASSOC);

    if ($existingInvite['isInstall'] == 1) {
        jsonError($existingInvite['inviteCode']);
    } else {
        // تحديث الدعوة الحالية
        $updateSql = "UPDATE `invites` SET `driverId` = :driverId, `expirationTime` = :expirationTime, `createdAt` = NOW() WHERE `id` = :id";
        $updateStmt = $con->prepare($updateSql);
        $expirationTime = date('Y-m-d H:i:s', strtotime('+1 hour'));
        $updateStmt->bindParam(':driverId', $driverId, PDO::PARAM_INT);
        $updateStmt->bindParam(':expirationTime', $expirationTime);
        $updateStmt->bindParam(':id', $existingInvite['id'], PDO::PARAM_INT);

        try {
            $updateStmt->execute();
            printSuccess([
                "message" => "Invite updated successfully",
                "inviteId" => $existingInvite['id'],
                "inviteCode" => $existingInvite['inviteCode'],
                "expirationTime" => $expirationTime
            ]);
        } catch (PDOException $e) {
            jsonError("Database error: " . $e->getMessage());
        }
    }

} else {
    // إنشاء دعوة جديدة
    $inviteCode = generateUniqueCode($con);
    $expirationTime = date('Y-m-d H:i:s', strtotime('+1 hour'));

    $sql = "INSERT INTO `invites` (`driverId`, `inviterDriverPhone`, `inviteCode`, `expirationTime`, `createdAt`, `isInstall`) 
            VALUES (:driverId, :inviterDriverPhone, :inviteCode, :expirationTime, NOW(), 0)";
    $stmt = $con->prepare($sql);
    $stmt->bindParam(':driverId', $driverId, PDO::PARAM_INT);
    $stmt->bindParam(':inviterDriverPhone', $inviterDriverPhoneEncrypted, PDO::PARAM_STR);
    $stmt->bindParam(':inviteCode', $inviteCode);
    $stmt->bindParam(':expirationTime', $expirationTime);

    try {
        $stmt->execute();
        if ($stmt->rowCount() > 0) {
            $insertedID = $con->lastInsertId();
            printSuccess([
                "message" => "Invite created successfully",
                "inviteId" => $insertedID,
                "inviteCode" => $inviteCode,
                "expirationTime" => $expirationTime
            ]);
        } else {
            jsonError("Failed to save invite data");
        }
    } catch (PDOException $e) {
        jsonError("Database error: " . $e->getMessage());
    }
}
?>

File: ride/invitor/update.php

<?php
require_once __DIR__ . '/../../connect.php';

$id = filterRequest("id");

$sql = "UPDATE `invites` SET `isGiftToken` = 1 WHERE `id` = :id";
$stmt = $con->prepare($sql);
$stmt->bindParam(':id', $id, PDO::PARAM_INT);
$stmt->execute();

if ($stmt->rowCount() > 0) {
    jsonSuccess(null, "Record updated successfully.");
} else {
    jsonError("No records were updated");
}
?>

File: ride/invitor/getDriverInvitationToPassengers.php

<?php
require_once __DIR__ . '/../../connect.php';

$driverId = filterRequest("driverId");

$sql = "SELECT
    i.`id`,
    i.`driverId`,
    i.inviterPassengerPhone,
    i.`createdAt`,
    i.`isInstall`,
    p.`id` AS passengerId,
    p.first_name AS passengerName,
    COALESCE(r.finishedTrips, 0) AS countOfInvitDriver
FROM
    invitesToPassengers i
LEFT JOIN `driver` d ON
    d.id = i.driverId
LEFT JOIN passengers p ON
    p.phone = i.inviterPassengerPhone
LEFT JOIN (
    SELECT passenger_id,
           COUNT(*) AS finishedTrips
    FROM ride
    WHERE `status` = 'Finished'
    GROUP BY passenger_id
) r ON r.passenger_id = i.passengerID
WHERE
    i.driverId = :driverId AND i.isInstall = 1 AND p.id != ''";

$stmt = $con->prepare($sql);
$stmt->bindParam(':driverId', $driverId, PDO::PARAM_INT);
$stmt->execute();

if ($stmt->rowCount() > 0) {
    $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);

    // 🔓 فك التشفير للحقول المطلوبة
    foreach ($rows as &$row) {
        $row['inviterPassengerPhone'] = $encryptionHelper->decryptData($row['inviterPassengerPhone']);
        $row['passengerName']         = $encryptionHelper->decryptData($row['passengerName']);
    }

    jsonSuccess($rows);
} else {
    jsonError("No records found.");
}
?>

File: ride/invitor/get.php

<?php
require_once __DIR__ . '/../../connect.php';

$driverId = filterRequest("driverId");

$sql = "SELECT 
    i.`id`,
    i.`driverId`,
    i.`inviterDriverPhone`,
    i.`createdAt`,
    i.`isInstall`,
    d.`id` AS driverInviterId,
    d.`phone` AS invitorPhone,
    d.`name_arabic` AS invitorName,
    COALESCE(r.finishedTrips, 0) AS countOfInvitDriver
FROM 
    `invites` i
LEFT JOIN `driver` d ON d.phone = i.inviterDriverPhone
LEFT JOIN (
    SELECT 
        driver_id, 
        COUNT(*) AS finishedTrips
    FROM 
        ride
    WHERE 
        status = 'Finished'
    GROUP BY 
        driver_id
) r ON r.driver_id = d.id
WHERE 
    i.driverId = :driverId
    AND i.isInstall = 1";

$stmt = $con->prepare($sql);
$stmt->bindParam(':driverId', $driverId, PDO::PARAM_INT);
$stmt->execute();

if ($stmt->rowCount() > 0) {
    $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);

    // 🔓 فك التشفير للحقول المطلوبة
    foreach ($rows as &$row) {
        $row['inviterDriverPhone'] = $encryptionHelper->decryptData($row['inviterDriverPhone']);
        $row['invitorPhone']       = $encryptionHelper->decryptData($row['invitorPhone']);
        $row['invitorName']        = $encryptionHelper->decryptData($row['invitorName']);
    }

    jsonSuccess($rows);
} else {
    jsonError("No records found.");
}
?>

File: ride/invitor/updatePassengersInvitation.php

<?php
require_once __DIR__ . '/../../connect.php';

$inviteCode = filterRequest("inviteCode");
$passengerID = filterRequest("passengerID");

if (empty($inviteCode) || empty($passengerID)) {
    jsonError("Invalid or missing invite code or passenger ID.");
    exit;
}

// 🔐 تشفير كود الدعوة قبل البحث
$inviteCodeEncrypted = $encryptionHelper->encryptData($inviteCode);

try {
    $checkSql = "SELECT `id`, `expirationTime` FROM `invitesToPassengers` 
                 WHERE `inviteCode` = :inviteCode 
                 AND `isInstall` = 0 
                 AND `isGiftToken` = 0";

    $checkStmt = $con->prepare($checkSql);
    $checkStmt->bindParam(':inviteCode', $inviteCodeEncrypted);
    $checkStmt->execute();
    
    if ($checkStmt->rowCount() > 0) {
        $invite = $checkStmt->fetch(PDO::FETCH_ASSOC);

        $updateSql = "UPDATE `invitesToPassengers` 
                      SET `isInstall` = 1, `passengerID` = :passengerID 
                      WHERE `id` = :id";

        $updateStmt = $con->prepare($updateSql);
        $updateStmt->bindParam(':id', $invite['id'], PDO::PARAM_INT);
        $updateStmt->bindParam(':passengerID', $passengerID);
        $updateStmt->execute();

        if ($updateStmt->rowCount() > 0) {
            jsonSuccess(null, "Invite code successfully used and marked as installed.");
        } else {
            jsonError("Invite found but update failed.");
        }
    } else {
        jsonError("Invalid invite code, already used, or marked as gift.");
    }
} catch (PDOException $e) {
    jsonError("Database error: " . $e->getMessage());
}
?>

File: ride/invitor/updatePassengerGift.php

<?php
require_once __DIR__ . '/../../connect.php';

$id = filterRequest("id");

$sql = "UPDATE `invitesToPassengers` SET `isGiftToken` = 1 WHERE `id` = :id";
$stmt = $con->prepare($sql);
$stmt->bindParam(':id', $id, PDO::PARAM_INT);
$stmt->execute();

if ($stmt->rowCount() > 0) {
    jsonSuccess(null, "Record updated successfully.");
} else {
    jsonError("No records were updated");
}
?>

File: ride/invitor/addInvitationPassenger.php

<?php
require_once __DIR__ . '/../../connect.php';

function generateUniqueCode($con, $length = 7) {
    while (true) {
        $letters = substr(str_shuffle("ABCDEFGHIJKLMNOPQRSTUVWXYZ"), 0, 4);
        $numbers = substr(str_shuffle("0123456789"), 0, 3);
        $code = $letters . $numbers;

        $stmt = $con->prepare("SELECT COUNT(*) FROM invitesToPassengers WHERE inviteCode = ?");
        $stmt->execute([$code]);

        if ($stmt->fetchColumn() == 0) {
            return $code;
        }
    }
}

$driverId = filterRequest("driverId");
$inviterPassengerPhone = filterRequest("inviterPassengerPhone");

// 🔐 تشفير رقم الهاتف
$inviterPassengerPhoneEncrypted = $encryptionHelper->encryptData($inviterPassengerPhone);

// التحقق من وجود الرقم مسبقًا
$checkSql = "SELECT `id`, `inviteCode`, `isInstall`, `isGiftToken` FROM `invitesToPassengers` WHERE `inviterPassengerPhone` = :inviterPassengerPhone";
$checkStmt = $con->prepare($checkSql);
$checkStmt->bindParam(':inviterPassengerPhone', $inviterPassengerPhoneEncrypted, PDO::PARAM_STR);
$checkStmt->execute();

if ($checkStmt->rowCount() > 0) {
    $existingInvite = $checkStmt->fetch(PDO::FETCH_ASSOC);

    if ($existingInvite['isInstall'] == 1 || $existingInvite['isGiftToken'] == 1) {
        printFailure([
            "message" => "Invite code already used or gift token already applied",
            "inviteCode" => $existingInvite['inviteCode']
        ]);
    } else {
        // تحديث الدعوة
        $updateSql = "UPDATE `invitesToPassengers` SET `driverId` = :driverId, `expirationTime` = :expirationTime, `createdAt` = NOW() WHERE `id` = :id";
        $updateStmt = $con->prepare($updateSql);
        $expirationTime = date('Y-m-d H:i:s', strtotime('+1 hour'));
        $updateStmt->bindParam(':driverId', $driverId, PDO::PARAM_INT);
        $updateStmt->bindParam(':expirationTime', $expirationTime);
        $updateStmt->bindParam(':id', $existingInvite['id'], PDO::PARAM_INT);

        try {
            $updateStmt->execute();
            printSuccess([
                "message" => "Invite updated successfully",
                "inviteId" => $existingInvite['id'],
                "inviteCode" => $existingInvite['inviteCode'],
                "expirationTime" => $expirationTime
            ]);
        } catch (PDOException $e) {
            jsonError("Database error: " . $e->getMessage());
        }
    }
} else {
    // إنشاء دعوة جديدة
    $inviteCode = generateUniqueCode($con);
    $expirationTime = date('Y-m-d H:i:s', strtotime('+4 hour'));

    $sql = "INSERT INTO `invitesToPassengers` 
            (`driverId`, `inviterPassengerPhone`, `inviteCode`, `expirationTime`, `createdAt`, `isInstall`, `isGiftToken`) 
            VALUES 
            (:driverId, :inviterPassengerPhone, :inviteCode, :expirationTime, NOW(), 0, 0)";
    
    $stmt = $con->prepare($sql);
    $stmt->bindParam(':driverId', $driverId, PDO::PARAM_INT);
    $stmt->bindParam(':inviterPassengerPhone', $inviterPassengerPhoneEncrypted, PDO::PARAM_STR);
    $stmt->bindParam(':inviteCode', $inviteCode);
    $stmt->bindParam(':expirationTime', $expirationTime);

    try {
        $stmt->execute();
        if ($stmt->rowCount() > 0) {
            $insertedID = $con->lastInsertId();
            printSuccess([
                "message" => "Invite created successfully",
                "inviteId" => $insertedID,
                "inviteCode" => $inviteCode,
                "expirationTime" => $expirationTime
            ]);
        } else {
            jsonError("Failed to save invite data");
        }
    } catch (PDOException $e) {
        jsonError("Database error: " . $e->getMessage());
    }
}
?>

File: ride/invitor/updateInvitationCodeFromRegister.php

<?php
require_once __DIR__ . '/../../connect.php';

$inviteCode = filterRequest("inviteCode");

if (empty($inviteCode)) {
    jsonError("Invalid or missing invite code.");
    exit;
}

try {
    $checkSql = "SELECT `id`, `expirationTime`, `driverId` FROM `invites` 
                 WHERE `inviteCode` = :inviteCode 
                 AND `isInstall` = 0 
                 AND `expirationTime` > NOW()";
    
    $checkStmt = $con->prepare($checkSql);
    $checkStmt->bindParam(':inviteCode', $inviteCode);
    $checkStmt->execute();
    
    if ($checkStmt->rowCount() > 0) {
        $invite = $checkStmt->fetch(PDO::FETCH_ASSOC);

        $updateSql = "UPDATE `invites` SET `isInstall` = 1 WHERE `id` = :id";
        $updateStmt = $con->prepare($updateSql);
        $updateStmt->bindParam(':id', $invite['id'], PDO::PARAM_INT);
        $updateStmt->execute();

        if ($updateStmt->rowCount() > 0) {
            printSuccess([
                "message" => "Invite code successfully used and marked as installed.",
                "driverId" => $invite['driverId'],
                "expirationTime" => $invite['expirationTime']
            ]);
        } else {
            jsonError("Failed to update the invite record.");
        }
    } else {
        jsonError("Invalid invite code, already installed, or expired.");
    }
} catch (PDOException $e) {
    jsonError("Database error: " . $e->getMessage());
}
?>

File: ride/invitor/updateDriverInvitationDirectly.php

<?php
require_once __DIR__ . '/../../connect.php';

$inviterDriverPhone = filterRequest("inviterDriverPhone");

if (empty($inviterDriverPhone)) {
    jsonError("Invalid or missing inviter phone.");
    exit;
}

try {
    // تشفير الرقم
    $inviterDriverPhoneEncrypted = $encryptionHelper->encryptData($inviterDriverPhone);

    // ✅ الآن الاستعلام نظيف وطبيعي جداً لأن قاعدة البيانات تم إصلاحها
    $fetchSql = "SELECT
        i.`id`,
        i.`driverId`,
        i.`inviterDriverPhone`,
        i.`createdAt`,
        i.`inviteCode`,
        i.`isInstall`,
        i.`isGiftToken`,
        i.`expirationTime`,
        dt.token
    FROM `invites` i
    LEFT JOIN `driverToken` dt ON dt.captain_id = i.driverId
    WHERE i.`inviterDriverPhone` = :inviterDriverPhone 
        AND i.`expirationTime` > NOW()";

    $fetchStmt = $con->prepare($fetchSql);
    $fetchStmt->bindParam(':inviterDriverPhone', $inviterDriverPhoneEncrypted);
    $fetchStmt->execute();

    if ($fetchStmt->rowCount() > 0) {
        $invite = $fetchStmt->fetch(PDO::FETCH_ASSOC);

        // فك التشفير
        $invite['inviterDriverPhone'] = $encryptionHelper->decryptData($invite['inviterDriverPhone']);
        if (!empty($invite['token'])) {
            $invite['token'] = $encryptionHelper->decryptData($invite['token']);
        }

        // التحديث
        $updateSql = "UPDATE `invites` SET `isInstall` = 1 WHERE `id` = :id";
        $updateStmt = $con->prepare($updateSql);
        $updateStmt->bindParam(':id', $invite['id'], PDO::PARAM_INT);
        $updateStmt->execute();

        printSuccess("Record found and updated successfully.", $invite);
    } else {
        jsonError("No records found.");
    }

} catch (PDOException $e) {
    error_log("DB Error: " . $e->getMessage());
    jsonError("Database error: " . $e->getMessage());
}
?>

File: ride/seferWallet/add.php

<?php
require_once __DIR__ . '/../../connect.php';
$driver_id = filterRequest("driverId");
$passenger_id = filterRequest("passengerId");
$amount = filterRequest("amount");
$payment_method = filterRequest("paymentMethod");
$token = filterRequest("token");

$sql = "INSERT INTO `seferWallet` (
    `driverId`,
    `passengerId`,
    `amount`,
    `paymentMethod`,
    `token`,
    `createdAt`
) VALUES (
    :driver_id,
    :passenger_id,
    :amount,
    :payment_method,
    :token,
    CURRENT_TIMESTAMP
)";

$stmt = $con->prepare($sql);
$stmt->bindParam(':driver_id', $driver_id, PDO::PARAM_STR);
$stmt->bindParam(':passenger_id', $passenger_id, PDO::PARAM_STR);
$stmt->bindParam(':amount', $amount, PDO::PARAM_STR);
$stmt->bindParam(':payment_method', $payment_method, PDO::PARAM_STR);
$stmt->bindParam(':token', $token, PDO::PARAM_STR);

if ($stmt->execute()) {
    // Print a success message
    jsonSuccess($message = "Wallet data saved successfully");
} else {
    // Print a failure message
    jsonError($message = "Failed to save wallet data");
}
?>

File: ride/seferWallet/get.php

<?php

require_once __DIR__ . '/../../connect.php';

$driver_id = filterRequest("driver_id");
$order_id = filterRequest("order_id");

$sql = "SELECT
    SUM(amount)
FROM
    `seferWallet`
WHERE
    createdAt BETWEEN DATE_FORMAT(CURRENT_DATE, '%Y-%m-01') AND LAST_DAY(CURRENT_DATE)";

$stmt = $con->prepare($sql);
$stmt->execute();
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);

if ($stmt->rowCount() > 0) {
    // Print the retrieved data
    // echo json_encode($result);
     jsonSuccess($data = $result);
} else {
    // Print a failure message
    
     jsonError($message = "No driver order data found");
}

?>

File: ride/notificationCaptain/add.php

<?php

require_once __DIR__ . '/../../connect.php';

$driverID = filterRequest("driverID");
$title = filterRequest("title");
$body = filterRequest("body");
$isPin = filterRequest("isPin");

$sql = "INSERT INTO `notificationCaptain` (
  `driverID`,
  `title`,
  `body`,
  `isPin`
) VALUES (
  :driverID,
  :title,
  :body,
  :isPin
)";

$stmt = $con->prepare($sql);
$stmt->execute([
    ':driverID' => $driverID,
    ':title'    => $title,
    ':body'     => $body,
    ':isPin'    => $isPin
]);

if ($stmt->rowCount() > 0) {
    jsonSuccess(null, "Notification data saved successfully");
} else {
    jsonError("Failed to save notification data");
}

?>

File: ride/notificationCaptain/update.php

<?php
require_once __DIR__ . '/../../connect.php';

$id = filterRequest("id");

// Array to hold the SET parts and parameters
$columnValues = [];
$params = [':id' => $id];

if (isset($_POST["driverID"])) {
    $columnValues[] = "`driverID` = :driverID";
    $params[':driverID'] = filterRequest("driverID");
}

if (isset($_POST["title"])) {
    $columnValues[] = "`title` = :title";
    $params[':title'] = filterRequest("title");
}

if (isset($_POST["body"])) {
    $columnValues[] = "`body` = :body";
    $params[':body'] = filterRequest("body");
}

if (isset($_POST["isShown"])) {
    $columnValues[] = "`isShown` = :isShown";
    $params[':isShown'] = filterRequest("isShown");
}

if (isset($_POST["dateCreated"])) {
    $columnValues[] = "`dateCreated` = :dateCreated";
    $params[':dateCreated'] = filterRequest("dateCreated");
}

// Check if there are fields to update
if (empty($columnValues)) {
    jsonError("No fields to update");
    exit;
}

$setClause = implode(", ", $columnValues);
$sql = "UPDATE `notificationCaptain` SET $setClause WHERE `id` = :id";

$stmt = $con->prepare($sql);
$stmt->execute($params);

if ($stmt->rowCount() > 0) {
    jsonSuccess(null, "Notification data updated successfully");
} else {
    jsonError("Failed to update notification data");
}
?>

File: ride/notificationCaptain/get.php

<?php
require_once __DIR__ . '/../../connect.php';

$driverID = filterRequest("driverID");

$sql = "SELECT * FROM `notificationCaptain`
        WHERE `driverID` = :driverID
        AND `dateCreated` > DATE_SUB(NOW(), INTERVAL 2 DAY)
        ORDER BY `dateCreated` DESC
        LIMIT 10";

$stmt = $con->prepare($sql);
$stmt->bindParam(':driverID', $driverID, PDO::PARAM_STR);
$stmt->execute();

$notifications = $stmt->fetchAll(PDO::FETCH_ASSOC);

if ($notifications) {
    jsonSuccess($notifications);
} else {
    jsonError("No notification data found");
}
?>

File: ride/notificationCaptain/addWaitingRide.php

<?php
require_once __DIR__ . '/../../connect.php';

try {
    $requiredParams = [
        'id', 'start_location', 'end_location', 'price', 
        'passenger_id', 'status', 'carType', 'price_for_passenger', 
        'distance', 'passengerRate', 'duration'
    ];
    
    $params = [];
    foreach ($requiredParams as $param) {
        $value = filterRequest($param);
        if ($value === null) {
            throw new Exception("Missing required parameter: $param");
        }
        $params[$param] = $value;
    }

    // استخراج lat/lng من start_location و end_location
    $startCoords = explode(',', $params['start_location']);
    $endCoords = explode(',', $params['end_location']);
    
    $params['start_lat'] = trim($startCoords[0]);
    $params['start_lng'] = trim($startCoords[1]);
    $params['end_lat'] = trim($endCoords[0]);
    $params['end_lng'] = trim($endCoords[1]);

    // استخدام INSERT ... ON DUPLICATE KEY UPDATE (أفضل من فحص منفصل)
    $sql = "INSERT INTO waitingRides (
        id, start_location, end_location, start_lat, start_lng, 
        end_lat, end_lng, date, time, price, passenger_id, 
        status, carType, passengerRate, created_at, 
        price_for_passenger, distance, duration
    ) VALUES (
        :id, :start_location, :end_location, :start_lat, :start_lng,
        :end_lat, :end_lng, CURDATE(), CURTIME(), :price, :passenger_id,
        :status, :carType, :passengerRate, NOW(),
        :price_for_passenger, :distance, :duration
    ) ON DUPLICATE KEY UPDATE
        start_location = VALUES(start_location),
        end_location = VALUES(end_location),
        start_lat = VALUES(start_lat),
        start_lng = VALUES(start_lng),
        end_lat = VALUES(end_lat),
        end_lng = VALUES(end_lng),
        date = CURDATE(),
        time = CURTIME(),
        price = VALUES(price),
        status = VALUES(status),
        carType = VALUES(carType),
        passengerRate = VALUES(passengerRate),
        price_for_passenger = VALUES(price_for_passenger),
        distance = VALUES(distance),
        duration = VALUES(duration)";

    $stmt = $con->prepare($sql);
    $stmt->execute($params);

    if ($stmt->rowCount() > 0) {
        jsonSuccess(null, "Operation completed successfully");
    } else {
        jsonSuccess(null, "No changes made");
    }

} catch (PDOException $e) {
    error_log("Database error in addWaitingRide: " . $e->getMessage());
    jsonError("Database error: " . $e->getMessage());
} catch (Exception $e) {
    jsonError("Error: " . $e->getMessage());
}
?>

File: ride/notificationCaptain/deleteAvailableRide.php

<?php
require_once __DIR__ . '/../../connect.php';

try {
    // Retrieve and validate the 'id' parameter
    $id = filterRequest('id');
    if ($id === null || $id === '') {
        throw new Exception("Missing required parameter: id");
    }

    // Prepare the SQL query to delete the record
    $sql = "DELETE FROM `waitingRides` WHERE `id` = :id";

    // Prepare and execute the statement
    $stmt = $con->prepare($sql);
    $stmt->bindParam(':id', $id, PDO::PARAM_INT);
    $stmt->execute();

    // Check the result and print the appropriate message
    if ($stmt->rowCount() > 0) {
        jsonSuccess(null, "Record with ID $id deleted successfully.");
    } else {
        jsonError("No record found with ID $id.");
    }
} catch (PDOException $e) {
    jsonError("Database error: " . $e->getMessage());
} catch (Exception $e) {
    jsonError("Error: " . $e->getMessage());
}
?>

File: ride/notificationCaptain/delete.php

<?php

require_once __DIR__ . '/../../connect.php';

$notificationID = filterRequest("id");

$sql = "DELETE FROM `notificationCaptain` WHERE `id` = :id";
$stmt = $con->prepare($sql);
$stmt->bindParam(':id', $notificationID, PDO::PARAM_INT);
$stmt->execute();

if ($stmt->rowCount() > 0) {
    jsonSuccess(null, "Notification data deleted successfully");
} else {
    jsonError("Failed to delete notification data");
}

?>

File: ride/notificationCaptain/getRideWaiting.php

<?php
// getRideWaiting.php
require_once __DIR__ . '/../../connect.php';

$lat = filterRequest("lat"); 
$lng = filterRequest("lng"); 
$radius = filterRequest("radius"); 

if (empty($lat) || empty($lng)) {
    jsonSuccess([]); 
    exit;
}

if (empty($radius)) {
    $radius = 50; 
}

$finalRides = [];
$rideIds = [];
$redisResultsMap = [];

// 1. محاولة البحث عبر Redis
try {
    $locationServerUrl = "http://location.intaleq.xyz:2021"; 
    $INTERNAL_KEY = trim(@file_get_contents('/home/siro-api/.internal_socket_key'));

    $postData = [
        'action' => 'get_nearby_ride_ids',
        'lat'    => $lat,
        'lng'    => $lng,
        'radius' => $radius
    ];

    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $locationServerUrl);
    curl_setopt($ch, CURLOPT_POST, 1);
    curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData));
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_TIMEOUT_MS, 500); 
    curl_setopt($ch, CURLOPT_HTTPHEADER, ["x-internal-key: $INTERNAL_KEY"]);

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

    if ($httpCode == 200 && $response) {
        $jsonResults = json_decode($response, true);
        if (is_array($jsonResults) && !empty($jsonResults)) {
            foreach ($jsonResults as $res) {
                $rideIds[] = $res[0];
                $redisResultsMap[$res[0]] = $res[1];
            }
        }
    }
} catch (Exception $e) {
    // نتابع للخطة ب
}

// 2. جلب البيانات (إما عبر IDs أو بحث مباشر)
try {
    if (!empty($rideIds)) {
        // --- الحالة أ: الريدز وجد رحلات ---
        $placeholders = implode(',', array_fill(0, count($rideIds), '?'));
        
        $sql = "
            SELECT 
                wr.id, wr.start_location AS startName, wr.end_location AS endName, 
                wr.date, wr.time, wr.price, wr.passenger_id, wr.status, wr.carType, 
                wr.passengerRate, wr.created_at, wr.price_for_passenger, 
                wr.distance, wr.duration, wr.start_lat, wr.start_lng, 
                wr.end_lat, wr.end_lng, wr.payment_method, wr.passenger_wallet,
                p.email, p.first_name, p.phone, p.id AS passengerId, t.token AS passengerToken
            FROM waitingRides wr
            INNER JOIN passengers p ON p.id = wr.passenger_id
            LEFT JOIN tokens t ON t.passengerID = wr.passenger_id
            LEFT JOIN passengerWallet pw ON pw.passenger_id = wr.passenger_id
            WHERE wr.id IN ($placeholders) AND wr.status IN ('wait', 'waiting')
        ";
        
        $stmt = $con->prepare($sql);
        $stmt->execute($rideIds); 
        $waitingRides = $stmt->fetchAll(PDO::FETCH_ASSOC);

    } else {
        // --- الحالة ب: بحث مباشر MySQL (Fallback) ---
        // 🔥 التصحيح هنا: استخدام أسماء فريدة (:lat1, :lat2) لتجنب خطأ التكرار
        
        $haversine = "( 6371 * acos( cos( radians(:lat1) ) * cos( radians( wr.start_lat ) ) * cos( radians( wr.start_lng ) - radians(:lng) ) + sin( radians(:lat2) ) * sin( radians( wr.start_lat ) ) ) )";

        $sql = "
            SELECT 
                wr.id, wr.start_location AS startName, wr.end_location AS endName, 
                wr.date, wr.time, wr.price, wr.passenger_id, wr.status, wr.carType, 
                wr.passengerRate, wr.created_at, wr.price_for_passenger, 
                wr.distance, wr.duration, wr.start_lat, wr.start_lng, 
                wr.end_lat, wr.end_lng, wr.payment_method, wr.passenger_wallet,
                p.email, p.first_name, p.phone, p.id AS passengerId, t.token AS passengerToken,
                {$haversine} AS driver_distance_km
            FROM waitingRides wr
            INNER JOIN passengers p ON p.id = wr.passenger_id
            LEFT JOIN tokens t ON t.passengerID = wr.passenger_id
            LEFT JOIN passengerWallet pw ON pw.passenger_id = wr.passenger_id
            WHERE 
                wr.status IN ('wait', 'waiting')
                AND wr.created_at >= DATE_SUB(NOW(), INTERVAL 24 HOUR)
                AND wr.start_lat IS NOT NULL
            HAVING driver_distance_km <= :radius
            ORDER BY driver_distance_km ASC
            LIMIT 50
        ";

        $stmt = $con->prepare($sql);
        
        // نمرر القيمة مرتين للمفتاحين المختلفين
        $stmt->execute([
            ':lat1'   => $lat,
            ':lng'    => $lng,
            ':lat2'   => $lat, // تكرار القيمة للمتغير الثاني
            ':radius' => $radius
        ]);
        
        $waitingRides = $stmt->fetchAll(PDO::FETCH_ASSOC);
    }

    // 3. التنسيق
    foreach ($waitingRides as $ride) {
        $ride['phone']      = $encryptionHelper->decryptData($ride['phone'] ?? '');
        $ride['first_name'] = $encryptionHelper->decryptData($ride['first_name'] ?? '');
        $ride['email']      = $encryptionHelper->decryptData($ride['email'] ?? '');

        $ride['start_location'] = $ride['start_lat'] . ',' . $ride['start_lng'];
        $ride['end_location'] = (!empty($ride['end_lat'])) 
            ? $ride['end_lat'] . ',' . $ride['end_lng'] 
            : $ride['endName'];

        $ride['id'] = (string)$ride['id'];

        if (isset($ride['driver_distance_km'])) {
            $ride['driver_distance_km'] = number_format((float)$ride['driver_distance_km'], 1);
        } elseif (isset($redisResultsMap[$ride['id']])) {
            $ride['driver_distance_km'] = number_format((float)$redisResultsMap[$ride['id']], 1);
        } else {
            $ride['driver_distance_km'] = "0.0";
        }

        $finalRides[] = $ride;
    }

    usort($finalRides, function($a, $b) {
        return $a['driver_distance_km'] <=> $b['driver_distance_km'];
    });

    jsonSuccess($finalRides);

} catch (PDOException $e) {
    error_log("DB Error getRideWaiting: " . $e->getMessage());
    jsonError("Database error"); 
}
?>

File: ride/notificationCaptain/updateWaitingTrip.php

<?php
require_once __DIR__ . '/../../connect.php';

$id = filterRequest("id");

$fields = [];
$params = [':id' => $id];

$possibleFields = [
    'start_location', 'end_location', 'date', 'time', 'price',
    'passenger_id', 'status', 'carType', 'passengerRate',
    'price_for_passenger', 'distance', 'duration'
];

foreach ($possibleFields as $field) {
    if (isset($_POST[$field])) {
        $value = filterRequest($field);
        $fields[] = "`$field` = :$field";
        $params[":$field"] = $value;
    }
}

if (empty($fields)) {
    jsonError("No fields provided for update");
    exit;
}

$setClause = implode(", ", $fields);
$sql = "UPDATE `waitingRides` SET $setClause WHERE `id` = :id";

$stmt = $con->prepare($sql);
$stmt->execute($params);

if ($stmt->rowCount() > 0) {
    jsonSuccess(null, "Waiting ride data updated successfully");
} else {
    jsonError("Failed to update waiting ride data");
}
?>

File: ride/overLay/add.php

<?php
require_once __DIR__ . '/../../connect.php';

// --- دالة تسجيل الأخطاء (تبقى كما هي) ---
function log_message($message) {
    $log_file = __DIR__ . '/_log.txt';
    $formatted_message = "[" . date("Y-m-d H:i:s") . "] " . $message . "\n";
    file_put_contents($log_file, $formatted_message, FILE_APPEND);
}

log_message("--- New Request Received ---");
log_message("Incoming POST data: " . json_encode($_POST));

// --- قائمة المتغيرات (تبقى كما هي) ---
define('TABLE_NAME', 'write_argument_after_applied_from_background');
$params = [
    'rideId', 'driver_id', 'passengerId', 'passengerLocation', 'passengerDestination',
    'Duration', 'DurationToPassenger', 'durationOfRideValue', 'Distance', 'totalCost',
    'paymentAmount', 'paymentMethod', 'WalletChecked', 'isHaveSteps', 'step0', 'step1',
    'step2', 'step3', 'step4', 'passengerWalletBurc', 'tokenPassenger', 'name',
    'phone', 'email', 'startNameLocation', 'endNameLocation', 'carType', 'kazan',
    'direction', 'timeOfOrder', 'totalPassenger',
];

$data = [];
foreach ($params as $key) {
    $data[$key] = isset($_POST[$key]) ? filterRequest($key) : null;
}

// التحقق من البيانات (يبقى كما هو)
if (empty($data['rideId']) || empty($data['driver_id']) || empty($data['passengerLocation']) || empty($data['passengerDestination'])) {
    $error_msg = "Critical error: Missing required fields (rideId, driver_id, or locations). Check incoming keys.";
    log_message($error_msg);
    jsonError($error_msg);
    exit();
}

// --- تم حذف تقسيم الإحداثيات ---
// لم نعد بحاجة لـ list($plat, $plng) = explode(...)

// --- التعديل الرئيسي هنا في جملة SQL ---
$sql = "
  INSERT INTO " . TABLE_NAME . " (
    ride_id, driver_id, passenger_id,
    passenger_location, passenger_destination,  -- These are now simple string fields
    duration, duration_to_passenger, duration_of_ride,
    distance, total_cost, payment_amount, payment_method,
    wallet_checked, has_steps, step0, step1, step2, step3, step4,
    passenger_wallet_burc, token_passenger,
    name, phone, email,
    start_name_location, end_name_location,
    car_type, kazan, direction_url, time_of_order, total_passenger
  ) VALUES (
    :rideId, :driver_id, :passengerId,
    :passengerLocation, :passengerDestination, -- We removed the POINT() function
    :Duration, :DurationToPassenger, :durationOfRideValue,
    :Distance, :totalCost, :paymentAmount, :paymentMethod,
    :WalletChecked, :isHaveSteps, :step0, :step1, :step2, :step3, :step4,
    :passengerWalletBurc, :tokenPassenger,
    :name, :phone, :email,
    :startNameLocation, :endNameLocation,
    :carType, :kazan, :direction, :timeOfOrder, :totalPassenger
  )";

try {
    $stmt = $con->prepare($sql);

    // --- التعديل الرئيسي هنا في bindValue ---
    $stmt->bindValue(':rideId', $data['rideId']);
    $stmt->bindValue(':driver_id', $data['driver_id']);
    $stmt->bindValue(':passengerId', $data['passengerId']);
    
    // Bind the locations as simple strings
    $stmt->bindValue(':passengerLocation', $data['passengerLocation']);
    $stmt->bindValue(':passengerDestination', $data['passengerDestination']);

    // باقي الـ bindValue تبقى كما هي
    $stmt->bindValue(':Duration', intval($data['Duration']), PDO::PARAM_INT);
    $stmt->bindValue(':DurationToPassenger', intval($data['DurationToPassenger']), PDO::PARAM_INT);
    $stmt->bindValue(':durationOfRideValue', intval($data['durationOfRideValue']), PDO::PARAM_INT);
    $stmt->bindValue(':Distance', (float)$data['Distance']);
    $stmt->bindValue(':totalCost', (float)$data['totalCost']);
    $stmt->bindValue(':paymentAmount', (float)$data['paymentAmount']);
    $stmt->bindValue(':paymentMethod', $data['paymentMethod']);
    $stmt->bindValue(':WalletChecked', $data['WalletChecked'] === 'true' ? 1 : 0, PDO::PARAM_INT);
    $stmt->bindValue(':isHaveSteps', !empty($data['isHaveSteps']) ? 1 : 0, PDO::PARAM_INT);
    $stmt->bindValue(':step0', $data['step0']);
    $stmt->bindValue(':step1', $data['step1']);
    $stmt->bindValue(':step2', $data['step2']);
    $stmt->bindValue(':step3', $data['step3']);
    $stmt->bindValue(':step4', $data['step4']);
    $stmt->bindValue(':passengerWalletBurc', (float)$data['passengerWalletBurc']);
    $stmt->bindValue(':tokenPassenger', $data['tokenPassenger']);
    $stmt->bindValue(':name', $data['name']);
    $stmt->bindValue(':phone', $data['phone']);
    $stmt->bindValue(':email', $data['email']);
    $stmt->bindValue(':startNameLocation', $data['startNameLocation']);
    $stmt->bindValue(':endNameLocation', $data['endNameLocation']);
    $stmt->bindValue(':carType', $data['carType']);
    $stmt->bindValue(':kazan', (float)$data['kazan']);
    $stmt->bindValue(':direction', $data['direction']);
    $stmt->bindValue(':timeOfOrder', $data['timeOfOrder']);
    $stmt->bindValue(':totalPassenger', intval($data['totalPassenger']), PDO::PARAM_INT);

    log_message("SQL statement prepared successfully. Attempting to execute...");

    if ($stmt->execute()) {
        log_message("SUCCESS: Database insert was successful for rideId: " . $data['rideId']);
        jsonSuccess(null, "نجحت الإضافة");
    } else {
        $errorInfo = $stmt->errorInfo();
        $error_msg = "FAILURE: Database insert failed. PDO Error: " . implode(" | ", $errorInfo);
        log_message($error_msg);
        jsonError("failure");
    }
} catch (Exception $e) {
    $error_msg = "EXCEPTION: An unexpected error occurred: " . $e->getMessage();
    log_message($error_msg);
    jsonError("failure");
}

?>

File: ride/overLay/deletArgumets.php

<?php
require_once __DIR__ . '/../../connect.php';

$driver_id = filterRequest('driver_id');

if (empty($driver_id)) {
    jsonError('Missing driver ID');
    exit;
}

// SQL to DELETE the latest record for this driver
// Still respects the 2-minute constraint
$sql = "DELETE FROM write_argument_after_applied_from_background 
        WHERE driver_id = :driver_id 
        AND TIMESTAMPDIFF(MINUTE, time_of_order, NOW()) <= 20
        ORDER BY time_of_order DESC 
        LIMIT 1";

$stmt = $con->prepare($sql);
$stmt->bindParam(':driver_id', $driver_id);
$stmt->execute();

// Check if any rows were actually deleted
$count = $stmt->rowCount();

if ($count > 0) {
    jsonSuccess(null, "Record deleted successfully");
} else {
    // Failure occurs if no record exists OR if the record is older than 2 minutes
    jsonError('No data found to delete (or time limit exceeded)');
}
?>

File: ride/overLay/get.php

<?php
require_once __DIR__ . '/../../connect.php';

$driver_id = filterRequest("driver_id");

// 1) تأكد من وجود driver_id
if (empty($driver_id)) {
    jsonError("Missing driver ID.");
    exit;
}

// 2) استعلام لأحدث رحلة بحالة apply
$sql = "
    SELECT
  r.*,
  t.token
FROM `ride` AS r
LEFT JOIN `tokens` AS t
  ON t.passengerID = r.passenger_id
WHERE
  r.driver_id = :driver_id
  AND r.status  = 'Apply'
  AND r.created_at >= NOW() - INTERVAL 2 MINUTE
ORDER BY
  r.created_at DESC
LIMIT 1;
";

$stmt = $con->prepare($sql);
$stmt->bindParam(':driver_id', $driver_id, PDO::PARAM_INT);
$stmt->execute();

$row = $stmt->fetch(PDO::FETCH_ASSOC);

// 3) إرجاع النتيجة أو رسالة خطأ
if ($row) {
    jsonSuccess($row);
} else {
    jsonError("Ride not found.");
}

File: ride/overLay/_log.txt

[2025-06-20 17:42:27] --- New Request Received ---
[2025-06-20 17:42:27] Incoming POST data: {"driver_id":"109270481246447459618","status":"Apply","passengerLocation":"32.1117875,36.0669891","passengerDestination":"32.0798703,36.0749472","Duration":"528","totalCost":"6.99","Distance":"5.64","name":"hamza","phone":"+201010101010","email":"hamzaayedflutter@gmail.com","WalletChecked":"true","tokenPassenger":"e4QWqe7K607luM7qUMOPCL:APA91bFjX4XBM4I5COJl9fyxCTKJ1ZQpT3vzY7iEbOTuT4uo0-OSCAt5zgVhlhw4aC33s-VhyucDnP1tQGFd9svaazQ8A_SKgolPk3owzug8dCsiXoPeJ0k","direction":"https:\/\/maps.googleapis.com\/maps\/api\/staticmap?size=600x150&maptype=roadmap&markers=color:green%7Clabel:S%7C32.1117875%2C36.0669891&markers=color:red%7Clabel:D%7C32.0798703%2C36.0749472&path=color:0x007bff%7Cweight:5%7C32.1117875%2C36.0669891%7C32.0798703%2C36.0749472&key=AIzaSyCyfwRXTwSTLOFQSQgN5p7QZgGJVZnEKq0","DurationToPassenger":"1","rideId":"1292","passengerId":"113172279072358305645","durationOfRideValue":"528","paymentAmount":"33.78","paymentMethod":"visa","isHaveSteps":"startEnd","step0":"32.09571771505668,36.06855209916831","step1":"","step2":"","step3":"","step4":"","passengerWalletBurc":"6.99","carType":"Speed","kazan":"8","startNameLocation":"4368+PPP\u060c \u0627\u0644\u0633\u062e\u0646\u0629\u060c \u0627\u0644\u0623\u0631\u062f\u0646","endNameLocation":"33HG+R6R\u060c \u0627\u0644\u0632\u0631\u0642\u0627\u0621\u060c \u0627\u0644\u0623\u0631\u062f\u0646","timeOfOrder":"2025-06-20T17:42:26.285449","totalPassenger":"33.78"}
[2025-06-20 17:42:27] Critical error: Missing required fields (rideId, driverId, or locations).
[2025-06-20 17:45:59] --- New Request Received ---
[2025-06-20 17:45:59] Incoming POST data: {"driver_id":"109270481246447459618","status":"Apply","passengerLocation":"32.1117875,36.0669891","passengerDestination":"32.0798703,36.0749472","Duration":"528","totalCost":"6.99","Distance":"5.64","name":"hamza","phone":"+201010101010","email":"hamzaayedflutter@gmail.com","WalletChecked":"true","tokenPassenger":"e4QWqe7K607luM7qUMOPCL:APA91bFjX4XBM4I5COJl9fyxCTKJ1ZQpT3vzY7iEbOTuT4uo0-OSCAt5zgVhlhw4aC33s-VhyucDnP1tQGFd9svaazQ8A_SKgolPk3owzug8dCsiXoPeJ0k","direction":"https:\/\/maps.googleapis.com\/maps\/api\/staticmap?size=600x150&maptype=roadmap&markers=color:green%7Clabel:S%7C32.1117875%2C36.0669891&markers=color:red%7Clabel:D%7C32.0798703%2C36.0749472&path=color:0x007bff%7Cweight:5%7C32.1117875%2C36.0669891%7C32.0798703%2C36.0749472&key=AIzaSyCyfwRXTwSTLOFQSQgN5p7QZgGJVZnEKq0","DurationToPassenger":"3","rideId":"1293","passengerId":"113172279072358305645","durationOfRideValue":"528","paymentAmount":"33.78","paymentMethod":"visa","isHaveSteps":"startEnd","step0":"32.09571771505668,36.06855209916831","step1":"","step2":"","step3":"","step4":"","passengerWalletBurc":"6.99","carType":"Speed","kazan":"8","startNameLocation":"4368+PPP\u060c \u0627\u0644\u0633\u062e\u0646\u0629\u060c \u0627\u0644\u0623\u0631\u062f\u0646","endNameLocation":"33HG+R6R\u060c \u0627\u0644\u0632\u0631\u0642\u0627\u0621\u060c \u0627\u0644\u0623\u0631\u062f\u0646","timeOfOrder":"2025-06-20T17:45:58.817633","totalPassenger":"33.78"}
[2025-06-20 17:45:59] Critical error: Missing required fields (rideId, driverId, or locations).
[2025-06-20 17:47:00] --- New Request Received ---
[2025-06-20 17:47:00] Incoming POST data: {"driver_id":"109270481246447459618","status":"Apply","passengerLocation":"32.1117875,36.0669891","passengerDestination":"32.1364001,36.0707479","Duration":"434","totalCost":"5.42","Distance":"4.38","name":"hamza","phone":"+201010101010","email":"hamzaayedflutter@gmail.com","WalletChecked":"true","tokenPassenger":"e4QWqe7K607luM7qUMOPCL:APA91bFjX4XBM4I5COJl9fyxCTKJ1ZQpT3vzY7iEbOTuT4uo0-OSCAt5zgVhlhw4aC33s-VhyucDnP1tQGFd9svaazQ8A_SKgolPk3owzug8dCsiXoPeJ0k","direction":"https:\/\/maps.googleapis.com\/maps\/api\/staticmap?size=600x150&maptype=roadmap&markers=color:green%7Clabel:S%7C32.1117875%2C36.0669891&markers=color:red%7Clabel:D%7C32.1364001%2C36.0707479&path=color:0x007bff%7Cweight:5%7C32.1117875%2C36.0669891%7C32.1364001%2C36.0707479&key=AIzaSyCyfwRXTwSTLOFQSQgN5p7QZgGJVZnEKq0","DurationToPassenger":"2","rideId":"1294","passengerId":"113172279072358305645","durationOfRideValue":"434","paymentAmount":"27.82","paymentMethod":"visa","isHaveSteps":"startEnd","step0":"32.12404505187645,36.06566168367863","step1":"","step2":"","step3":"","step4":"","passengerWalletBurc":"5.42","carType":"Speed","kazan":"8","startNameLocation":"4368+PPP\u060c \u0627\u0644\u0633\u062e\u0646\u0629\u060c \u0627\u0644\u0623\u0631\u062f\u0646","endNameLocation":"43PC+C4G\u060c \u0627\u0644\u0633\u062e\u0646\u0629\u060c \u0627\u0644\u0623\u0631\u062f\u0646","timeOfOrder":"2025-06-20T17:46:59.188875","totalPassenger":"27.82"}
[2025-06-20 17:47:00] Parsed Locations: passenger_lat=32.1117875, passenger_lng=36.0669891 | destination_lat=32.1364001, destination_lng=36.0707479
[2025-06-20 17:47:00] SQL statement prepared successfully. Attempting to execute...
[2025-06-20 17:47:00] SUCCESS: Database insert was successful for rideId: 1294
[2025-06-20 17:49:18] --- New Request Received ---
[2025-06-20 17:49:18] Incoming POST data: {"driver_id":"109270481246447459618","status":"Apply","passengerLocation":"32.1117875,36.0669891","passengerDestination":"32.0798703,36.0749472","Duration":"528","totalCost":"6.99","Distance":"5.64","name":"hamza","phone":"+201010101010","email":"hamzaayedflutter@gmail.com","WalletChecked":"true","tokenPassenger":"e4QWqe7K607luM7qUMOPCL:APA91bFjX4XBM4I5COJl9fyxCTKJ1ZQpT3vzY7iEbOTuT4uo0-OSCAt5zgVhlhw4aC33s-VhyucDnP1tQGFd9svaazQ8A_SKgolPk3owzug8dCsiXoPeJ0k","direction":"https:\/\/maps.googleapis.com\/maps\/api\/staticmap?size=600x150&maptype=roadmap&markers=color:green%7Clabel:S%7C32.1117875%2C36.0669891&markers=color:red%7Clabel:D%7C32.0798703%2C36.0749472&path=color:0x007bff%7Cweight:5%7C32.1117875%2C36.0669891%7C32.0798703%2C36.0749472&key=AIzaSyCyfwRXTwSTLOFQSQgN5p7QZgGJVZnEKq0","DurationToPassenger":"1","rideId":"1295","passengerId":"113172279072358305645","durationOfRideValue":"528","paymentAmount":"33.78","paymentMethod":"visa","isHaveSteps":"startEnd","step0":"32.09571771505668,36.06855209916831","step1":"","step2":"","step3":"","step4":"","passengerWalletBurc":"6.99","carType":"Speed","kazan":"8","startNameLocation":"4368+PPP\u060c \u0627\u0644\u0633\u062e\u0646\u0629\u060c \u0627\u0644\u0623\u0631\u062f\u0646","endNameLocation":"33HG+R6R\u060c \u0627\u0644\u0632\u0631\u0642\u0627\u0621\u060c \u0627\u0644\u0623\u0631\u062f\u0646","timeOfOrder":"2025-06-20T17:49:16.916262","totalPassenger":"33.78"}
[2025-06-20 17:49:18] Parsed Locations: passenger_lat=32.1117875, passenger_lng=36.0669891 | destination_lat=32.0798703, destination_lng=36.0749472
[2025-06-20 17:49:18] SQL statement prepared successfully. Attempting to execute...
[2025-06-20 17:49:18] EXCEPTION: An unexpected error occurred: SQLSTATE[HY000]: General error: 1366 Incorrect string value: '\x84\x0DO\x0E@@...' for column 'passenger_location' at row 1
[2025-06-20 17:52:06] --- New Request Received ---
[2025-06-20 17:52:06] Incoming POST data: {"driver_id":"109270481246447459618","status":"Apply","passengerLocation":"32.1117875,36.0669891","passengerDestination":"32.1364001,36.0707479","Duration":"434","totalCost":"5.42","Distance":"4.38","name":"hamza","phone":"+201010101010","email":"hamzaayedflutter@gmail.com","WalletChecked":"true","tokenPassenger":"e4QWqe7K607luM7qUMOPCL:APA91bFjX4XBM4I5COJl9fyxCTKJ1ZQpT3vzY7iEbOTuT4uo0-OSCAt5zgVhlhw4aC33s-VhyucDnP1tQGFd9svaazQ8A_SKgolPk3owzug8dCsiXoPeJ0k","direction":"https:\/\/maps.googleapis.com\/maps\/api\/staticmap?size=600x150&maptype=roadmap&markers=color:green%7Clabel:S%7C32.1117875%2C36.0669891&markers=color:red%7Clabel:D%7C32.1364001%2C36.0707479&path=color:0x007bff%7Cweight:5%7C32.1117875%2C36.0669891%7C32.1364001%2C36.0707479&key=AIzaSyCyfwRXTwSTLOFQSQgN5p7QZgGJVZnEKq0","DurationToPassenger":"5","rideId":"1296","passengerId":"113172279072358305645","durationOfRideValue":"434","paymentAmount":"27.82","paymentMethod":"visa","isHaveSteps":"startEnd","step0":"32.12404505187645,36.06566168367863","step1":"","step2":"","step3":"","step4":"","passengerWalletBurc":"5.42","carType":"Speed","kazan":"8","startNameLocation":"4368+PPP\u060c \u0627\u0644\u0633\u062e\u0646\u0629\u060c \u0627\u0644\u0623\u0631\u062f\u0646","endNameLocation":"43PC+C4G\u060c \u0627\u0644\u0633\u062e\u0646\u0629\u060c \u0627\u0644\u0623\u0631\u062f\u0646","timeOfOrder":"2025-06-20T17:52:05.601313","totalPassenger":"27.82"}
[2025-06-20 17:52:06] SQL statement prepared successfully. Attempting to execute...
[2025-06-20 17:52:06] EXCEPTION: An unexpected error occurred: SQLSTATE[22001]: String data, right truncated: 1406 Data too long for column 'passenger_location' at row 1
[2025-06-20 17:53:56] --- New Request Received ---
[2025-06-20 17:53:56] Incoming POST data: {"driver_id":"109270481246447459618","status":"Apply","passengerLocation":"32.1117875,36.0669891","passengerDestination":"32.0798703,36.0749472","Duration":"528","totalCost":"6.99","Distance":"5.64","name":"hamza","phone":"+201010101010","email":"hamzaayedflutter@gmail.com","WalletChecked":"true","tokenPassenger":"e4QWqe7K607luM7qUMOPCL:APA91bFjX4XBM4I5COJl9fyxCTKJ1ZQpT3vzY7iEbOTuT4uo0-OSCAt5zgVhlhw4aC33s-VhyucDnP1tQGFd9svaazQ8A_SKgolPk3owzug8dCsiXoPeJ0k","direction":"https:\/\/maps.googleapis.com\/maps\/api\/staticmap?size=600x150&maptype=roadmap&markers=color:green%7Clabel:S%7C32.1117875%2C36.0669891&markers=color:red%7Clabel:D%7C32.0798703%2C36.0749472&path=color:0x007bff%7Cweight:5%7C32.1117875%2C36.0669891%7C32.0798703%2C36.0749472&key=AIzaSyCyfwRXTwSTLOFQSQgN5p7QZgGJVZnEKq0","DurationToPassenger":"3","rideId":"1297","passengerId":"113172279072358305645","durationOfRideValue":"528","paymentAmount":"33.78","paymentMethod":"visa","isHaveSteps":"startEnd","step0":"32.09571771505668,36.06855209916831","step1":"","step2":"","step3":"","step4":"","passengerWalletBurc":"6.99","carType":"Speed","kazan":"8","startNameLocation":"4368+PPP\u060c \u0627\u0644\u0633\u062e\u0646\u0629\u060c \u0627\u0644\u0623\u0631\u062f\u0646","endNameLocation":"33HG+R6R\u060c \u0627\u0644\u0632\u0631\u0642\u0627\u0621\u060c \u0627\u0644\u0623\u0631\u062f\u0646","timeOfOrder":"2025-06-20T17:53:56.195146","totalPassenger":"33.78"}
[2025-06-20 17:53:56] SQL statement prepared successfully. Attempting to execute...
[2025-06-20 17:53:56] SUCCESS: Database insert was successful for rideId: 1297
[2025-06-21 23:49:45] --- New Request Received ---
[2025-06-21 23:49:45] Incoming POST data: {"driver_id":"109270481246447459618","status":"Apply","passengerLocation":"32.1117875,36.0669891","passengerDestination":"32.0798703,36.0749472","Duration":"528","totalCost":"6.99","Distance":"5.64","name":"hamza","phone":"+201010101010","email":"hamzaayedflutter@gmail.com","WalletChecked":"true","tokenPassenger":"e4QWqe7K607luM7qUMOPCL:APA91bFjX4XBM4I5COJl9fyxCTKJ1ZQpT3vzY7iEbOTuT4uo0-OSCAt5zgVhlhw4aC33s-VhyucDnP1tQGFd9svaazQ8A_SKgolPk3owzug8dCsiXoPeJ0k","direction":"https:\/\/maps.googleapis.com\/maps\/api\/staticmap?size=600x150&maptype=roadmap&markers=color:green%7Clabel:S%7C32.1117875%2C36.0669891&markers=color:red%7Clabel:D%7C32.0798703%2C36.0749472&path=color:0x007bff%7Cweight:5%7C32.1117875%2C36.0669891%7C32.0798703%2C36.0749472&key=AIzaSyCyfwRXTwSTLOFQSQgN5p7QZgGJVZnEKq0","DurationToPassenger":"1","rideId":"1298","passengerId":"113172279072358305645","durationOfRideValue":"528","paymentAmount":"29.81","paymentMethod":"visa","isHaveSteps":"startEnd","step0":"32.09571771505668,36.06855209916831","step1":"","step2":"","step3":"","step4":"","passengerWalletBurc":"6.99","carType":"Speed","kazan":"8","startNameLocation":"4368+PPP\u060c \u0627\u0644\u0633\u062e\u0646\u0629\u060c \u0627\u0644\u0623\u0631\u062f\u0646","endNameLocation":"33HG+R6R\u060c \u0627\u0644\u0632\u0631\u0642\u0627\u0621\u060c \u0627\u0644\u0623\u0631\u062f\u0646","timeOfOrder":"2025-06-21T23:49:42.340702","totalPassenger":"29.81"}
[2025-06-21 23:49:45] SQL statement prepared successfully. Attempting to execute...
[2025-06-21 23:49:45] SUCCESS: Database insert was successful for rideId: 1298
[2025-07-08 18:34:43] --- New Request Received ---
[2025-07-08 18:34:43] Incoming POST data: {"driver_id":"109270481246447459618","status":"Apply","passengerLocation":"33.4934292,36.3335578","passengerDestination":"33.5165162,36.3174916","Duration":"842","totalCost":"6.32","Distance":"5.11","name":"hamza","phone":"+201010101010","email":"hamzaayedflutter@gmail.com","WalletChecked":"true","tokenPassenger":"e4QWqe7K607luM7qUMOPCL:APA91bFjX4XBM4I5COJl9fyxCTKJ1ZQpT3vzY7iEbOTuT4uo0-OSCAt5zgVhlhw4aC33s-VhyucDnP1tQGFd9svaazQ8A_SKgolPk3owzug8dCsiXoPeJ0k","direction":"https:\/\/maps.googleapis.com\/maps\/api\/staticmap?size=600x150&maptype=roadmap&markers=color:green%7Clabel:S%7C33.4934292%2C36.3335578&markers=color:red%7Clabel:D%7C33.5165162%2C36.3174916&path=color:0x007bff%7Cweight:5%7C33.4934292%2C36.3335578%7C33.5165162%2C36.3174916&key=AIzaSyCyfwRXTwSTLOFQSQgN5p7QZgGJVZnEKq0","DurationToPassenger":"11","rideId":"1315","passengerId":"113172279072358305645","durationOfRideValue":"842","paymentAmount":"34.78","paymentMethod":"visa","isHaveSteps":"startEnd","step0":"33.505157730332385,36.32586847990751","step1":"","step2":"","step3":"","step4":"","passengerWalletBurc":"6.32","carType":"Speed","kazan":"8","startNameLocation":"F8VM+C95\u060c \u062f\u0645\u0634\u0642\u060c \u0633\u0648\u0631\u064a\u0627","endNameLocation":"G888+MV4\u060c \u062f\u0645\u0634\u0642\u060c \u0633\u0648\u0631\u064a\u0627","timeOfOrder":"2025-07-08T18:34:14.861836","totalPassenger":"34.78"}
[2025-07-08 18:34:43] SQL statement prepared successfully. Attempting to execute...
[2025-07-08 18:34:43] SUCCESS: Database insert was successful for rideId: 1315
[2025-07-27 16:51:54] --- New Request Received ---
[2025-07-27 16:51:54] Incoming POST data: {"driver_id":"34feffd3fa72d6bee56b","status":"Apply","passengerLocation":"32.1117875,36.0669891","passengerDestination":"32.1324686,36.0710479","Duration":"346","totalCost":"2767.81","Distance":"2.64","name":"hamza","phone":"963992952235","email":"963992952235@intaleqapp.com","WalletChecked":"false","tokenPassenger":"eskhRGH3gkzOmUQou8xJjg:APA91bGkbGdXRTuB3QTZ5BjHGiYLZNugjVlW7o89ck9KPDmJrT7v1DBSjdamRSLc4oqT56xNpZ_LgkFKhRWkprlLUvZx5HLCOTXMk0WBiQ0UibiSWqw10oI","direction":"https:\/\/maps.googleapis.com\/maps\/api\/staticmap?size=600x150&maptype=roadmap&markers=color:green%7Clabel:S%7C32.1117875%2C36.0669891&markers=color:red%7Clabel:D%7C32.1324686%2C36.0710479&path=color:0x007bff%7Cweight:5%7C32.1117875%2C36.0669891%7C32.1324686%2C36.0710479&key=QOsqYdTCyHNapgBsg2Kn-nTKbhaWhEAGOjUeU78","DurationToPassenger":"1","rideId":"2","passengerId":"0b24f04061d6853df4b9","durationOfRideValue":"346","paymentAmount":"10532.56","paymentMethod":"cash","isHaveSteps":"startEnd","step0":"32.122128403255125,36.07006452977657","step1":"","step2":"","step3":"","step4":"","passengerWalletBurc":"2767.81","carType":"Speed","kazan":"15","startNameLocation":"4368+PPP\u060c \u0627\u0644\u0633\u062e\u0646\u0629\u060c \u0627\u0644\u0623\u0631\u062f\u0646","endNameLocation":"43MC+374\u060c \u0627\u0644\u0633\u062e\u0646\u0629\u060c \u0627\u0644\u0623\u0631\u062f\u0646","timeOfOrder":"2025-07-27T16:51:53.436851","totalPassenger":"10532.56"}
[2025-07-27 16:51:54] SQL statement prepared successfully. Attempting to execute...
[2025-07-27 16:51:54] SUCCESS: Database insert was successful for rideId: 2
[2025-08-05 12:13:28] --- New Request Received ---
[2025-08-05 12:13:28] Incoming POST data: {"driver_id":"34feffd3fa72d6bee56b","status":"Apply","passengerLocation":"32.1117131,36.067405","passengerDestination":"32.1278332,36.0702951","Duration":"253","totalCost":"2126.67","Distance":"2.03","name":"hamza","phone":"963992952235","email":"963992952235@intaleqapp.com","WalletChecked":"false","tokenPassenger":"dwDRLsWhZEIqum1oxaaTWY:APA91bHhImBb0-kyeRE8zP8jL-ps_K4Xt09g1YNRWbVx007FO4N9U4b9lPAoNOU029qM5-GU65doySW7dfsdQ_mDogqGtQnGtJz1uVOb_3_v-tuoL9irixo","direction":"https:\/\/maps.googleapis.com\/maps\/api\/staticmap?size=600x150&maptype=roadmap&markers=color:green%7Clabel:S%7C32.1117131%2C36.067405&markers=color:red%7Clabel:D%7C32.1278332%2C36.0702951&path=color:0x007bff%7Cweight:5%7C32.1117131%2C36.067405%7C32.1278332%2C36.0702951&key=AIzaSyCFsWBqvkXzk1Gb-bCGxwqTwJQKIeHjH64","DurationToPassenger":"3","rideId":"23","passengerId":"0b24f04061d6853df4b9","durationOfRideValue":"253","paymentAmount":"5938.31","paymentMethod":"cash","isHaveSteps":"startEnd","step0":"32.119773283888684,36.06956731528044","step1":"","step2":"","step3":"","step4":"","passengerWalletBurc":"2126.67","carType":"Speed","kazan":"15","startNameLocation":"4368+PPP\u060c \u0627\u0644\u0633\u062e\u0646\u0629\u060c \u0627\u0644\u0623\u0631\u062f\u0646","endNameLocation":"43H9+3V8\u060c \u0627\u0644\u0633\u062e\u0646\u0629\u060c \u0627\u0644\u0623\u0631\u062f\u0646","timeOfOrder":"2025-08-05T12:13:27.287381","totalPassenger":"5938.31"}
[2025-08-05 12:13:28] SQL statement prepared successfully. Attempting to execute...
[2025-08-05 12:13:28] SUCCESS: Database insert was successful for rideId: 23
[2025-11-03 16:54:25] --- New Request Received ---
[2025-11-03 16:54:25] Incoming POST data: {"driver_id":"90393d64b8cd7488c4df","status":"Apply","passengerLocation":"33.4323,36.24325","passengerDestination":"33.4277,36.23907","Duration":"111","totalCost":"0.00","Distance":"0.72","name":"\u062d\u0645\u0632\u0647","phone":"963992952235","email":"963992952235@intaleqapp.com","WalletChecked":"false","tokenPassenger":"eznj5vRWRnqwKNtKJBaYNg:APA91bHhJ2DJ1KQa3KRx6wQtX8BkFHq6I_-dXGxT16p6pnV5AwI0bWOeiTJOI35VfTBaK4YSCKmAB4SsRnpARK0MTJ96xtpPmwAKfkvsZFga8OoGMeb3PmA","direction":"https:\/\/maps.googleapis.com\/maps\/api\/staticmap?size=600x150&maptype=roadmap&markers=color:green%7Clabel:S%7C33.4323%2C36.24325&markers=color:red%7Clabel:D%7C33.4277%2C36.23907&path=color:0x007bff%7Cweight:5%7C33.4323%2C36.24325%7C33.4277%2C36.23907&key=AIzaSyAPFR_XbRN0XZ5Iz3AYDjNYHGJG2s2QWwM","DurationToPassenger":"0","rideId":"5","passengerId":"f1e06c5908dcae1f5bf2","durationOfRideValue":"111","paymentAmount":"17280.00","paymentMethod":"cash","isHaveSteps":"startEnd","step0":"33.430078683118474,36.241159960627556","step1":"","step2":"","step3":"","step4":"","passengerWalletBurc":"0.00","carType":"Speed","kazan":"8","startNameLocation":"home","endNameLocation":"destination","timeOfOrder":"2025-11-03T16:54:23.416130","totalPassenger":"17280.00"}
[2025-11-03 16:54:25] SQL statement prepared successfully. Attempting to execute...
[2025-11-03 16:54:25] SUCCESS: Database insert was successful for rideId: 5
[2025-11-18 18:07:16] --- New Request Received ---
[2025-11-18 18:07:16] Incoming POST data: {"driver_id":"ca60f0f65d7d6de23e5c","status":"Apply","passengerLocation":"36.16167,37.15408","passengerDestination":"36.2431,37.1496","Duration":"1254","totalCost":"0.00","Distance":"11.53","name":"George","phone":"447441447609","email":"sahrsa6@gmail.com","WalletChecked":"false","tokenPassenger":"eoHpQeewTbKL3ZU5ioLgP5:APA91bG0FhuTixe_kuDw49onLPdOjxdyRvmbT_TG5Va81lI7RqOpoHqaho6NThvybVJZaelkobwTDCZeC9WKLW-RytE1mUl3MfRiYiTPkHGZ2bCe9Raehtc","direction":"https:\/\/maps.googleapis.com\/maps\/api\/staticmap?size=600x150&maptype=roadmap&markers=color:green%7Clabel:S%7C36.16167%2C37.15408&markers=color:red%7Clabel:D%7C36.2431%2C37.1496&path=color:0x007bff%7Cweight:5%7C36.16167%2C37.15408%7C36.2431%2C37.1496&key=AIzaSyAPFR_XbRN0XZ5Iz3AYDjNYHGJG2s2QWwM","DurationToPassenger":"0","rideId":"124","passengerId":"21c382cde919795e93bb","durationOfRideValue":"1254","paymentAmount":"56469.00","paymentMethod":"cash","isHaveSteps":"startEnd","step0":"36.174937765937635,37.15724665671587","step1":"","step2":"","step3":"","step4":"","passengerWalletBurc":"0.00","carType":"Speed","kazan":"8","startNameLocation":"home","endNameLocation":"destination","timeOfOrder":"2025-11-18T18:07:15.160122","totalPassenger":"56469.00"}
[2025-11-18 18:07:16] SQL statement prepared successfully. Attempting to execute...
[2025-11-18 18:07:16] SUCCESS: Database insert was successful for rideId: 124
[2025-11-20 10:07:35] --- New Request Received ---
[2025-11-20 10:07:35] Incoming POST data: {"driver_id":"34feffd3fa72d6bee56b","status":"Apply","passengerLocation":"33.4323,36.24325","passengerDestination":"33.43575,36.2483","Duration":"203","totalCost":"0.00","Distance":"0.96","name":"\u062d\u0645\u0632\u0647","phone":"963992952235","email":"963992952235@intaleqapp.com","WalletChecked":"false","tokenPassenger":"clZNZD6JTNeytuyvhqAjAs:APA91bEfEgnGduR3yy2ND3V57d1-qT_OS_A-gGimALeYNwSla-IVMBfYgfDYucNN5Whf0wJODjkOYuT03JLr5AJ4eqRXKxUbkbBis-GYFDdly_3o5nDEiWo","direction":"https:\/\/maps.googleapis.com\/maps\/api\/staticmap?size=600x150&maptype=roadmap&markers=color:green%7Clabel:S%7C33.4323%2C36.24325&markers=color:red%7Clabel:D%7C33.43575%2C36.2483&path=color:0x007bff%7Cweight:5%7C33.4323%2C36.24325%7C33.43575%2C36.2483&key=AIzaSyAPFR_XbRN0XZ5Iz3AYDjNYHGJG2s2QWwM","DurationToPassenger":"0","rideId":"143","passengerId":"849a9faf3e68c1aeb708","durationOfRideValue":"203","paymentAmount":"17280.00","paymentMethod":"cash","isHaveSteps":"startEnd","step0":"33.43403283445615,36.24521479010582","step1":"","step2":"","step3":"","step4":"","passengerWalletBurc":"0.00","carType":"Speed","kazan":"8","startNameLocation":"home","endNameLocation":"destination","timeOfOrder":"2025-11-20T10:07:33.481734","totalPassenger":"17280.00"}
[2025-11-20 10:07:35] SQL statement prepared successfully. Attempting to execute...
[2025-11-20 10:07:35] SUCCESS: Database insert was successful for rideId: 143
[2025-11-25 20:16:54] --- New Request Received ---
[2025-11-25 20:16:54] Incoming POST data: {"driver_id":"7939eb03eb3b912ffb49","status":"Apply","passengerLocation":"35.12533,36.76929","passengerDestination":"35.13223,36.7536","Duration":"292","totalCost":"0.00","Distance":"2.81","name":"\u0639\u0628\u062f\u0627\u0644\u0644\u0647","phone":"963098198141","email":"bdallhlwany@gmail.com","WalletChecked":"false","tokenPassenger":"e-z9_8IRZEEsjwL3qFQAzN:APA91bHZEIWbF418RCnLeo3yVsGHkD7xDqoIHZzbw7tiXoImzSDi5KlOQbhIrEFxrtxNJ1uvStUk9jobI3k1p1LBr-Er7O2fhWG-P-HSHsChgGWoEjEZ15o","direction":"https:\/\/maps.googleapis.com\/maps\/api\/staticmap?size=600x150&maptype=roadmap&markers=color:green%7Clabel:S%7C35.12533%2C36.76929&markers=color:red%7Clabel:D%7C35.13223%2C36.7536&path=color:0x007bff%7Cweight:5%7C35.12533%2C36.76929%7C35.13223%2C36.7536&key=AIzaSyAPFR_XbRN0XZ5Iz3AYDjNYHGJG2s2QWwM","DurationToPassenger":"0","rideId":"229","passengerId":"64070ab2e6cfa4be0c58","durationOfRideValue":"292","paymentAmount":"17280.00","paymentMethod":"cash","isHaveSteps":"startEnd","step0":"35.1270850911746,36.76192492246628","step1":"","step2":"","step3":"","step4":"","passengerWalletBurc":"0.00","carType":"Speed","kazan":"8","startNameLocation":"\u062f\u0648\u0627\u0631 \u0627\u0644\u0627\u0633\u0643\u0627\u0646","endNameLocation":"\u062d\u0645\u0627\u0629","timeOfOrder":"2025-11-25T20:16:53.203785","totalPassenger":"17280.00"}
[2025-11-25 20:16:54] SQL statement prepared successfully. Attempting to execute...
[2025-11-25 20:16:54] SUCCESS: Database insert was successful for rideId: 229
[2025-11-29 13:25:59] --- New Request Received ---
[2025-11-29 13:25:59] Incoming POST data: {"driver_id":"f48c50ef7bb6f55e710c","status":"Apply","passengerLocation":"33.43231,36.24297","passengerDestination":"33.43562,36.16933","Duration":"1419","totalCost":"0.00","Distance":"12.68","name":"\u062d\u0645\u0632\u0647","phone":"963992952235","email":"963992952235@intaleqapp.com","WalletChecked":"false","tokenPassenger":"eduBTsgC501SmEff3v4MGi:APA91bGf2PpOdgC3dEK7h3E4Kccu30tw7rbZeAJe7Co5JmHrrkwsz0pijAXFcjrbNkWQLI867bTogGGjL847OBNQ8FHSQJN9Gs1RY-GwaXh9ubffApwEdd0","direction":"https:\/\/maps.googleapis.com\/maps\/api\/staticmap?size=600x150&maptype=roadmap&markers=color:green%7Clabel:S%7C33.43231%2C36.24297&markers=color:red%7Clabel:D%7C33.43562%2C36.16933&path=color:0x007bff%7Cweight:5%7C33.43231%2C36.24297%7C33.43562%2C36.16933&key=AIzaSyAPFR_XbRN0XZ5Iz3AYDjNYHGJG2s2QWwM","DurationToPassenger":"0","rideId":"290","passengerId":"849a9faf3e68c1aeb708","durationOfRideValue":"1419","paymentAmount":"60710.00","paymentMethod":"cash","isHaveSteps":"startEnd","step0":"33.449831692690715,36.20406500995159","step1":"","step2":"","step3":"","step4":"","passengerWalletBurc":"0.00","carType":"Speed","kazan":"8","startNameLocation":"\u0623\u0634\u0631\u0641\u064a\u0629","endNameLocation":"\u062c\u062f\u064a\u062f\u0629 \u0639\u0631\u0637\u0648\u0632","timeOfOrder":"2025-11-29T13:25:58.938290","totalPassenger":"60710.00"}
[2025-11-29 13:25:59] SQL statement prepared successfully. Attempting to execute...
[2025-11-29 13:25:59] SUCCESS: Database insert was successful for rideId: 290
[2025-12-01 10:28:09] --- New Request Received ---
[2025-12-01 10:28:09] Incoming POST data: {"driver_id":"b21737ec0edb0d02eb86","status":"Apply","passengerLocation":"33.4323,36.24329","passengerDestination":"33.41301,36.23664","Duration":"575","totalCost":"0.00","Distance":"3.64","name":"\u062d\u0645\u0632\u0647","phone":"963992952235","email":"963992952235@intaleqapp.com","WalletChecked":"false","tokenPassenger":"eduBTsgC501SmEff3v4MGi:APA91bGf2PpOdgC3dEK7h3E4Kccu30tw7rbZeAJe7Co5JmHrrkwsz0pijAXFcjrbNkWQLI867bTogGGjL847OBNQ8FHSQJN9Gs1RY-GwaXh9ubffApwEdd0","direction":"https:\/\/maps.googleapis.com\/maps\/api\/staticmap?size=600x150&maptype=roadmap&markers=color:green%7Clabel:S%7C33.4323%2C36.24329&markers=color:red%7Clabel:D%7C33.41301%2C36.23664&path=color:0x007bff%7Cweight:5%7C33.4323%2C36.24329%7C33.41301%2C36.23664&key=AIzaSyAPFR_XbRN0XZ5Iz3AYDjNYHGJG2s2QWwM","DurationToPassenger":"0","rideId":"314","passengerId":"849a9faf3e68c1aeb708","durationOfRideValue":"575","paymentAmount":"19754.00","paymentMethod":"cash","isHaveSteps":"startEnd","step0":"33.42334065389521,36.23577006161213","step1":"","step2":"","step3":"","step4":"","passengerWalletBurc":"0.00","carType":"Speed","kazan":"8","startNameLocation":"\u0623\u0634\u0631\u0641\u064a\u0629","endNameLocation":"\u0627\u0644\u0634\u064a\u062e \u0625\u0628\u0631\u0627\u0647\u064a\u0645","timeOfOrder":"2025-12-01T10:28:11.316238","totalPassenger":"19754.00"}
[2025-12-01 10:28:09] SQL statement prepared successfully. Attempting to execute...
[2025-12-01 10:28:09] SUCCESS: Database insert was successful for rideId: 314
[2026-01-08 01:45:12] --- New Request Received ---
[2026-01-08 01:45:12] Incoming POST data: {"driver_id":"34feffd3fa72d6bee56b","status":"Apply","passengerLocation":"31.990668","passengerDestination":"35.877682","Duration":"35.930359","totalCost":"3.50","Distance":"8.5 km","name":"Hamza Passenger","phone":"0791234567","email":"client@email.com","WalletChecked":"false","tokenPassenger":"PASSENGER_FCM_TOKEN_XYZ","direction":"","DurationToPassenger":"5 min","rideId":"9999","passengerId":"55","durationOfRideValue":"20 min","paymentAmount":"3.50","paymentMethod":"cash","isHaveSteps":"false","step0":"","step1":"","step2":"","step3":"","step4":"","passengerWalletBurc":"3.50","carType":"speed","kazan":"2.75","startNameLocation":"\u0627\u0644\u062c\u0627\u0645\u0639\u0629 \u0627\u0644\u0623\u0631\u062f\u0646\u064a\u0629 - \u0627\u0644\u0628\u0648\u0627\u0628\u0629 \u0627\u0644\u0631\u0626\u064a\u0633\u064a\u0629","endNameLocation":"\u0627\u0644\u0639\u0628\u062f\u0644\u064a \u0645\u0648\u0644 - \u0627\u0644\u0628\u0648\u0644\u064a\u0641\u0627\u0631\u062f","timeOfOrder":"2026-01-08T01:45:11.370578","totalPassenger":"3.50"}
[2026-01-08 01:45:12] SQL statement prepared successfully. Attempting to execute...
[2026-01-08 01:45:12] EXCEPTION: An unexpected error occurred: SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'direction_url' cannot be null
[2026-01-08 21:23:04] --- New Request Received ---
[2026-01-08 21:23:04] Incoming POST data: {"driver_id":"34feffd3fa72d6bee56b","status":"Apply","passengerLocation":"32.073743222739","passengerDestination":"36.096920477709","Duration":"35.930359","totalCost":"3.50","Distance":"8.9 km","name":"Hamza Passenger","phone":"0791234567","email":"client@email.com","WalletChecked":"false","tokenPassenger":"PASSENGER_FCM_TOKEN_XYZ","direction":"","DurationToPassenger":"5 min","rideId":"9999","passengerId":"55","durationOfRideValue":"18 min","paymentAmount":"53.50","paymentMethod":"cash","isHaveSteps":"false","step0":"","step1":"","step2":"","step3":"","step4":"","passengerWalletBurc":"3.50","carType":"speed","kazan":"2.75","startNameLocation":"\u0627\u0644\u062c\u0627\u0645\u0639\u0629 \u0627\u0644\u0623\u0631\u062f\u0646\u064a\u0629 - \u0627\u0644\u0628\u0648\u0627\u0628\u0629 \u0627\u0644\u0631\u0626\u064a\u0633\u064a\u0629","endNameLocation":"\u0627\u0644\u0639\u0628\u062f\u0644\u064a \u0645\u0648\u0644 - \u0627\u0644\u0628\u0648\u0644\u064a\u0641\u0627\u0631\u062f","timeOfOrder":"2026-01-08T21:23:03.507502","totalPassenger":"53.50"}
[2026-01-08 21:23:04] SQL statement prepared successfully. Attempting to execute...
[2026-01-08 21:23:04] EXCEPTION: An unexpected error occurred: SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'direction_url' cannot be null
[2026-01-22 14:29:49] --- New Request Received ---
[2026-01-22 14:29:49] Incoming POST data: {"driver_id":"34feffd3fa72d6bee56b","status":"Apply","passengerLocation":"startLocation","passengerDestination":"endLocation","Duration":"durationToPassenger","totalCost":"totalCost","Distance":"distance","name":"passengerName","phone":"passengerPhone","email":"email","WalletChecked":"WalletChecked","tokenPassenger":"passengerToken","direction":"","DurationToPassenger":"DurationToPassenger","rideId":"rideId","passengerId":"passengerId","durationOfRideValue":"durationOfRideValue","paymentAmount":"paymentAmount","paymentMethod":"cash","isHaveSteps":"isHaveSteps","step0":"step0","step1":"step1","step2":"step2","step3":"step3","step4":"step4","passengerWalletBurc":"totalCost","carType":"carType","kazan":"kazan","startNameLocation":"startNameLocation","endNameLocation":"endNameLocation","timeOfOrder":"2026-01-22T14:29:46.887096","totalPassenger":"paymentAmount"}
[2026-01-22 14:29:49] SQL statement prepared successfully. Attempting to execute...
[2026-01-22 14:29:49] EXCEPTION: An unexpected error occurred: SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'direction_url' cannot be null
[2026-01-22 14:31:31] --- New Request Received ---
[2026-01-22 14:31:31] Incoming POST data: {"driver_id":"34feffd3fa72d6bee56b","status":"Apply","passengerLocation":"startLocation","passengerDestination":"endLocation","Duration":"durationToPassenger","totalCost":"totalCost","Distance":"distance","name":"passengerName","phone":"passengerPhone","email":"email","WalletChecked":"WalletChecked","tokenPassenger":"passengerToken","direction":"","DurationToPassenger":"DurationToPassenger","rideId":"rideId","passengerId":"passengerId","durationOfRideValue":"durationOfRideValue","paymentAmount":"paymentAmount","paymentMethod":"cash","isHaveSteps":"isHaveSteps","step0":"step0","step1":"step1","step2":"step2","step3":"step3","step4":"step4","passengerWalletBurc":"totalCost","carType":"carType","kazan":"kazan","startNameLocation":"startNameLocation","endNameLocation":"endNameLocation","timeOfOrder":"2026-01-22T14:31:29.409730","totalPassenger":"paymentAmount"}
[2026-01-22 14:31:31] SQL statement prepared successfully. Attempting to execute...
[2026-01-22 14:31:31] EXCEPTION: An unexpected error occurred: SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'direction_url' cannot be null
[2026-01-22 14:39:59] --- New Request Received ---
[2026-01-22 14:39:59] Incoming POST data: {"driver_id":"34feffd3fa72d6bee56b","status":"Apply","passengerLocation":"startLocation","passengerDestination":"endLocation","Duration":"durationToPassenger","totalCost":"totalCost","Distance":"distance","name":"passengerName","phone":"passengerPhone","email":"email","WalletChecked":"WalletChecked","tokenPassenger":"passengerToken","direction":"","DurationToPassenger":"DurationToPassenger","rideId":"rideId","passengerId":"passengerId","durationOfRideValue":"durationOfRideValue","paymentAmount":"paymentAmount","paymentMethod":"cash","isHaveSteps":"isHaveSteps","step0":"step0","step1":"step1","step2":"step2","step3":"step3","step4":"step4","passengerWalletBurc":"totalCost","carType":"carType","kazan":"kazan","startNameLocation":"startNameLocation","endNameLocation":"endNameLocation","timeOfOrder":"2026-01-22T14:39:56.986847","totalPassenger":"paymentAmount"}
[2026-01-22 14:39:59] SQL statement prepared successfully. Attempting to execute...
[2026-01-22 14:39:59] EXCEPTION: An unexpected error occurred: SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'direction_url' cannot be null
[2026-02-20 16:39:52] --- New Request Received ---
[2026-02-20 16:39:52] Incoming POST data: {"driver_id":"eefed62b0aeb9e304efd","status":"Apply","passengerLocation":"32.11172","passengerDestination":"36.06738","Duration":"36.06738","totalCost":"173.00","Distance":"0.0","name":"\u062d\u0645\u0632\u0647 \u0639\u0627\u064a\u062f","phone":"963992952235","email":"963992952235@intaleqapp.com","WalletChecked":"false","tokenPassenger":"e9X4q6nL3EuRu2OIsWJ-A2:APA91bE223jfIOjWbSrjF41HZjeZVWc-jm2NAg2sXTmoyHUkoC10uycmxl0Ne4WcE8aojjTm7fWTPm5aEFi1xJKN1Wy0vgupUmSD2LcKBcE1Cym_GTvikME","direction":"","DurationToPassenger":"","rideId":"782","passengerId":"849a9faf3e68c1aeb708","durationOfRideValue":"","paymentAmount":"173.00","paymentMethod":"cash","isHaveSteps":"false","step0":"32.11180279564045,36.067136228084564","step1":"","step2":"","step3":"","step4":"","passengerWalletBurc":"173.00","carType":"Fixed Price","kazan":"0.00","startNameLocation":"\u0648\u0627\u062f\u064a \u0623\u0643\u064a\u062f\u0631","endNameLocation":"\u0648\u0627\u062f\u064a \u0623\u0643\u064a\u062f\u0631","timeOfOrder":"2026-02-20T16:40:10.040464","totalPassenger":"173.00"}
[2026-02-20 16:39:52] SQL statement prepared successfully. Attempting to execute...
[2026-02-20 16:39:52] EXCEPTION: An unexpected error occurred: SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'direction_url' cannot be null

File: ride/overLay/getArgumentAfterAppliedFromBackground.php

<?php
require_once __DIR__ . '/../../connect.php';

$driver_id = filterRequest('driver_id');

if (empty($driver_id)) {
    jsonError('Missing driver ID');
    exit;
}

// Fetch latest record for this driver:
$sql = "SELECT * FROM write_argument_after_applied_from_background 
        WHERE driver_id = :driver_id 
        AND TIMESTAMPDIFF(MINUTE, time_of_order, NOW()) <= 2
        ORDER BY time_of_order DESC 
        LIMIT 1";



$stmt = $con->prepare($sql);
$stmt->bindParam(':driver_id', $driver_id);
$stmt->execute();

$row = $stmt->fetch(PDO::FETCH_ASSOC);
if ($row) {
    // convert WKT POINT back to "lat,lng"
    foreach (['passenger_location', 'passenger_destination'] as $f) {
        if (!empty($row["{$f}_wkt"])) {
            // WKT format: POINT(lng lat)
            preg_match('/POINT\(([^ ]+) ([^ ]+)\)/', $row["{$f}_wkt"], $m);
            $row[$f] = "{$m[2]},{$m[1]}";
        }
        unset($row["{$f}_wkt"]);
    }
    jsonSuccess($row);
} else {
    jsonError('No data found');
}

File: ride/promo/add.php

<?php
require_once __DIR__ . '/../../connect.php';

$promoCode   = filterRequest("promoCode");
$amount      = filterRequest("amount");
$description = filterRequest("description");
$passengerID = filterRequest("passengerID"); // يفترض أنه ID وليس قيمة مشفرة

$sql = "INSERT INTO `promos`(
            `promo_code`, `amount`, `description`, `passengerID`, 
            `validity_start_date`, `validity_end_date`
        ) 
        VALUES (
            :promoCode, :amount, :description, :passengerID,
            NOW(), DATE_ADD(NOW(), INTERVAL 1 WEEK)
        )";

$stmt = $con->prepare($sql);
$stmt->bindValue(':promoCode', $promoCode);
$stmt->bindValue(':amount', $amount);
$stmt->bindValue(':description', $description);
$stmt->bindValue(':passengerID', $passengerID);

$stmt->execute();

if ($stmt->rowCount() > 0) {
    jsonSuccess(null, "Promo data saved successfully");
} else {
    jsonError("Failed to save promo data");
}
?>

File: ride/promo/update.php

<?php
require_once __DIR__ . '/../../connect.php';

$id = filterRequest("id");
$promoCode = filterRequest("promoCode");
$description = filterRequest("description");
$validityStartDate = filterRequest("validityStartDate");
$validityEndDate = filterRequest("validityEndDate");

$sql = "UPDATE `promos` SET
  `promo_code` = :promoCode,
  `description` = :description,
  `validity_start_date` = :validityStartDate,
  `validity_end_date` = :validityEndDate
WHERE `id` = :id";

$stmt = $con->prepare($sql);
$stmt->bindParam(':promoCode', $promoCode);
stmt->bindParam(':description', $description);
stmt->bindParam(':validityStartDate', $validityStartDate);
$stmt->bindParam(':validityEndDate', $validityEndDate);
stmt->bindParam(':id', $id, PDO::PARAM_INT);

$stmt->execute();

if ($stmt->rowCount() > 0) {
    jsonSuccess(null, "Promo data updated successfully");
} else {
    jsonError("Failed to update promo data");
}
?>

File: ride/promo/get.php

<?php
require_once __DIR__ . '/../../connect.php';

$promo_code = filterRequest("promo_code");

$sql = "SELECT
    `id`,
    `promo_code`,
    `amount`,
    `description`,
    `validity_start_date`,
    `validity_end_date`
FROM
    `promos`
WHERE
    `promo_code` = :promo_code
    AND CURDATE() BETWEEN validity_start_date AND validity_end_date";

$stmt = $con->prepare($sql);
$stmt->bindParam(':promo_code', $promo_code, PDO::PARAM_STR);
$stmt->execute();
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);

if ($result) {
    jsonSuccess($result);
} else {
    jsonError("Failed to retrieve promo records");
}
?>

File: ride/promo/getPromoFirst.php

<?php
require_once __DIR__ . '/../../connect.php';

// Get passengerID and encrypt it only if هو رقم مشفر (إذا لزم الأمر)
// $passengerID = $encryptionHelper->encryptData(filterRequest("passengerID"));
$passengerID = filterRequest("passengerID"); // استخدم هذا إذا ID رقم فقط

$sql = "SELECT
    `id`,
    `promo_code`,
    `amount`,
    `description`,
    `validity_start_date`,
    `validity_end_date`
FROM
    `promos`
WHERE
    `passengerID` = ? AND CURDATE() BETWEEN validity_start_date AND validity_end_date";

$stmt = $con->prepare($sql);
$stmt->bindParam(1, $passengerID);
$stmt->execute();

$result = $stmt->fetchAll(PDO::FETCH_ASSOC);

if ($result) {
    jsonSuccess($result);
} else {
    jsonError("Failed to retrieve promo records");
}
?>

File: ride/promo/delete.php

<?php
require_once __DIR__ . '/../../connect.php';

$id = filterRequest("id");

$sql = "DELETE FROM `promos` WHERE `id` = :id";
$stmt = $con->prepare($sql);
$stmt->bindParam(':id', $id, PDO::PARAM_INT); // استخدام bindParam لحماية الاستعلام
$stmt->execute();

if ($stmt->rowCount() > 0) {
    jsonSuccess(null, "Promo data deleted successfully");
} else {
    jsonError("Failed to delete promo data");
}
?>

File: ride/promo/getPromoBytody.php

<?php
require_once __DIR__ . '/../../connect.php';


 $passengerID = filterRequest("passengerID"); 

$sql = "SELECT
   `id`, `promo_code`, `amount`, `description`, `passengerID`, `validity_start_date`,
    DATEDIFF(promos.validity_end_date, CURDATE()) AS validity_end_date
FROM
    `promos`
WHERE
    (passengerID = '$passengerID' OR passengerID LIKE '%all%')
    AND promos.validity_start_date <= CURDATE()
    AND promos.validity_end_date >= CURDATE();";

$stmt = $con->prepare($sql);
$stmt->execute();
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);

if ($result) {
    // Print all promo records
    jsonSuccess($result);
} else {
    // Print a failure message
    jsonError($message = "Failed to retrieve promo records");
   
}
?>

File: ride/carDrivers/add.php

<?php
require_once __DIR__ . '/../../connect.php';

// استقبال القيم
$driverID          = filterRequest("driverID");
$vin               = $encryptionHelper->encryptData(filterRequest("vin"));
$car_plate         = $encryptionHelper->encryptData(filterRequest("car_plate"));
$make              = filterRequest("make");
$model             = filterRequest("model");
$year              = filterRequest("year");
$expiration_date   = filterRequest("expiration_date");
$color             = filterRequest("color");
$owner             = $encryptionHelper->encryptData(filterRequest("owner"));
$color_hex         = filterRequest("color_hex");
$address           = $encryptionHelper->encryptData(filterRequest("address"));
$displacement      = filterRequest("displacement");
$fuel              = filterRequest("fuel");
$registration_date = filterRequest("registration_date");

// SQL statement
$sql = "INSERT INTO `captains_car` (
    `driverID`, `vin`, `car_plate`, `make`, `model`, `year`, `expiration_date`,
    `color`, `owner`, `color_hex`, `address`, `displacement`, `fuel`, `registration_date`
) VALUES (
    :driverID, :vin, :car_plate, :make, :model, :year, :expiration_date,
    :color, :owner, :color_hex, :address, :displacement, :fuel, :registration_date
)";

$stmt = $con->prepare($sql);

// Bind parameters
$stmt->bindParam(':driverID', $driverID);
$stmt->bindParam(':vin', $vin);
$stmt->bindParam(':car_plate', $car_plate);
$stmt->bindParam(':make', $make);
$stmt->bindParam(':model', $model);
$stmt->bindParam(':year', $year, PDO::PARAM_INT);
$stmt->bindParam(':expiration_date', $expiration_date);
$stmt->bindParam(':color', $color);
$stmt->bindParam(':owner', $owner);
$stmt->bindParam(':color_hex', $color_hex);
$stmt->bindParam(':address', $address);
$stmt->bindParam(':displacement', $displacement);
$stmt->bindParam(':fuel', $fuel);
$stmt->bindParam(':registration_date', $registration_date);

$stmt->execute();
$insertedId = $con->lastInsertId();

if ($stmt->rowCount() > 0) {
    jsonSuccess(["id" => $insertedId]);
} else {
    jsonError("Failed to save car registration information");
}
?>

File: ride/carDrivers/get.php

<?php
// get_driver_cars.php
require_once __DIR__ . '/../../connect.php';

// استقبال driverID (نصي لأنه غالباً محفوظ كنص)
$driverID = filterRequest("driverID");

try {
    if (empty($driverID)) {
        jsonError("driverID is required");
        exit;
    }

    // هنعرّف دالة لتوحيد الصف من أي جدول لنفس المخطط
    function normalize_car_row(array $row, string $source, $encryptionHelper): array {
        // بعض الحقول قد لا تكون موجودة في كلا الجدولين
        $get = function($k, $default = null) use ($row) {
            return array_key_exists($k, $row) ? $row[$k] : $default;
        };

        // فك التشفير عند الحاجة وبشكل آمن
        $dec = function($v) use ($encryptionHelper) {
            if ($v === null || $v === '') return $v;
            try { return $encryptionHelper->decryptData($v); } catch (\Throwable $e) { return $v; }
        };

        // أعمدة مشتركة/موحّدة للإخراج
        return [
            'id'               => $get('id'),
            'driverID'         => $get('driverID'),
            'vin'              => $dec($get('vin')),                // إن كان مُشفراً
            'car_plate'        => $dec($get('car_plate')),          // إن كان مُشفراً
            'make'             => $get('make'),
            'model'            => $get('model'),
            'year'             => $get('year'),
            'expiration_date'  => $get('expiration_date'),
            'color'            => $get('color'),
            'color_hex'        => $get('color_hex'),
            'owner'            => $dec($get('owner')),              // إن كان مُشفراً
            'address'          => $dec($get('address')),            // قد لا يوجد في CarRegistration
            'type'             => $get('type'),                     // إن وُجد
            'isDefault'        => (int)($get('isDefault', 0)),
            'status'           => $get('status'),
            'created_at'       => $get('created_at'),
            'source'           => $source,                          // لمعرفة مصدر السجل
        ];
    }

    // 1) جلب من captains_car
    $sql1 = "SELECT * FROM captains_car WHERE driverID = :driverID";
    $st1  = $con->prepare($sql1);
    $st1->execute([':driverID' => $driverID]);
    $rows1 = $st1->fetchAll(PDO::FETCH_ASSOC);

    // 2) جلب من CarRegistration
    $sql2 = "SELECT * FROM CarRegistration WHERE driverID = :driverID";
    $st2  = $con->prepare($sql2);
    $st2->execute([':driverID' => $driverID]);
    $rows2 = $st2->fetchAll(PDO::FETCH_ASSOC);

    // 3) توحيد النتائج مع فك التشفير
    $result = [];
    foreach ($rows1 as $r) { $result[] = normalize_car_row($r, 'captains_car', $encryptionHelper); }
    foreach ($rows2 as $r) { $result[] = normalize_car_row($r, 'CarRegistration', $encryptionHelper); }

    if (empty($result)) {
        jsonError("No driver car data found");
        exit;
    }

    // 4) ترتيب النتيجة: السيارات الافتراضية أولاً ثم الأحدث إنشاءً
    usort($result, function($a, $b) {
        // isDefault desc
        if ((int)$a['isDefault'] !== (int)$b['isDefault']) {
            return (int)$b['isDefault'] <=> (int)$a['isDefault'];
        }
        // created_at desc (لو أحدهم null لن يؤثر)
        return strcmp((string)$b['created_at'], (string)$a['created_at']);
    });

    jsonSuccess($result);

} catch (PDOException $e) {
    error_log("Database error (get_driver_cars): " . $e->getMessage());
    jsonError("Database error occurred");
} catch (Throwable $e) {
    error_log("App error (get_driver_cars): " . $e->getMessage());
    jsonError("Unexpected error occurred");
}

File: ride/carDrivers/delete.php

<?php
require_once __DIR__ . '/../../connect.php';

// استقبال ID السجل
$id = filterRequest("id");

// حذف السجل من جدول captains_car (أو CarRegistration لو هو الصحيح فعلاً)
$sql = "DELETE FROM captains_car WHERE id = :id";
$stmt = $con->prepare($sql);
$stmt->bindParam(':id', $id, PDO::PARAM_INT);
$stmt->execute();

// التحقق من نجاح الحذف
if ($stmt->rowCount() > 0) {
    jsonSuccess(null, "Car registration deleted successfully");
} else {
    jsonError("Failed to delete car registration");
}
?>

File: Admin/jwtService.php

<?php
// ============================================================
// Admin/jwtService.php (Customer Service Login)
// ============================================================

require_once __DIR__ . '/../core/bootstrap.php';

header('Content-Type: application/json');
header("Access-Control-Allow-Origin: https://intaleqapp.com");
header("Access-Control-Allow-Methods: POST, OPTIONS");
header("Access-Control-Allow-Headers: Content-Type, Authorization");

if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
    http_response_code(200);
    exit;
}

// ── Rate Limiting ───────────────────────────────────────────
$limiter = new RateLimiter($redis);
$limiter->enforce(RateLimiter::identifier(), 'login');

try {
    $email    = filterRequest('email') ?? '';
    $password = filterRequest('password') ?? '';
    $audience = filterRequest('aud') ?? '';

    $allowed1 = getenv('allowedService1');
    $allowed2 = getenv('allowedService2');
    $allowedAudiences = array_values(array_filter([$allowed1, $allowed2]));

    if (empty($email) || empty($password) || empty($audience)) {
        jsonError('Email and password are required.', 400);
    }

    if (!in_array($audience, $allowedAudiences, true)) {
        jsonError('Invalid audience', 400);
    }

    $con = Database::get('main');

    // استخدام user table ويفضل استخدام password_hash لاحقا مثل admin_users
    $stmt = $con->prepare("SELECT `id`, `password`, `email` FROM `users` WHERE email = :email LIMIT 1");
    $stmt->execute([':email' => $email]);
    $user = $stmt->fetch();

    $startTime = microtime(true);

    // دعم password_verify مع البقاء على التوافق مع كلمات السر القديمة (Plain Text)
    if ($user && (password_verify($password, $user['password']) || $user['password'] === $password)) {
        
        $limiter->reset(RateLimiter::identifier(), 'login');
        
        $jwtService = new JwtService($redis);
        $jwt = $jwtService->generateAccessToken($user['id'], 'service', $audience);
        $refresh = $jwtService->generateRefreshToken($user['id']);

        jsonSuccess([
            'jwt' => $jwt,
            'refresh_token' => $refresh['token'],
            'expires_in' => 900 // أو 6600 كما كان في الكود الأصلي
        ]);

    } else {
        $elapsed = microtime(true) - $startTime;
        if ($elapsed < 0.1) usleep((int)((0.1 - $elapsed) * 1000000));
        
        securityLog("Service login failed", ['email' => $email]);
        jsonError('Invalid email or password', 401);
    }

} catch (PDOException $e) {
    securityLog("Service Login PDO Error", ['msg' => $e->getMessage()]);
    jsonError('Login failed: Database error', 500);
} catch (Exception $e) {
    securityLog("Service Login Error", ['msg' => $e->getMessage()]);
    jsonError('Login failed: Server error', 500);
}

File: Admin/send_whatsapp_message.php

<?php
// File: send_whatsapp_message.php
// هذا السكربت يرسل رسالة واتساب فقط باستخدام RaseelPlus API

require_once __DIR__ . '/../connect.php'; // فقط إذا كنت تحتاج للوصول إلى environment

error_log("--- [send_whatsapp_message.php] Script execution started ---");

// استقبال المعطيات من POST
$receiver = filterRequest("receiver"); // رقم الهاتف
$message = filterRequest("message");  // نص الرسالة

if (empty($receiver) || empty($message)) {
    error_log("[send_whatsapp_message.php] Error: Missing receiver or message.");
    jsonError('Phone number and message are required.');
    exit();
}

// بيانات Raseel
$instanceId   = getenv("RASEEL_DRIVER_INSTANCE_ID");
$accessToken  = getenv("RASEEL_DRIVER_ACCESS_TOKEN");

// API URL
$apiUrl = 'https://raseelplus.com/api/send';

// تجهيز البيانات للإرسال
$payload = [
    "number"      => $receiver,
    "type"        => "text",
    "message"     => $message,
    "instance_id" => $instanceId,
    "access_token"=> $accessToken
];

error_log("[send_whatsapp_message.php] Sending payload: " . json_encode($payload));

// إرسال الطلب
$response = callAPI("POST", $apiUrl, json_encode($payload));
error_log("[send_whatsapp_message.php] Raw response: " . print_r($response, true));

// فحص الاستجابة
if ($response && !isset($response->error) && (isset($response->status) && $response->status == 'success' || isset($response->message))) {
    jsonSuccess(null, "Message sent successfully.");
} else {
    $errorMessage = isset($response->message) ? $response->message : "Unknown error.";
    error_log("[send_whatsapp_message.php] Failed to send: $errorMessage");
    jsonError("Failed to send message: $errorMessage");
}

// دالة cURL
function callAPI($method, $url, $data)
{
    $curl = curl_init();
    curl_setopt_array($curl, [
        CURLOPT_URL => $url,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_ENCODING => "",
        CURLOPT_MAXREDIRS => 10,
        CURLOPT_TIMEOUT => 30,
        CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
        CURLOPT_CUSTOMREQUEST => $method,
        CURLOPT_POSTFIELDS => $data,
        CURLOPT_HTTPHEADER => [
            "Content-Type: application/json",
            "Accept: application/json"
        ],
    ]);
    $response = curl_exec($curl);
    $err = curl_error($curl);
    curl_close($curl);

    if ($err) {
        error_log("[callAPI] cURL Error: $err");
        return null;
    } else {
        return json_decode($response);
    }
}
?>

File: Admin/sendEmailToDrivertransaction.php

<?php
// File: send_payment_received_email.php

require_once __DIR__ . '/../connect.php';

$driverID        = filterRequest('driverID');
$totalAmount     = filterRequest('total_amount');
$driverPhone     = filterRequest('phone');
$driverArabicName = filterRequest('name_arabic');
$accountBank     = filterRequest('accountBank');
$driverEmail     = filterRequest('email');

// لغة الإيميل (تلقائي إنجليزي حالياً، يمكن تعيينها لاحقًا حسب المستخدم)
$language = 'en';

// عنوان واسم التطبيق الرسمي
$appName = "tripz"; // الاسم الجديد مع حرف "Z"
$domain  = "https://tripz-egypt.com";

// محتوى الإيميل - باللغة الإنجليزية
$bodyEmail = "<html>
    <head>
      <style>
        body { font-family: Arial, sans-serif; color: #333; background: #f9f9f9; padding: 20px; }
        .container { background: #fff; padding: 30px; border-radius: 8px; max-width: 600px; margin: auto; }
        h1 { color: #007bff; }
        p { font-size: 16px; }
      </style>
    </head>
    <body>
      <div class='container'>
        <img src='$domain/assets/logo.png' alt='$appName Logo' style='width: 150px; margin: 20px auto; display: block;'>
        <h1>Payment Sent - $appName</h1>
        <p>Thank you for being a valued driver on the $appName platform.</p>
        <p>We have sent a payment of <strong>$totalAmount EGP</strong> to your account <strong>$accountBank</strong>.</p>
        <p>Please note that it may take a few days for your bank to process this transaction.</p>
        <p>We appreciate your efforts and are proud to have you on board with $appName.</p>
        <p style='margin-top: 40px;'>Regards,<br><strong>tripz Team</strong></p>
        <p style='font-size: 12px; color: #888;'>tripz, Egypt | $domain</p>
      </div>
    </body>
</html>";

// محتوى الإيميل - باللغة العربية
$bodyEmailAr = "<html>
    <head>
      <style>
        body { font-family: 'Cairo', sans-serif; color: #333; background: #f9f9f9; padding: 20px; direction: rtl; }
        .container { background: #fff; padding: 30px; border-radius: 8px; max-width: 600px; margin: auto; text-align: right; }
        h1 { color: #007bff; }
        p { font-size: 16px; }
      </style>
    </head>
    <body>
      <div class='container'>
        <img src='$domain/assets/logo.png' alt='$appName' style='width: 150px; margin: 20px auto; display: block;'>
        <h1>تم إرسال الدفعة - $appName</h1>
        <p>شكرًا لك لكونك سائقًا مميزًا على منصة $appName.</p>
        <p>لقد تم إرسال دفعة قدرها <strong>$totalAmount جنيه</strong> إلى حسابك <strong>$accountBank</strong>.</p>
        <p>يرجى ملاحظة أن عملية التحويل قد تستغرق بضعة أيام حسب إجراءات البنك.</p>
        <p>نقدّر جهودك ونتطلع إلى استمرار الشراكة معك على تطبيق $appName.</p>
        <p style='margin-top: 40px;'>مع التحية،<br><strong>فريق $appName</strong></p>
        <p style='font-size: 12px; color: #888;'>$appName - مصر | $domain</p>
      </div>
    </body>
</html>";

// إعدادات الإيميل
$supportEmail = 'support@tripz-egypt.com';
$headers  = "MIME-Version: 1.0\r\n";
$headers .= "Content-Type: text/html; charset=UTF-8\r\n";
$headers .= "From: tripz Egypt <$supportEmail>\r\n";

// إرسال الإيميل إن وُجد عنوان صالح
if (!empty($driverEmail)) {
    $subject = "Payment Sent - $appName";
    $message = ($language === 'ar') ? $bodyEmailAr : $bodyEmail;

    if (mail($driverEmail, $subject, $message, $headers)) {
        jsonSuccess(null, "Email sent successfully to $driverEmail");
    } else {
        jsonError("Failed to send email to $driverEmail");
    }
} else {
    jsonError("Invalid or missing driver email address.");
}
?>

File: Admin/getPassengerDetails.php

<?php
require_once __DIR__ . '/../connect.php';

$sql = "SELECT
    `passengers`.`id`,
    `passengers`.`phone`,
    `passengers`.`email`,
    `passengers`.`gender`,
    `passengers`.`status`,
    `passengers`.`birthdate`,
    `passengers`.`site`,
    `passengers`.`first_name`,
    `passengers`.`last_name`,
    `passengers`.`sosPhone`,
    `passengers`.`education`,
    `passengers`.`employmentType`,
    `passengers`.`maritalStatus`,
    `passengers`.`created_at`,
    `passengers`.`updated_at`,
    (
        SELECT COUNT(`id`) FROM `passengers`
    ) AS countPassenger,
    (
        SELECT COUNT(`id`) FROM `feedBack`
    ) AS countFeedback,
    (
        SELECT CAST(AVG(`rating`) AS DECIMAL(10,2))
        FROM `ratingPassenger`
        WHERE `passenger_id` = `passengers`.`id`
    ) AS ratingPassenger,
    (
        SELECT COUNT(`driverID`)
        FROM `ratingPassenger`
        WHERE `passenger_id` = `passengers`.`id`
    ) AS countDriverRate,
    (
        SELECT COUNT(`passengerID`)
        FROM `canecl`
        WHERE `passengerID` = `passengers`.`id`
    ) AS countPassengerCancel,
    (
        SELECT CAST(AVG(`rating`) AS DECIMAL(10,2))
        FROM `ratingDriver`
        WHERE `passenger_iD` = `passengers`.`id`
    ) AS passengerAverageRating,
    (
        SELECT COUNT(`driver_id`)
        FROM `ratingDriver`
        WHERE `passenger_id` = `passengers`.`id`
    ) AS countPassengerRate,
    (
        SELECT COUNT(`ride`.`passenger_id`)
        FROM `ride`
        WHERE `ride`.`passenger_id` = `passengers`.`id`
    ) AS countPassengerRide,
    (
        SELECT `token`
        FROM `tokens`
        WHERE `tokens`.`passengerID` = `passengers`.`id`
    ) AS passengerToken
FROM
    `passengers`
GROUP BY
    `passengers`.`id`
ORDER BY
    countPassengerRide DESC
LIMIT 10";

$stmt = $con->prepare($sql);
$stmt->execute();
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);

// ✅ فك التشفير للحقول الحساسة
foreach ($result as &$row) {
    $fieldsToDecrypt = [
        "phone", "email", "gender", "birthdate", "site",
        "first_name", "last_name", "sosPhone",
        "education", "employmentType", "maritalStatus", "passengerToken"
    ];

    foreach ($fieldsToDecrypt as $field) {
    if (isset($row[$field]) && $row[$field] !== null) {
        $decrypted = $encryptionHelper->decryptData($row[$field]);
        if ($decrypted !== false) {
            $row[$field] = $decrypted;
        } else {
            // سجل أو تجاهل القيم التي فشل فك تشفيرها
            $row[$field] = null; // أو احتفظ بالقيمة المشفرة
            error_log("Failed to decrypt field '$field' for passenger ID: " . $row['id']);
        }
    }
}
}

if ($stmt->rowCount() > 0) {
    jsonSuccess($data = $result);
} else {
    jsonError("No records found");
}
?>

File: Admin/view_errors.php

<?php
require_once __DIR__ . '/../connect.php';

// استلام 'status' كمتغير اختياري لتصفية النتائج
// مثلاً: view_errors.php?status=new  سيجلب الأخطاء الجديدة فقط
$status = filterRequest("status");

// إذا تم تحديد status، قم بتصفية النتائج بناءً عليه
if (!empty($status)) {
    $stmt = $con->prepare("SELECT * FROM `error` WHERE `status` = ? ORDER BY `created_at` DESC");
    $stmt->execute(array($status));
} else {
    // إذا لم يتم تحديد status، قم بجلب جميع الأخطاء
    $stmt = $con->prepare("SELECT * FROM `error` ORDER BY `created_at` DESC");
    $stmt->execute();
}

// جلب جميع النتائج
$errors = $stmt->fetchAll(PDO::FETCH_ASSOC);

$count = $stmt->rowCount();

if ($count > 0) {
    // إرجاع البيانات كـ JSON مع رسالة نجاح
    echo json_encode(array("status" => "success", "data" => $errors));
} else {
    // في حال عدم وجود أخطاء، إرجاع رسالة نجاح مع بيانات فارغة
    echo json_encode(array("status" => "success", "data" => []));
}

?>

File: Admin/getPassengerbyEmail.php

<?php
require_once __DIR__ . '/../connect.php';

$passengerEmail = $encryptionHelper->encryptData(filterRequest("passengerEmail"));
$passengerId = filterRequest("passengerId");
$passengerphone = $encryptionHelper->encryptData(filterRequest("passengerphone"));

$sql = "SELECT
    `passengers`.`id`,
    `passengers`.`phone`,
    `passengers`.`email`,
    `passengers`.`gender`,
    `passengers`.`status`,
    `passengers`.`birthdate`,
    `passengers`.`site`,
    `passengers`.`first_name`,
    `passengers`.`last_name`,
    `passengers`.`sosPhone`,
    `passengers`.`education`,
    `passengers`.`employmentType`,
    `passengers`.`maritalStatus`,
    `passengers`.`created_at`,
    `passengers`.`updated_at`,
    (
        SELECT COUNT(`id`) FROM `passengers`
    ) AS countPassenger,
    (
        SELECT COUNT(`id`) FROM `feedBack`
    ) AS countFeedback,
    (
        SELECT CAST(AVG(`rating`) AS DECIMAL(10, 2)) FROM `ratingPassenger`
        WHERE `passenger_id` = `passengers`.`id`
    ) AS ratingPassenger,
    (
        SELECT COUNT(`driverID`) FROM `ratingPassenger`
        WHERE `passenger_id` = `passengers`.`id`
    ) AS countDriverRate,
    (
        SELECT COUNT(`passengerID`) FROM `canecl`
        WHERE `passengerID` = `passengers`.`id`
    ) AS countPassengerCancel,
    (
        SELECT CAST(AVG(`rating`) AS DECIMAL(10, 2)) FROM `ratingDriver`
        WHERE `passenger_iD` = `passengers`.`id`
    ) AS passengerAverageRating,
    (
        SELECT COUNT(`driver_id`) FROM `ratingDriver`
        WHERE `passenger_id` = `passengers`.`id`
    ) AS countPassengerRate,
    (
        SELECT COUNT(`passenger_id`) FROM `ride`
        WHERE `passenger_id` = `passengers`.`id`
    ) AS countPassengerRide,
    (
        SELECT `token` FROM `tokens`
        WHERE `passengerID` = `passengers`.`id`
    ) AS passengerToken
FROM
    `passengers`
WHERE
    passengers.email = :email OR passengers.phone = :phone OR passengers.id = :id
";

$stmt = $con->prepare($sql);
$stmt->bindParam(":email", $passengerEmail);
$stmt->bindParam(":phone", $passengerphone);
$stmt->bindParam(":id", $passengerId);
$stmt->execute();
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);

// فك التشفير للحقول الحساسة
foreach ($result as &$row) {
    $fieldsToDecrypt = [
        "phone", "email", "gender", "birthdate", "site",
        "first_name", "last_name", "sosPhone",
        "education", "employmentType", "maritalStatus"
    ];

    foreach ($fieldsToDecrypt as $field) {
        if (isset($row[$field])) {
            $row[$field] = $encryptionHelper->decryptData($row[$field]);
        }
    }
}

if ($stmt->rowCount() > 0) {
    jsonSuccess($data = $result);
} else {
    jsonError("No records found");
}
?>

File: Admin/errorApp.php

<?php
require_once __DIR__ . '/../connect.php';

// استلام البيانات من الطلب
$error = filterRequest("error");
$userId = filterRequest("userId");
$userType = filterRequest("userType");
$phone = filterRequest("phone");
$device = filterRequest("device");
$details = filterRequest("details"); // <--  الحقل الجديد الذي أضفناه

// جملة SQL لإدخال البيانات، مع إضافة الحقل الجديد
// لاحظ أننا لا نرسل حقل 'status' لأنه سيأخذ القيمة الافتراضية 'new' تلقائياً في قاعدة البيانات
$sql = "INSERT INTO `error` (`error`, `userId`, `userType`, `phone`, `device`, `details`) 
        VALUES (:error, :userId, :userType, :phone, :device, :details)";

$stmt = $con->prepare($sql);

// ربط المتغيرات بالقيم
$stmt->bindParam(':error', $error);
$stmt->bindParam(':userId', $userId);
$stmt->bindParam(':userType', $userType);
$stmt->bindParam(':phone', $phone);
$stmt->bindParam(':device', $device);
$stmt->bindParam(':details', $details); // <-- ربط المتغير الجديد

$stmt->execute();

if ($stmt->rowCount() > 0) {
    // طباعة رسالة نجاح
    jsonSuccess($message = "Error data saved successfully");
} else {
    // طباعة رسالة فشل
    jsonError($message = "Failed to save error data");
}
?>

File: Admin/getVisaForEachDriver.php

<?php
require_once __DIR__ . '/../connect.php';

// جلب البيانات
$sql = "SELECT
    COUNT(DISTINCT driverID) AS driver_count,
    `payments`.driverID,
    COALESCE(SUM(amount), 0) AS total_amount,
    `driver`.`phone`,
    `driver`.`name_arabic`,
    `driver`.`accountBank`,
    `driver`.`bankCode`,
    `driver`.`email`
FROM
    payments
LEFT JOIN `driver` ON `driver`.`id` = payments.driverID
WHERE
    isGiven = 'waiting' AND payment_method IN(
        'visa-in', 'visa', 'visaRide', 'TransferFrom',
        'payout', 'TransferTo', 'payFromSeferToDriver'
    )
    AND WEEK(`payments`.created_at) = WEEK(CURRENT_DATE)
GROUP BY
    driverID
HAVING
    COALESCE(SUM(amount), 0) > 0 AND total_amount > 100
LIMIT 0, 25";

$stmt = $con->prepare($sql);
$stmt->execute();
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);

// فك التشفير للحقول المطلوبة
foreach ($result as &$row) {
    $fieldsToDecrypt = ['phone', 'email', 'accountBank', 'bankCode', 'name_arabic'];
    foreach ($fieldsToDecrypt as $field) {
        if (isset($row[$field]) && $row[$field] !== null) {
            $row[$field] = $encryptionHelper->decryptData($row[$field]);
        }
    }
}

if ($stmt->rowCount() > 0) {
    jsonSuccess($result);
} else {
    jsonError("No wallet record found");
}
?>

File: Admin/ggg.php

<?php
// ============================================================
// Admin/ggg.php
// أداة تشفير وفك تشفير للمشرفين
// ============================================================

require_once __DIR__ . '/../core/bootstrap.php';

// نضمن أن الرد دائماً JSON
header('Content-Type: application/json; charset=utf-8');

// 1) قراءة الـ body كـ JSON أو POST
$action = filterRequest('action');
$text   = filterRequest('text');
$adminPhoneParam = filterRequest('admin_phone');

// 2) التحقق من رقم هاتف الأدمن المصرّح له
$phonesRaw = getenv('ADMIN_PHONE_NUMBERS') ?: '';
$ALLOWED_TOOL_PHONES = array_values(
    array_filter(
        array_map(function ($p) {
            return preg_replace('/\D+/', '', $p);
        }, explode(',', $phonesRaw))
    )
);

$adminPhoneParam = $adminPhoneParam ? preg_replace('/\D+/', '', $adminPhoneParam) : '';

if ($adminPhoneParam === '' || !in_array($adminPhoneParam, $ALLOWED_TOOL_PHONES, true)) {
    securityLog("Unauthorized encrypt/decrypt attempt", ['phone' => $adminPhoneParam]);
    jsonError('Access denied for this admin phone.', 403);
}

if (empty($text) || ($action !== 'encrypt' && $action !== 'decrypt')) {
    jsonError('Invalid input: need action=encrypt|decrypt and non-empty text.', 400);
}

// 4) تنفيذ التشفير / الفك (التوافق مع CBC الحالي)
try {
    if ($action === 'encrypt') {
        $result = $encryptionHelper->encryptData($text);
    } else { // decrypt
        $result = $encryptionHelper->decryptData($text);
    }

    jsonSuccess([
        'action' => $action,
        'result' => (string) $result,
    ]);
} catch (Exception $e) {
    securityLog("Encryption tool failed", ['error' => $e->getMessage()]);
    jsonError('Operation failed.', 500);
}

File: Admin/facebook.php

<?php
require_once 'vendor/autoload.php'; // Include the Composer autoloader

use Facebook\Facebook;

$appId = '$appId';            // Replace with your App ID
$appSecret = '$appSecret';    // Replace with your App Secret
$accessToken = '$accessToken'; // Replace with the token you want to debug

$fb = new Facebook([
    'app_id' => $appId,
    'app_secret' => $appSecret,
    'default_graph_version' => 'v16.0', // Adjust based on your API version
]);

try {
    // Generate the app token
    $appToken = $appId . '|' . $appSecret;

    // Debug the token
    $response = $fb->get('/debug_token?input_token=' . $accessToken, $appToken);
    $tokenData = $response->getDecodedBody();

    // Display the token details
    echo "Token Data:\n";
    print_r($tokenData);

    if (isset($tokenData['data']['expires_at'])) {
        echo "Expires At: " . date('Y-m-d H:i:s', $tokenData['data']['expires_at']) . "\n";
    } else {
        echo "The token does not have an expiration time.\n";
    }
} catch (Facebook\Exceptions\FacebookResponseException $e) {
    echo 'Graph API Error: ' . $e->getMessage();
} catch (Facebook\Exceptions\FacebookSDKException $e) {
    echo 'SDK Error: ' . $e->getMessage();
}

File: Admin/dashbord.php

<?php
require_once __DIR__ . '/../connect.php';

$sql = "
SELECT
    -- العدادات العامة
    (SELECT COUNT(*) FROM passengers) AS countPassengers,
    (SELECT COUNT(*) FROM driver) AS countDriver,
    (SELECT COUNT(*) FROM ride) AS countRide,

    -- إحصائيات الشهر الحالي
    (SELECT COUNT(*) FROM passengers WHERE created_at BETWEEN DATE_FORMAT(CURDATE(), '%Y-%m-01') AND LAST_DAY(CURDATE())) AS countPassengersThisMonth,
    (SELECT COUNT(*) FROM driver WHERE created_at BETWEEN DATE_FORMAT(CURDATE(), '%Y-%m-01') AND LAST_DAY(CURDATE())) AS countDriverThisMonth,
    (SELECT COUNT(*) FROM ride WHERE created_at BETWEEN DATE_FORMAT(CURDATE(), '%Y-%m-01') AND LAST_DAY(CURDATE())) AS countRideThisMonth,
    (SELECT COUNT(*) FROM CarRegistration WHERE created_at BETWEEN DATE_FORMAT(CURDATE(), '%Y-%m-01') AND LAST_DAY(CURDATE())) AS countCarRegistrationThisMonth,

    -- شكاوى
    (SELECT COUNT(*) FROM complaint WHERE date_filed BETWEEN DATE_FORMAT(CURDATE(), '%Y-%m-01') AND LAST_DAY(CURDATE())) AS countComplaintThisMonth,
    (SELECT COUNT(*) FROM complaint WHERE date_filed BETWEEN DATE_SUB(CURDATE(), INTERVAL WEEKDAY(CURDATE()) DAY) AND DATE_ADD(DATE_SUB(CURDATE(), INTERVAL WEEKDAY(CURDATE()) DAY), INTERVAL 6 DAY)) AS countComplaintThisWeek,
    (SELECT COUNT(*) FROM complaint WHERE DATE(date_filed) = CURDATE()) AS countComplaintToday,

    -- المحافظ والتحويلات
   
    -- إحصائيات وقت ومسافة الرحلات
    (SELECT TIME_FORMAT(SEC_TO_TIME(AVG(TIMESTAMPDIFF(SECOND, rideTimeStart, rideTimeFinish))), '%Hh %im') FROM ride WHERE rideTimeStart IS NOT NULL AND rideTimeFinish IS NOT NULL) AS driver_avg_duration,
    (SELECT MAX(SEC_TO_TIME(TIMESTAMPDIFF(SECOND, rideTimeStart, rideTimeFinish))) FROM ride WHERE rideTimeStart IS NOT NULL AND rideTimeFinish IS NOT NULL) AS longest_duration,
    (SELECT ROUND(SUM(distance),2) FROM ride) AS total_distance,
    (SELECT ROUND(AVG(distance),2) FROM ride) AS average_distance,
    (SELECT ROUND(MAX(distance),2) FROM ride) AS longest_distance,

    -- أرباح السائق والشركة
    (SELECT SUM(price_for_driver) FROM ride WHERE status = 'Finished') AS total_driver_earnings,
    (SELECT ROUND(AVG(price_for_passenger),2) FROM ride) AS avg_passenger_price,

    -- توزيع الرحلات حسب الوقت
    (SELECT COUNT(*) FROM ride WHERE HOUR(created_at) BETWEEN 6 AND 11) AS morning_ride_count,
    (SELECT COUNT(*) FROM ride WHERE HOUR(created_at) BETWEEN 12 AND 17) AS evening_ride_count,
    (SELECT COUNT(*) FROM ride WHERE HOUR(created_at) BETWEEN 18 AND 23 OR HOUR(created_at) BETWEEN 0 AND 5) AS night_ride_count,

    -- أنواع الرحلات
    (SELECT COUNT(*) FROM ride WHERE carType = 'Comfort') AS comfort,
    (SELECT COUNT(*) FROM ride WHERE carType = 'Speed') AS speed,
    (SELECT COUNT(*) FROM ride WHERE carType = 'Lady') AS lady,

    -- حالة الرحلات
    (SELECT COUNT(*) FROM ride WHERE status = 'wait') AS ongoing_rides,
    (SELECT COUNT(*) FROM ride WHERE status = 'Finished') AS completed_rides,
    (SELECT COUNT(*) FROM ride WHERE status = 'cancel') AS cancelled_rides,

    -- عدد السائقين الفريدين
    (SELECT COUNT(*) FROM (SELECT driver_id FROM ride GROUP BY driver_id) AS sub) AS num_Driver,

    -- التحويلات البنكية
    (SELECT COUNT(*) FROM payments WHERE payment_method = 'TransferFrom') AS transfer_from_count

FROM passengers
LIMIT 1;
";

$stmt = $con->prepare($sql);
$stmt->execute();
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);

if ($result) {
    jsonSuccess($result);
} else {
    jsonError("No dashboard data found");
}
?>

File: Admin/getPassengerDetailsByPassengerID.php

<?php
require_once __DIR__ . '/../connect.php';

$passengerID = filterRequest("passengerID");

$sql = "SELECT
    `passengers`.`id`,
    `passengers`.`phone`,
    `passengers`.`email`,
    `passengers`.`gender`,
    `passengers`.`status`,
    `passengers`.`birthdate`,
    `passengers`.`site`,
    `passengers`.`first_name`,
    `passengers`.`last_name`,
    `passengers`.`sosPhone`,
    `passengers`.`education`,
    `passengers`.`employmentType`,
    `passengers`.`maritalStatus`,
    `passengers`.`created_at`,
    `passengers`.`updated_at`,
    (
        SELECT COUNT(`id`) FROM `passengers`
    ) AS countPassenger,
    (
        SELECT COUNT(`id`) FROM `feedBack`
    ) AS countFeedback,
    (
        SELECT CAST(AVG(`rating`) AS DECIMAL(10,2))
        FROM `ratingPassenger`
        WHERE `passenger_id` = `passengers`.`id`
    ) AS ratingPassenger,
    (
        SELECT COUNT(`driverID`)
        FROM `ratingPassenger`
        WHERE `passenger_id` = `passengers`.`id`
    ) AS countDriverRate,
    (
        SELECT COUNT(`passengerID`)
        FROM `canecl`
        WHERE `passengerID` = `passengers`.`id`
    ) AS countPassengerCancel,
    (
        SELECT CAST(AVG(`rating`) AS DECIMAL(10,2))
        FROM `ratingDriver`
        WHERE `passenger_iD` = `passengers`.`id`
    ) AS passengerAverageRating,
    (
        SELECT COUNT(`driver_id`)
        FROM `ratingDriver`
        WHERE `passenger_id` = `passengers`.`id`
    ) AS countPassengerRate,
    (
        SELECT COUNT(`ride`.`passenger_id`)
        FROM `ride`
        WHERE `ride`.`passenger_id` = `passengers`.`id`
    ) AS countPassengerRide,
    (
        SELECT `token`
        FROM `tokens`
        WHERE `tokens`.`passengerID` = `passengers`.`id`
    ) AS passengerToken
FROM
    `passengers`
WHERE
    passengers.id = '$passengerID'
GROUP BY
    `passengers`.`id`
ORDER BY
    countPassengerRide DESC";

$stmt = $con->prepare($sql);
$stmt->execute();
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);

// ✅ فك تشفير الحقول الحساسة
foreach ($result as &$row) {
    $fieldsToDecrypt = [
        "phone", "email", "gender", "birthdate", "site",
        "first_name", "last_name", "sosPhone",
        "education", "employmentType", "maritalStatus", "passengerToken"
    ];

    foreach ($fieldsToDecrypt as $field) {
        if (isset($row[$field]) && $row[$field] !== null) {
            $row[$field] = $encryptionHelper->decryptData($row[$field]);
        }
    }
}

if ($stmt->rowCount() > 0) {
    jsonSuccess($result);
} else {
    jsonError("No records found");
}
?>

File: Admin/rides/get_driver_live_pos.php

<?php
// =================================================================
// ملف: get_driver_live_pos.php
// الوظيفة: جلب الموقع اللحظي لسائق محدد (بناءً على ID)
// =================================================================

require_once __DIR__ . '/../../connect.php'; // تأكد أن هذا الملف يحتوي على $con_tracking

header("Access-Control-Allow-Origin: *");
header("Content-Type: application/json; charset=UTF-8");

try {
    // 1. استقبال معرف السائق
    $driver_id = filterRequest("driver_id");

    if (!$driver_id) {
        jsonError("driver_id is required");
        exit;
    }

    // 2. الاستعلام من قاعدة بيانات التتبع (car_locations)
    // نجلب أحدث إحداثيات تم تسجيلها لهذا السائق
    $sql = "
        SELECT 
            latitude, 
            longitude, 
            heading, 
            speed, 
            updated_at 
        FROM car_locations 
        WHERE driver_id = ? 
        ORDER BY updated_at DESC 
        LIMIT 1
    ";

    $stmt = $con_tracking->prepare($sql);
    $stmt->execute([$driver_id]);
    $data = $stmt->fetch(PDO::FETCH_ASSOC);

    if ($data) {
        jsonSuccess($data);
    } else {
        // السائق ليس له موقع مسجل (ربما لم يشغل التطبيق بعد)
        jsonError("No location found for this driver");
    }

} catch (PDOException $e) {
    jsonError("Database Error: " . $e->getMessage());
}
?>

File: Admin/rides/admin_get_rides_by_phone.php

<?php
require_once __DIR__ . '/../../connect.php';

$phone = filterRequest('phone');
if (!$phone) {
    error_log("[get_last_ride] Missing phone parameter");
    jsonError("Phone is required");
    exit;
}

$raw = $phone;

// شَفِّر قبل الاستعلام
$enc_raw = $encryptionHelper->encryptData($raw);

try {
    error_log("[get_last_ride] Searching passenger with phone=$raw");

    // 1) ابحث عن الراكب بالهاتف المشفّر
    $selP = $con->prepare("
        SELECT id, first_name, last_name, phone
        FROM passengers
        WHERE phone =:enc_raw
        LIMIT 1
    ");
    $selP->execute(['enc_raw' => $enc_raw]);
    $passenger = $selP->fetch(PDO::FETCH_ASSOC);

    if (!$passenger) {
        error_log("[get_last_ride] Passenger not found (phone=$raw)");
        jsonError('Passenger not found for provided phone');
        exit;
    }

    error_log("[get_last_ride] Passenger found id=" . $passenger['id']);

    // 2) آخر رحلة لهذا الراكب
    $rideStmt = $con->prepare("
        SELECT
            r.id,
            r.start_location,
            r.end_location,
            r.date,
            r.time,
            r.endtime,
            r.status,
            r.paymentMethod,
            r.carType,
            r.price,
            r.price_for_driver,
            r.price_for_passenger,
            r.distance,
            r.driver_id,
            r.passenger_id,
            r.created_at,
            r.updated_at,
            r.DriverIsGoingToPassenger,
            r.rideTimeStart,
            r.rideTimeFinish,
            d.first_name AS driver_first_name,
            d.last_name  AS driver_last_name
        FROM ride r
        LEFT JOIN driver d ON d.id = r.driver_id
        WHERE r.passenger_id = :pid
        ORDER BY r.created_at DESC, r.id DESC
        LIMIT 1
    ");
    $rideStmt->execute(['pid' => $passenger['id']]);
    $ride = $rideStmt->fetch(PDO::FETCH_ASSOC);

    if (!$ride) {
        error_log("[get_last_ride] No rides found for passenger_id=" . $passenger['id']);
        jsonError('No rides found for this passenger');
        exit;
    }

    error_log("[get_last_ride] Found ride id=" . $ride['id'] . " for passenger_id=" . $passenger['id']);

    // فك التشفير
    $passenger['first_name'] = $encryptionHelper->decryptData($passenger['first_name']);
    $passenger['last_name']  = $encryptionHelper->decryptData($passenger['last_name']);
    $passenger['phone']      = $encryptionHelper->decryptData($passenger['phone']);
    $ride['driver_first_name'] = $encryptionHelper->decryptData($ride['driver_first_name']);
    $ride['driver_last_name']  = $encryptionHelper->decryptData($ride['driver_last_name']);

    // 3) اطبع النتيجة
    $response = [
        'passenger' => [
            'id'         => $passenger['id'],
            'first_name' => $passenger['first_name'],
            'last_name'  => $passenger['last_name'],
            'phone'      => $passenger['phone'],
        ],
        'ride' => $ride
    ];

    error_log("[get_last_ride] Success response for passenger_id=" . $passenger['id']);
    jsonSuccess($response);

} catch (Throwable $e) {
    error_log("[get_last_ride] Exception: " . $e->getMessage());
    jsonError("Error: " . $e->getMessage());
}

File: Admin/rides/get_rides_by_status.php

<?php
require_once __DIR__ . '/../../connect.php';

header("Access-Control-Allow-Origin: *");
header('Content-Type: application/json; charset=utf-8');

try {
    $statusFilter = filterRequest("status"); 
    // القيم المتوقعة من التطبيق: 'All', 'Begin', 'New', 'Completed', 'Canceled'
    if (!$statusFilter) $statusFilter = "Begin";

    $params = [];
    $whereClause = "";

    // --- منطق ترجمة الحالات (Mapping Logic) ---
    switch ($statusFilter) {
        case 'All':
            $whereClause = ""; // لا يوجد شرط، اجلب الكل
            break;
            
        case 'Begin':
            // قد تكون الرحلة بدأت أو وصل السائق
            $whereClause = "WHERE r.status IN ('Begin','Apply','Applied')";
            break;

        case 'New':
            $whereClause = "WHERE r.status = 'New'";
            break;

        case 'Completed':
            // في قاعدة البيانات الحالة اسمها Finished
            $whereClause = "WHERE r.status = 'Finished'";
            break;

        case 'Canceled':
            // نجمع كل حالات الإلغاء الممكنة
            $whereClause = "WHERE r.status IN ('Cancel', 'CancelFromDriverAfterApply', 'TimeOut')";
            break;
            
        default:
            // في حال تم إرسال حالة محددة غير المذكورين
            $whereClause = "WHERE r.status = ?";
            $params[] = $statusFilter;
            break;
    }

    // --- الاستعلام ---
    $sql = "
        SELECT 
            r.*,
            -- بيانات السائق
            d.first_name as d_fname, d.last_name as d_lname, d.phone as d_phone, d.id as driver_real_id,
            -- إحصائيات السائق (نحسب المكتمل والملغي بشكل أدق)
            (SELECT COUNT(*) FROM ride WHERE driver_id = d.id AND status = 'Finished') as d_completed,
            (SELECT COUNT(*) FROM ride WHERE driver_id = d.id AND status LIKE 'Cancel%') as d_canceled,
            
            -- بيانات الراكب
            p.first_name as p_fname, p.last_name as p_lname, p.phone as p_phone,
            -- إحصائيات الراكب
            (SELECT COUNT(*) FROM ride WHERE passenger_id = p.id AND status = 'Finished') as p_completed,

            -- سبب الإلغاء
            -- نحاول جلبه من جدول driver_orders (ملاحظات السائق)
            -- نستخدم COALESCE لجلب 'لا يوجد سبب' إذا كانت القيمة فارغة
            COALESCE(
                (SELECT notes FROM driver_orders WHERE order_id = r.id LIMIT 1),
                'لا يوجد سبب مسجل'
            ) as cancel_reason

        FROM ride r
        LEFT JOIN driver d ON r.driver_id = d.id
        LEFT JOIN passengers p ON r.passenger_id = p.id
        $whereClause
        ORDER BY r.id DESC
        LIMIT 100
    ";

    $stmt = $con->prepare($sql);
    $stmt->execute($params);
    $rides = $stmt->fetchAll(PDO::FETCH_ASSOC);

    $data = [];

    foreach ($rides as $row) {
        // فك التشفير
        try { $row['d_fname'] = $encryptionHelper->decryptData($row['d_fname']); } catch(Exception $e){}
        try { $row['d_lname'] = $encryptionHelper->decryptData($row['d_lname']); } catch(Exception $e){}
        try { $row['d_phone'] = $encryptionHelper->decryptData($row['d_phone']); } catch(Exception $e){}
        
        try { $row['p_fname'] = $encryptionHelper->decryptData($row['p_fname']); } catch(Exception $e){}
        try { $row['p_lname'] = $encryptionHelper->decryptData($row['p_lname']); } catch(Exception $e){}
        try { $row['p_phone'] = $encryptionHelper->decryptData($row['p_phone']); } catch(Exception $e){}

        $row['driver_full_name'] = trim($row['d_fname'] . ' ' . $row['d_lname']);
        $row['passenger_full_name'] = trim($row['p_fname'] . ' ' . $row['p_lname']);
        
        if(empty($row['driver_full_name'])) $row['driver_full_name'] = "Unknown Driver";
        if(empty($row['passenger_full_name'])) $row['passenger_full_name'] = "Unknown Passenger";

        $data[] = $row;
    }

    jsonSuccess($data);

} catch (PDOException $e) {
    jsonError("Database Error: " . $e->getMessage());
}
?>

File: Admin/rides/monitorRide.php

<?php
require_once __DIR__ . '/../../connect.php';

// 1. Log the start of the request
$phone = filterRequest("phone");
error_log("[MONITOR_RIDE] ---------------- START REQUEST ----------------");
error_log("[MONITOR_RIDE] 1. Received Phone: " . $phone);

//------------------------------------------------------------------------
// 1) البحث عن الهاتف أولاً في جدول السائق ثم جدول الراكب
//------------------------------------------------------------------------

$encPhone = $encryptionHelper->encryptData($phone);
error_log("[MONITOR_RIDE] 2. Encrypted Phone: " . $encPhone);

// Check Driver Table
$driverQuery = $con->prepare("SELECT id AS driverID FROM driver WHERE phone = :phone LIMIT 1");
$driverQuery->execute([':phone' => $encPhone]);
$driver = $driverQuery->fetch(PDO::FETCH_ASSOC);

// Check Passenger Table
$customerQuery = $con->prepare("SELECT id AS customerID FROM passengers WHERE phone = :phone LIMIT 1");
$customerQuery->execute([':phone' => $encPhone]);
$customer = $customerQuery->fetch(PDO::FETCH_ASSOC);


// حدد نوع المستخدم
$userType = '';
$driverID = null;
$customerID = null;

if ($driver) {
    $userType = 'driver';
    $driverID = $driver['driverID'];
    error_log("[MONITOR_RIDE] 3. User Found: Type = DRIVER, ID = " . $driverID);
} elseif ($customer) {
    $userType = 'customer';
    $customerID = $customer['customerID'];
    error_log("[MONITOR_RIDE] 3. User Found: Type = CUSTOMER, ID = " . $customerID);
} else {
    error_log("[MONITOR_RIDE] 3. FAILURE: Phone number not found in Driver or Passenger tables.");
    jsonError("رقم الهاتف غير موجود في النظام.");
    exit;
}

//------------------------------------------------------------------------
// 2) جلب آخر رحلة حالتها "بدأت" بناءً على نوع المستخدم
//------------------------------------------------------------------------

if ($userType == 'driver') {
    error_log("[MONITOR_RIDE] 4. Searching for active ride for Driver ID: " . $driverID);
    $rideQuery = $con->prepare("
        SELECT * FROM ride
        WHERE driver_id = :driverID AND status = 'Begin'
        ORDER BY id DESC LIMIT 1
    ");
    $rideQuery->execute([':driverID' => $driverID]);
} else {
    error_log("[MONITOR_RIDE] 4. Searching for active ride for Customer ID: " . $customerID);
    $rideQuery = $con->prepare("
        SELECT * FROM ride
        WHERE passenger_id = :customerID AND status = 'Begin'
        ORDER BY id DESC LIMIT 1
    ");
    $rideQuery->execute([':customerID' => $customerID]);
}

$ride = $rideQuery->fetch(PDO::FETCH_ASSOC);

if (!$ride) {
    error_log("[MONITOR_RIDE] 4. FAILURE: No ride with status 'Begin' found.");
    jsonError("لا توجد رحلة بدأت لهذا المستخدم.");
    exit;
} else {
    error_log("[MONITOR_RIDE] 4. SUCCESS: Active Ride Found. Ride ID: " . $ride['id']);
}

//------------------------------------------------------------------------
// 3) جلب معلومات السائق من الرحلة
//------------------------------------------------------------------------

// FIX 1: Safe assignment of driver ID (checking driverID vs driver_id)
$rideDriverID = $ride['driverID'] ?? $ride['driver_id'];

error_log("[MONITOR_RIDE] 5. Fetching info for Driver ID from Ride: " . $rideDriverID);

// FIX 2: Select first_name and last_name instead of fullname
$driverInfoQuery = $con->prepare("
    SELECT id, first_name, last_name, phone
    FROM driver 
    WHERE id = :driverID
    LIMIT 1
");

$driverInfoQuery->execute([':driverID' => $rideDriverID]);
$driverInfo = $driverInfoQuery->fetch(PDO::FETCH_ASSOC);

if ($driverInfo) {
    // فك التشفير للهاتف
    $driverInfo['phone'] = $encryptionHelper->decryptData($driverInfo['phone']);
    
    // FIX 4: Decrypt First Name and Last Name
    $driverInfo['first_name'] = $encryptionHelper->decryptData($driverInfo['first_name']);
    $driverInfo['last_name']  = $encryptionHelper->decryptData($driverInfo['last_name']);

    // Construct fullname for the response
    $fullName = $driverInfo['first_name'] . " " . $driverInfo['last_name'];
    $driverInfo['fullname'] = $fullName;

    error_log("[MONITOR_RIDE] 5. Driver Info Found: " . $fullName);
} else {
    error_log("[MONITOR_RIDE] 5. WARNING: Driver info not found for ID " . $rideDriverID);
}

//------------------------------------------------------------------------
// 4) جلب آخر موقع للسائق من جدول driver_location بشرط الحالة ON
//------------------------------------------------------------------------

error_log("[MONITOR_RIDE] 6. Querying Tracking DB for Driver ID: " . $rideDriverID);

// FIX 3: Changed ORDER BY id DESC to ORDER BY updated_at DESC
$locationQuery = $con_tracking->prepare("
    SELECT latitude, longitude, speed, heading, updated_at 
    FROM car_locations
    WHERE driver_id = :driverID AND status = 'ON'
    ORDER BY updated_at DESC LIMIT 1
");
$locationQuery->execute([':driverID' => $rideDriverID]);
$location = $locationQuery->fetch(PDO::FETCH_ASSOC);

if ($location) {
    error_log("[MONITOR_RIDE] 6. Location Found: Lat=" . $location['latitude'] . " Lng=" . $location['longitude'] . " Updated=" . $location['updated_at']);
} else {
    error_log("[MONITOR_RIDE] 6. WARNING: No live location found (status=ON) or list empty.");
}

//------------------------------------------------------------------------
// 5) تجهيز البيانات للرد
//------------------------------------------------------------------------

$response = [
    "ride_details"    => $ride,
    "driver_details" => $driverInfo,
    "driver_location" => $location ?: "No live location"
];

error_log("[MONITOR_RIDE] 7. Sending Success Response.");
jsonSuccess($response);

?>

File: Admin/rides/admin_update_ride_status.php

<?php
require_once __DIR__ . '/../../connect.php';



$rideId = filterRequest('id');
$status = filterRequest('status');
$reason = filterRequest('reason'); // اختياري

if (empty($rideId) || empty($status)) {
    jsonError("id and status are required");
    exit;
}

/* whitelist للحالات المسموحة  عدّل حسب نظامك */
$allowed = [
    'Pending', 'Accepted', 'EnRoute', 'Arrived',
    'Started', 'Completed', 'Canceled'
];

if (!in_array($status, $allowed, true)) {
    jsonError("Invalid status");
    exit;
}

try {
    $con->beginTransaction();

    // إن أردت ختم وقت النهاية تلقائيًا عند الإكمال
    if ($status === 'Completed') {
        $sql = "UPDATE ride 
                   SET status = :st, rideTimeFinish = IFNULL(rideTimeFinish, NOW()), updated_at = CURRENT_TIMESTAMP
                 WHERE id = :id";
    } else {
        $sql = "UPDATE ride 
                   SET status = :st, updated_at = CURRENT_TIMESTAMP
                 WHERE id = :id";
    }

    $stmt = $con->prepare($sql);
    $ok = $stmt->execute(['st' => $status, 'id' => $rideId]);

    if (!$ok || $stmt->rowCount() === 0) {
        $con->rollBack();
        jsonError("Ride not found or no change");
        exit;
    }

    // أعِدّ بيانات الرحلة المحدّثة (للتحديث الفوري في الواجهة)
    $fetch = $con->prepare("
        SELECT
            r.id,
            r.start_location,
            r.end_location,
            r.date,
            r.time,
            r.endtime,
            r.status,
            r.paymentMethod,
            r.carType,
            r.price,
            r.price_for_driver,
            r.price_for_passenger,
            r.distance,
            r.driver_id,
            r.passenger_id,
            r.created_at,
            r.updated_at,
            r.DriverIsGoingToPassenger,
            r.rideTimeStart,
            r.rideTimeFinish,
            d.first_name AS driver_first_name,
            d.last_name  AS driver_last_name
        FROM ride r
        LEFT JOIN driver d ON d.id = r.driver_id
        WHERE r.id = :id
        LIMIT 1
    ");
    $fetch->execute(['id' => $rideId]);
    $ride = $fetch->fetch(PDO::FETCH_ASSOC);

    $con->commit();
    jsonSuccess(['ride' => $ride, 'message' => 'Status updated']);
} catch (Throwable $e) {
    if ($con->inTransaction()) $con->rollBack();
    jsonError("Error: ".$e->getMessage());
}

File: Admin/AdminCaptain/add.php


File: Admin/AdminCaptain/update.php


File: Admin/AdminCaptain/get.php

<?php
require_once __DIR__ . '/../../connect.php';

$sql = "SELECT
    `driver`.`id`,
    `driver`.`phone`,
    `driver`.`email`,
    `driver`.`gender`,
    `driver`.`status`,
    `driver`.`birthdate`,
    `driver`.`site`,
    `driver`.`first_name`,
    `driver`.`last_name`,
    `driver`.`employmentType`,
    `driver`.`maritalStatus`,
    `driver`.`created_at`,
    `driver`.`updated_at`,
    (
        SELECT COUNT(`driver`.`id`) FROM `driver`
    ) AS countPassenger,
    (
        SELECT CAST(AVG(`rating`) AS DECIMAL(10, 2))
        FROM `ratingPassenger`
        WHERE `ratingPassenger`.`driverID` = `driver`.`id`
    ) AS ratingPassenger,
    (
        SELECT COUNT(*) FROM `ratingPassenger` WHERE `driverID` = `driver`.`id`
    ) AS countDriverRate,
    (
        SELECT COUNT(*) FROM `canecl` WHERE `driverID` = `driver`.`id`
    ) AS countPassengerCancel,
    (
        SELECT CAST(AVG(`rating`) AS DECIMAL(10, 2))
        FROM `ratingDriver`
        WHERE `driver_id` = `driver`.`id`
    ) AS passengerAverageRating,
    (
        SELECT COUNT(*) FROM `ratingDriver` WHERE `driver_id` = `driver`.`id`
    ) AS countPassengerRate,
    (
        SELECT COUNT(*) FROM `ride` WHERE `driver_id` = `driver`.`id`
    ) AS countPassengerRide,
    (
        SELECT `token`
        FROM `driverToken`
        WHERE `captain_id` = `driver`.`id`
        LIMIT 1
    ) AS passengerToken
FROM `driver`
ORDER BY passengerAverageRating DESC
LIMIT 10";

$stmt = $con->prepare($sql);
$stmt->execute();
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);

// فك تشفير الحقول الحساسة
foreach ($result as &$row) {
    $row['phone'] = $encryptionHelper->decryptData($row['phone']);
    $row['email'] = $encryptionHelper->decryptData($row['email']);
    $row['gender'] = $encryptionHelper->decryptData($row['gender']);
    $row['birthdate'] = $encryptionHelper->decryptData($row['birthdate']);
    $row['site'] = $encryptionHelper->decryptData($row['site']);
    $row['first_name'] = $encryptionHelper->decryptData($row['first_name']);
    $row['last_name'] = $encryptionHelper->decryptData($row['last_name']);
    $row['employmentType'] = $encryptionHelper->decryptData($row['employmentType']);
    $row['maritalStatus'] = $encryptionHelper->decryptData($row['maritalStatus']);
}

if (count($result) > 0) {
    jsonSuccess($result);
} else {
    jsonError("No records found");
}
?>

File: Admin/AdminCaptain/getCaptainDetailsByEmailOrIDOrPhone.php

<?php
require_once __DIR__ . '/../../connect.php';

$driver_id = filterRequest("driver_id");
$driverEmail = $encryptionHelper->encryptData(filterRequest("driverEmail"));
$driverPhone = $encryptionHelper->encryptData(filterRequest("driverPhone"));

$sql = "SELECT
    `driver`.`id`,
    `driver`.`phone`,
    `driver`.`email`,
    `driver`.`gender`,
    `driver`.`status`,
    `driver`.`birthdate`,
    `driver`.`site`,
    `driver`.`first_name`,
    `driver`.`last_name`,
    `driver`.`education`,
    `driver`.`employmentType`,
    `driver`.`maritalStatus`,
    `driver`.`created_at`,
    `driver`.`updated_at`,
    (
        SELECT COUNT(*) FROM `driver`
    ) AS countPassenger,
    (
        SELECT CAST(AVG(`rating`) AS DECIMAL(10, 2))
        FROM `ratingPassenger`
        WHERE `ratingPassenger`.`driverID` = `driver`.`id`
    ) AS ratingPassenger,
    (
        SELECT COUNT(*) FROM `ratingPassenger` WHERE `driverID` = `driver`.`id`
    ) AS countDriverRate,
    (
        SELECT COUNT(*) FROM `canecl` WHERE `driverID` = `driver`.`id`
    ) AS countPassengerCancel,
    (
        SELECT CAST(AVG(`rating`) AS DECIMAL(10, 2))
        FROM `ratingDriver`
        WHERE `driver_id` = `driver`.`id`
    ) AS passengerAverageRating,
    (
        SELECT COUNT(*) FROM `ratingDriver` WHERE `driver_id` = `driver`.`id`
    ) AS countPassengerRate,
    (
        SELECT COUNT(*) FROM `ride` WHERE `driver_id` = `driver`.`id`
    ) AS countPassengerRide,
    (
        SELECT `token`
        FROM `driverToken`
        WHERE `captain_id` = `driver`.`id`
        LIMIT 1
    ) AS passengerToken
FROM `driver`
WHERE `driver`.`email` = :email OR `driver`.`phone` = :phone OR `driver`.`id` = :id
ORDER BY passengerAverageRating DESC
LIMIT 10
";

$stmt = $con->prepare($sql);
$stmt->bindParam(":email", $driverEmail);
$stmt->bindParam(":phone", $driverPhone);
$stmt->bindParam(":id", $driver_id);
$stmt->execute();
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);

// فك تشفير الحقول الحساسة
foreach ($result as &$row) {
    $row['phone'] = $encryptionHelper->decryptData($row['phone']);
    $row['email'] = $encryptionHelper->decryptData($row['email']);
    $row['gender'] = $encryptionHelper->decryptData($row['gender']);
    $row['birthdate'] = $encryptionHelper->decryptData($row['birthdate']);
    $row['site'] = $encryptionHelper->decryptData($row['site']);
    $row['first_name'] = $encryptionHelper->decryptData($row['first_name']);
    $row['last_name'] = $encryptionHelper->decryptData($row['last_name']);
    $row['education'] = $encryptionHelper->decryptData($row['education']);
    $row['employmentType'] = $encryptionHelper->decryptData($row['employmentType']);
    $row['maritalStatus'] = $encryptionHelper->decryptData($row['maritalStatus']);
}

if ($stmt->rowCount() > 0) {
    jsonSuccess($result);
} else {
    jsonError("No records found");
}
?>

File: Admin/AdminCaptain/getCaptainDetailsById.php

<?php
require_once __DIR__ . '/../../connect.php';

// تشفير driver_id قبل استخدامه في SQL
$driver_id = filterRequest("driver_id");

$sql = "SELECT
    `driver`.`id`,
    `driver`.`phone`,
    `driver`.`email`,
    `driver`.`gender`,
    `driver`.`status`,
    `driver`.`birthdate`,
    `driver`.`site`,
    `driver`.`first_name`,
    `driver`.`last_name`,
    `driver`.`education`,
    `driver`.`employmentType`,
    `driver`.`maritalStatus`,
    `driver`.`created_at`,
    `driver`.`updated_at`,
    (
        SELECT COUNT(*) FROM `driver`
    ) AS countPassenger,
    (
        SELECT CAST(AVG(`rating`) AS DECIMAL(10, 2))
        FROM `ratingPassenger`
        WHERE `ratingPassenger`.`driverID` = `driver`.`id`
    ) AS ratingPassenger,
    (
        SELECT COUNT(*) FROM `ratingPassenger`
        WHERE `ratingPassenger`.`driverID` = `driver`.`id`
    ) AS countDriverRate,
    (
        SELECT COUNT(*) FROM `canecl`
        WHERE `canecl`.`driverID` = `driver`.`id`
    ) AS countPassengerCancel,
    (
        SELECT CAST(AVG(`rating`) AS DECIMAL(10, 2))
        FROM `ratingDriver`
        WHERE `ratingDriver`.`driver_id` = `driver`.`id`
    ) AS passengerAverageRating,
    (
        SELECT COUNT(*) FROM `ratingDriver`
        WHERE `ratingDriver`.`driver_id` = `driver`.`id`
    ) AS countPassengerRate,
    (
        SELECT COUNT(*) FROM `ride`
        WHERE `ride`.`driver_id` = `driver`.`id`
    ) AS countPassengerRide,
    (
        SELECT `token`
        FROM `driverToken`
        WHERE `driverToken`.`captain_id` = `driver`.`id`
        LIMIT 1
    ) AS passengerToken
FROM `driver`
WHERE `driver`.`id` = :driver_id
ORDER BY passengerAverageRating DESC
LIMIT 10";

$stmt = $con->prepare($sql);
$stmt->bindParam(':driver_id', $driver_id);
$stmt->execute();

$result = $stmt->fetchAll(PDO::FETCH_ASSOC);

// فك تشفير الحقول الحساسة بعد الجلب
foreach ($result as &$row) {
    $row['phone'] = $encryptionHelper->decryptData($row['phone']);
    $row['email'] = $encryptionHelper->decryptData($row['email']);
    $row['gender'] = $encryptionHelper->decryptData($row['gender']);
    $row['birthdate'] = $encryptionHelper->decryptData($row['birthdate']);
    $row['site'] = $encryptionHelper->decryptData($row['site']);
    $row['first_name'] = $encryptionHelper->decryptData($row['first_name']);
    $row['last_name'] = $encryptionHelper->decryptData($row['last_name']);
    $row['education'] = $encryptionHelper->decryptData($row['education']);
    $row['employmentType'] = $encryptionHelper->decryptData($row['employmentType']);
    $row['maritalStatus'] = $encryptionHelper->decryptData($row['maritalStatus']);
}

if ($stmt->rowCount() > 0) {
    jsonSuccess($result);
} else {
    jsonError("No records found");
}
?>

File: Admin/AdminCaptain/delete.php


File: Admin/AdminCaptain/getDriversPhonesAndTokens.php

<?php
require_once __DIR__ . '/../../connect.php';

$sql = "
SELECT
    d.phone,
    d.id,
    d.name_arabic,
    dt.token
FROM
    `driver` d
LEFT JOIN driverToken dt ON
    dt.captain_id = d.id
";

$stmt = $con->prepare($sql);
$stmt->execute();
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);

// فك التشفير للحقول الحساسة
foreach ($result as &$row) {
    $row['phone'] = $encryptionHelper->decryptData($row['phone']);
    if (!empty($row['token'])) {
        $row['token'] = $encryptionHelper->decryptData($row['token']);
    }
}

if ($stmt->rowCount() > 0) {
    jsonSuccess($result);
} else {
    jsonError("No records found");
}
?>

File: Admin/auth/login.php

<?php
//login.php
require_once __DIR__ . '/../../connect.php';

$device = filterRequest("device_number");
$phone  = filterRequest("phone_number");

if (empty($device) || empty($phone)) {
    jsonError("device_number أو phone_number مفقود");
    exit;
}

$stmt = $con->prepare("SELECT * FROM adminUser WHERE device_number = ? AND name = ?");
$stmt->execute([$device, $phone]);

if ($stmt->rowCount() > 0) {
    $admin = $stmt->fetch(PDO::FETCH_ASSOC);

    // يمكن لاحقًا توليد توكن أو بيانات أخرى
    printSuccess([
        "message" => "تم التحقق بنجاح",
        "admin" => $admin,
    ]);
} else {
    jsonError("بيانات الدخول غير صحيحة أو غير مسجلة.");
}

File: Admin/auth/send_otp_admin.php

<?php
// send_otp_admin.php — إرسال رمز التحقق لمسؤول عبر WhatsApp

require_once __DIR__ . '/../../connect.php';

error_log("--- [send_otp_admin] Script started ---");

// جلب الرقم من الطلب
$receiver = filterRequest("receiver");
//error_log("[send_otp_admin] Received phone number: " . var_export($receiver, true));

if (!$receiver) {
  //  error_log("[send_otp_admin] Missing phone number");
    jsonError("رقم الهاتف مفقود.");
    exit;
}

// قراءة الأرقام المصرح بها من ENV
$allowedPhones = explode(',', getenv('ADMIN_PHONE_NUMBERS'));
//error_log("[send_otp_admin] Allowed phones: " . implode(', ', $allowedPhones));

if (!in_array($receiver, $allowedPhones)) {
    error_log("[send_otp_admin] Unauthorized phone number attempted: $receiver");
    jsonError("رقم الهاتف غير مصرح له.");
    exit;
}

// توليد رمز تحقق عشوائي
$otp = rand(10000, 99999);
$messageBody = "رمز التحقق الخاص بك للدخول إلى لوحة الإدارة هو: $otp";
//error_log("[send_otp_admin] Generated OTP: $otp for $receiver");

// إرسال الرسالة عبر WhatsApp
$success = sendWhatsAppFromServer($receiver, $messageBody);
error_log("[send_otp_admin] WhatsApp sending result: " . ($success ? "success" : "failure"));

if ($success) {
    try {
        $stmt = $con->prepare("INSERT INTO token_verification_admin (phone_number, token, expiration_time)
                               VALUES (?, ?, DATE_ADD(NOW(), INTERVAL 5 MINUTE))
                               ON DUPLICATE KEY UPDATE token = VALUES(token), expiration_time = VALUES(expiration_time)");
        $stmt->execute([$receiver, $otp]);
       // error_log("[send_otp_admin] OTP saved to database successfully for $receiver");

        jsonSuccess(null, "OTP sent successfully.");
    } catch (PDOException $e) {
       // error_log("[send_otp_admin] Database error: " . $e->getMessage());
        jsonError("حدث خطأ في حفظ الرمز.");
    }
} else {
  //  error_log("[send_otp_admin] Failed to send WhatsApp message to $receiver");
    jsonError("فشل في إرسال الرمز عبر WhatsApp.");
}

//error_log("--- [send_otp_admin] Script ended ---");
?>

File: Admin/auth/verify_otp_admin.php

<?php
require_once __DIR__ . '/../../connect.php';

$phone         = filterRequest("phone_number");
$otp           = filterRequest("otp");
$deviceNumber  = filterRequest("device_number");

if (empty($phone) || empty($otp)) {
    jsonError("رقم الهاتف أو رمز التحقق مفقود.");
    exit;
}

// التحقق من رمز التحقق (OTP)
$stmt = $con->prepare("SELECT * FROM token_verification_admin 
                       WHERE phone_number = ? AND token = ? 
                       AND expiration_time >= NOW()");
$stmt->execute([$phone, $otp]);

if ($stmt->rowCount() > 0) {
    // ✅ تحقق ناجح - ننتقل إلى إدخال أو تحديث سجل adminUser

    // تحقق إن كان المستخدم موجود مسبقًا
    $checkAdmin = $con->prepare("SELECT * FROM adminUser WHERE name = ?");
    $checkAdmin->execute([$phone]);

    $now = date("Y-m-d H:i:s");

    if ($checkAdmin->rowCount() > 0) {
        // المستخدم موجود ✅ تحديث device_number و updated_at
        $update = $con->prepare("UPDATE adminUser 
                                 SET device_number = ?, updated_at = ? 
                                 WHERE name = ?");
        $update->execute([$deviceNumber, $now, $phone]);
        jsonSuccess(["message" => "verified and updated existing admin"]);
    } else {
        // المستخدم غير موجود ✅ إدخال جديد
        $insert = $con->prepare("INSERT INTO adminUser (device_number, name, created_at, updated_at) 
                                 VALUES (?, ?, ?, ?)");
        $insert->execute([$deviceNumber, $phone, $now, $now]);
        jsonSuccess(["message" => "verified and new admin created"]);
    }

} else {
    // ❌ رمز التحقق غير صالح
    jsonError("رمز التحقق غير صالح أو منتهي.");
}

File: Admin/driver/remove_from_blacklist.php

<?php
require_once __DIR__ . '/../../connect.php';

$phone = filterRequest("phone");

if (empty($phone)) {
    jsonError("Phone number is required.");
    exit;
}

try {
    // تشفير الرقم للمطابقة مع المخزن
    $encPhone = $encryptionHelper->encryptData($phone);

    $sql = "DELETE FROM blacklist_driver WHERE phone = :phone";
    $stmt = $con->prepare($sql);
    $stmt->execute([':phone' => $encPhone]);

    if ($stmt->rowCount() > 0) {
        jsonSuccess(null, "Driver removed from blacklist successfully.");
    } else {
        jsonError("No driver found in blacklist with this phone.");
    }

} catch (PDOException $e) {
    jsonError("Error removing from blacklist: " . $e->getMessage());
}

File: Admin/driver/find_driver_by_phone.php

<?php
require_once __DIR__ . '/../../connect.php';

$phone = filterRequest("phone");

if (empty($phone)) {
    jsonError("Phone number is required.");
    exit;
}

try {
    // تشفير الرقم المدخل للبحث
    $encPhone = $encryptionHelper->encryptData($phone);

    // احضار كل الأعمدة باستثناء كلمة المرور
    $sql = "SELECT * 
            FROM driver 
            WHERE phone = :phone 
            LIMIT 1";
    $stmt = $con->prepare($sql);
    $stmt->execute([':phone' => $encPhone]);

    $driver = $stmt->fetch(PDO::FETCH_ASSOC);

    if ($driver) {
        // ✅ الحقول المشفرة اللي لازم تنفك:
        $encryptedFields = [
            'phone',
            'email',
            'first_name',
            'last_name',
            'national_number',
            'address','gender','site',
            'birthdate',
            'name_arabic',
        ];

        foreach ($encryptedFields as $field) {
            if (!empty($driver[$field])) {
                $driver[$field] = $encryptionHelper->decryptData($driver[$field]);
            }
        }

        // ❌ احذف كلمة المرور من النتيجة
        unset($driver['password']);

        jsonSuccess($driver);

    } else {
        jsonError("No driver found with this phone.");
    }

} catch (PDOException $e) {
    jsonError("Error searching driver: " . $e->getMessage());
}

File: Admin/driver/deleteCaptain.php

<?php
require_once __DIR__ . '/../../connect.php';

$driver_id = filterRequest("driver_id");
$phone     = filterRequest("phone");
$reason    = filterRequest("reason"); // يمكن أن يأتي من البارامتر أو نخليه افتراضي

if (empty($driver_id) || empty($phone)) {
    jsonError("Driver ID and phone are required.");
    exit;
}

try {
    // تشفير رقم الهاتف
    $encPhone = $encryptionHelper->encryptData($phone);

    // حذف السائق من جدول driver
    $sqlDel = "DELETE FROM driver WHERE id = :id";
    $stmtDel = $con->prepare($sqlDel);
    $stmtDel->bindParam(':id', $driver_id, PDO::PARAM_INT);
    $stmtDel->execute();

    if ($stmtDel->rowCount() > 0) {
        // إضافة بيانات السائق المحذوف إلى البلاك ليست
        $sqlInsert = "INSERT INTO blacklist_driver (driver_id, phone, reason) 
                      VALUES (:driver_id, :phone, :reason)";
        $stmtInsert = $con->prepare($sqlInsert);
        $stmtInsert->execute([
            'driver_id' => $driver_id,
            'phone'     => $encPhone,
            'reason'    => !empty($reason) ? $reason : "Deleted & blacklisted by admin"
        ]);

        jsonSuccess(null, "Driver deleted and blacklisted successfully.");
    } else {
        jsonError("No driver found with the provided ID.");
    }

} catch (PDOException $e) {
    jsonError("Error: " . $e->getMessage());
}

File: Admin/driver/updateDriverFromAdmin.php

<?php
require_once __DIR__ . '/../../connect.php';

$driver_id = filterRequest("id");
$phone     = filterRequest("phone");

// تشفير رقم الهاتف
$encphone = $encryptionHelper->encryptData($phone);

$sql = "UPDATE `driver` SET `phone` = :encphone WHERE `id` = :id";
$stmt = $con->prepare($sql);

// Bind values
$stmt->bindParam(':encphone', $encphone, PDO::PARAM_STR);
$stmt->bindParam(':id', $driver_id, PDO::PARAM_STR);

try {
    $stmt->execute();

    if ($stmt->rowCount() > 0) {
        // تم التحديث بنجاح
        jsonSuccess(null, "Phone updated successfully.");
    } else {
        // لم يتم العثور على أي سجل للتحديث
        jsonError("No records updated. Please check the driver ID.");
    }
} catch (PDOException $e) {
    jsonError("Error updating record: " . $e->getMessage());
}
?>

File: Admin/driver/getDriverGiftPayment.php

<?php

require_once __DIR__ . '/../../connect.php';

$phone = filterRequest("phone");

// Encrypt phone
$encphone = $encryptionHelper->encryptData($phone);

$sql = "SELECT
            *
        FROM
            `driver`
        WHERE
            phone = :encPhone";

$stmt = $con->prepare($sql);

// FIX 1: Bind AFTER preparing the statement
// FIX 2: Use the same placeholder name (:encPhone)
$stmt->bindParam(':encPhone', $encphone, PDO::PARAM_STR);

$stmt->execute();

if ($stmt->rowCount() > 0) {

    $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);

    // Decrypt sensitive fields
    foreach ($rows as &$row) {
        if (!empty($row['phone'])) {
            $row['phone'] = $encryptionHelper->decryptData($row['phone']);
        }
      if (!empty($row['name_arabic'])) {
            $row['name_arabic'] = $encryptionHelper->decryptData($row['name_arabic']);
        }
    }

    jsonSuccess($rows);

} else {
    jsonError("No recent driver location activity found");
}

?>

File: Admin/driver/getBestDriver.php

<?php

require_once __DIR__ . '/../../connect.php';

$sql = "SELECT
    COUNT(`car_locations`.driver_id) AS driver_count,
    driver.id,
    driver.phone,
    driver.name_arabic,
    MAX(dt.token) AS token
FROM
    `car_locations`
LEFT JOIN driver ON driver.id = car_locations.driver_id
LEFT JOIN driverToken dt ON dt.captain_id = driver.id
WHERE
    `car_locations`.created_at > TIMESTAMP(DATE_SUB(NOW(), INTERVAL 7 DAY))
GROUP BY
    driver.id
ORDER BY
    driver_count DESC
LIMIT 19;
";

$stmt = $con->prepare($sql);
$stmt->execute();

if ($stmt->rowCount() > 0) {
    $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);

    // فك التشفير للحقول الحساسة
    foreach ($rows as &$row) {
        if (!empty($row['phone'])) {
            $row['phone'] = $encryptionHelper->decryptData($row['phone']);
        }
        if (!empty($row['name_arabic'])) {
            $row['name_arabic'] = $encryptionHelper->decryptData($row['name_arabic']);
        }
        if (!empty($row['token'])) {
            $row['token'] = $encryptionHelper->decryptData($row['token']);
        }
    }

    jsonSuccess($rows);
} else {
    jsonError($message = "No recent driver location activity found");
}

?>

File: Admin/driver/deleteRecord.php

<?php

require_once __DIR__ . '/../../connect.php';

$driver_id = filterRequest("driver_id");

// Prepare the DELETE query
$sql = "DELETE FROM `car_locations` WHERE driver_id = :driver_id";
$stmt = $con->prepare($sql);

// Bind the driver_id parameter
$stmt->bindParam(':driver_id', $driver_id, PDO::PARAM_STR);

try {
    // Execute the query
    $stmt->execute();

    if ($stmt->rowCount() > 0) {
        // Success response
        jsonSuccess(null, "Record(s) deleted successfully.");
    } else {
        // Failure response: no records found to delete
        jsonError("No records found for the provided driver ID.");
    }
} catch (PDOException $e) {
    // Handle any SQL errors
    jsonError("Error deleting records: " . $e->getMessage());
}

?>

File: Admin/AdminRide/get.php

<?php
require_once __DIR__ . '/../../connect.php';

$sql = "SELECT
(
    SELECT TIME_FORMAT(SEC_TO_TIME(AVG(TIMESTAMPDIFF(SECOND, rideTimeStart, rideTimeFinish))), '%Hh %im')
    FROM ride
    WHERE rideTimeStart IS NOT NULL AND rideTimeFinish IS NOT NULL
) AS driver_avg_duration,

(
    SELECT COUNT(*) FROM (
        SELECT COUNT(driver_id) FROM ride GROUP BY driver_id
    ) AS sub
) AS num_Driver,

(
    SELECT COUNT(*) FROM ride
) AS total_rides,

(
    SELECT COUNT(*) FROM ride WHERE status = 'waiting'
) AS ongoing_rides,

(
    SELECT COUNT(*) FROM ride WHERE status = 'Finished'
) AS completed_rides,

(
    SELECT COUNT(*) FROM ride WHERE status = 'cancelled'
) AS cancelled_rides,

(
    SELECT TIME_FORMAT(SEC_TO_TIME(MAX(TIMESTAMPDIFF(SECOND, rideTimeStart, rideTimeFinish))), '%Hh %im')
    FROM ride
    WHERE rideTimeStart IS NOT NULL AND rideTimeFinish IS NOT NULL
) AS longest_duration,

(
    SELECT ROUND(SUM(distance), 2) FROM ride
) AS total_distance,

(
    SELECT ROUND(AVG(distance), 2) FROM ride
) AS average_distance,

(
    SELECT ROUND(MAX(distance), 2) FROM ride
) AS longest_distance,

(
    SELECT ROUND(SUM(price_for_driver), 2) FROM ride
) AS total_driver_earnings,

(
    SELECT ROUND(SUM(price_for_passenger), 2) FROM ride
) AS total_company_earnings,

(
    SELECT ROUND(
        (SELECT SUM(price_for_passenger) FROM ride) / 
        NULLIF((SELECT SUM(price_for_driver) FROM ride), 0),
        2
    )
) AS companyPercent

FROM dual
LIMIT 1";

$stmt = $con->prepare($sql);
$stmt->execute();
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);

if ($stmt->rowCount() > 0) {
    jsonSuccess($result);
} else {
    jsonError("No records found");
}
?>

File: Admin/AdminRide/getRidesPerMonth.php

<?php
require_once __DIR__ . '/../../connect.php';

$currentYear = date('Y');
$currentMonth = date('m');

// SQL to get daily ride counts
$sql = "
SELECT 
    YEAR(date) AS year,
    MONTH(date) AS month,
    DAY(date) AS day,
    COUNT(*) AS rides_count
FROM 
    ride
GROUP BY 
    YEAR(date), 
    MONTH(date), 
    DAY(date)
ORDER BY 
    YEAR(date), 
    MONTH(date), 
    DAY(date)
";
$stmt = $con->prepare($sql);
$stmt->execute();
$dailyRides = $stmt->fetchAll(PDO::FETCH_ASSOC);

// SQL to get current month's total ride count
$sqlMonth = "
SELECT COUNT(*) AS current_month_rides_count 
FROM ride 
WHERE MONTH(date) = :currentMonth AND YEAR(date) = :currentYear
";
$stmtMonth = $con->prepare($sqlMonth);
$stmtMonth->bindParam(':currentMonth', $currentMonth);
$stmtMonth->bindParam(':currentYear', $currentYear);
$stmtMonth->execute();
$monthRides = $stmtMonth->fetch(PDO::FETCH_ASSOC);

// Append current month total to each row (if needed)
foreach ($dailyRides as &$row) {
    $row['current_month_rides_count'] = $monthRides['current_month_rides_count'];
}

// Return result
if ($dailyRides) {
    jsonSuccess($dailyRides);
} else {
    jsonError("No records found");
}
?>

File: Admin/passenger/admin_update_passenger.php

<?php
require_once __DIR__ . '/../../connect.php';



$id          = filterRequest("id");            // مفضّل

$first_name  = filterRequest("first_name");
$last_name   = filterRequest("last_name");
$new_phone   = filterRequest("phone");

if (empty($id) ) { jsonError("Provide id or phone_lookup"); exit; }
if ($first_name === null && $last_name === null && $new_phone === null) {
    jsonError("Nothing to update"); exit;
}

$sets   = [];
$params = [];
 	$new_phone  = $encryptionHelper->encryptData($new_phone);
	$first_name  = $encryptionHelper->encryptData($first_name);
	$last_name  = $encryptionHelper->encryptData($last_name);

    $enc_norm = $encryptionHelper->encryptData($norm);
if ($first_name !== null) { $sets[] = "first_name = :first_name"; $params['first_name'] = trim($first_name); }
if ($last_name  !== null) { $sets[] = "last_name  = :last_name";  $params['last_name']  = trim($last_name);  }
if ($new_phone  !== null) { 
    $sets[] = "phone      = :phone";      
    $params['phone'] = trim($new_phone);

    // منع تكرار الهاتف على راكب آخر
    $q = $con->prepare("SELECT id FROM passengers WHERE phone = :ph LIMIT 1");
    $q->execute(['ph' => $params['phone']]);
    $row = $q->fetch(PDO::FETCH_ASSOC);
    if ($row) {
        if (!empty($id) && $row['id'] != $id) { jsonError("Phone already used by another passenger"); exit; }
        if (empty($id) && $row['id'] != $phoneLookup) { jsonError("Phone already used by another passenger"); exit; }
    }
}

$whereSql    = "";
$whereParams = [];
if (!empty($id))       { $whereSql = "id = :pid";   $whereParams['pid']   = $id; }
else                   { $whereSql = "phone = :plk"; $whereParams['plk']  = $phoneLookup; }

$sql = "UPDATE passengers SET ".implode(", ", $sets).", updated_at = CURRENT_TIMESTAMP WHERE $whereSql";
$stmt = $con->prepare($sql);
$ok = $stmt->execute(array_merge($params, $whereParams));

if ($ok && $stmt->rowCount() > 0) { jsonSuccess(null, "Passenger updated"); }
else                              { jsonError("No change or passenger not found"); }

File: Admin/passenger/admin_unblacklist.php

<?php
require_once __DIR__ . '/../../connect.php';

function normalize_phone($s) { return preg_replace('/\D+/', '', (string)$s); }

$phone = filterRequest("phone");
if (empty($phone)) { jsonError("phone is required"); exit; }

$phn = normalize_phone($phone);
$stmt = $con->prepare("DELETE FROM passenger_blacklist WHERE phone_normalized = :phn");
$stmt->execute(['phn' => $phn]);

if ($stmt->rowCount() > 0) { jsonSuccess(null, "Removed from blacklist"); }
else                       { jsonError("Phone was not blacklisted"); }

File: Admin/passenger/admin_delete_and_blacklist_passenger.php

<?php
require_once __DIR__ . '/../../connect.php';

function normalize_phone($s) { return preg_replace('/\D+/', '', (string)$s); }

$id    = filterRequest("id");     // أو
$phone = filterRequest("phone");  // أحدهما مطلوب
$reason= filterRequest("reason"); // اختياري
$exp   = filterRequest("expires_at"); // اختياري Y-m-d H:i:s

if (empty($id) && empty($phone)) { jsonError("Provide id or phone"); exit; }

try {
    $con->beginTransaction();

    // احضر السجل
    if (!empty($id)) {
        $sel = $con->prepare("SELECT id, phone FROM passengers WHERE id = :id LIMIT 1");
        $sel->execute(['id' => $id]);
    } else {
        $sel = $con->prepare("SELECT id, phone FROM passengers WHERE phone = :ph LIMIT 1");
        $sel->execute(['ph' => $phone]);
    }
    $p = $sel->fetch(PDO::FETCH_ASSOC);
    if (!$p) { throw new Exception("Passenger not found"); }

    $phRaw = $p['phone'];
    $phNorm= normalize_phone($phRaw);

    // أدخِل/حدّث في البلاك ليست
    $ins = $con->prepare("
        INSERT INTO passenger_blacklist (phone, phone_normalized, reason, expires_at)
        VALUES (:ph, :phn, :r, :exp)
        ON DUPLICATE KEY UPDATE reason = VALUES(reason), expires_at = VALUES(expires_at)
    ");
    $ins->execute([
        'ph'  => $phRaw,
        'phn' => $phNorm,
        'r'   => $reason ?: 'Deleted & blacklisted',
        'exp' => $exp ?: null
    ]);

    // حذف فعلي
    $del = $con->prepare("DELETE FROM passengers WHERE id = :id");
    $del->execute(['id' => $p['id']]);

    $con->commit();
    jsonSuccess(null, "Passenger deleted and blacklisted");
} catch (Throwable $e) {
    $con->rollBack();
    jsonError("Failed: ".$e->getMessage());
}

File: Admin/employee/add.php

<?php
require_once __DIR__ . '/../../connect.php';

// Get the data from the request
$name = filterRequest("name");
$education = filterRequest("education");
$site = filterRequest("site");
$phone = filterRequest("phone");
$status = filterRequest("status");
$id=filterRequest("id");

// Set the current timestamp for the 'created_at' field
$created_at = date("Y-m-d H:i:s");

// Prepare the SQL insert query using parameterized statements to avoid SQL injection
$sql = "INSERT INTO `employee` (`id`,`name`, `education`, `site`, `phone`, `created_at`, `status`) 
        VALUES (?,?, ?, ?, ?, ?, ?)";

// Prepare and execute the statement
$stmt = $con->prepare($sql);
$stmt->execute([$id, $name, $education, $site, $phone, $created_at, $status]);

// Check if the query successfully inserted the record
if ($stmt->rowCount() > 0) {
    // If a row was inserted, print success
    jsonSuccess($message = "Employee record added successfully");
} else {
    // If no rows were inserted, print failure
    jsonError($message = "Failed to add employee record");
}
?>

File: Admin/employee/get.php

<?php
require_once __DIR__ . '/../../connect.php';

// Prepare the SQL query to select all records from the employee table with a limit of 10
$sql = "SELECT
    *
FROM
    `employee` e
ORDER BY
    e.created_at
DESC
    ";

// Prepare and execute the statement
$stmt = $con->prepare($sql);
$stmt->execute();

// Fetch all records as an associative array
$employee_data = $stmt->fetchAll(PDO::FETCH_ASSOC);

// Check if any records were retrieved
if ($employee_data) {
    // If records were found, print the data as JSON
    jsonSuccess($data = $employee_data);
} else {
    // If no records were found, print a failure message
    jsonError($message = "No employee records found");
}
?>

File: Admin/error/error_list_last20.php

<?php
// File: /v1/admin/error/error_list_last20.php
require_once __DIR__ . '/../../connect.php';

try {
    $sql = "SELECT `id`, `error`, `userId`, `userType`, `phone`, `created_at`, `device`, `details`, `status`
            FROM `error`
            ORDER BY `created_at` DESC
            LIMIT 20";
    $stmt = $con->prepare($sql);
    $stmt->execute();
    $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);

    jsonSuccess($rows);
} catch (Exception $e) {
    error_log("error_list_last20.php: " . $e->getMessage());
    jsonError($message = "Failed to fetch last 20 errors");
}

File: Admin/error/error_search_by_phone.php

<?php
// File: /v1/admin/error/error_search_by_phone.php
require_once __DIR__ . '/../../connect.php';

try {
    $phone = filterRequest("phone");
    if ($phone === false || $phone === null || trim($phone) === "") {
        jsonError("Phone is required");
        exit;
    }

    // في حال مخزّن الهاتف مشفّر، طبق نفس دالتك للتشفير هنا:
    // $enc_phone = $encryptionHelper->encryptData(trim($phone));
    // ثم بدّل الحقل في WHERE إلى phone = :ph
    $sql = "SELECT `id`, `error`, `userId`, `userType`, `phone`, `created_at`, `device`, `details`, `status`
            FROM `error`
            WHERE `phone` = :ph OR `phone` LIKE :phLike
            ORDER BY `created_at` DESC
            LIMIT 20";

    $stmt = $con->prepare($sql);
    $stmt->execute([
        ":ph"     => trim($phone),
        ":phLike" => '%' . trim($phone) . '%', // يسمح بجزء من الرقم إن أردت
    ]);

    $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
    jsonSuccess($rows);
} catch (Exception $e) {
    error_log("error_search_by_phone.php: " . $e->getMessage());
    jsonError($message = "Failed to search errors by phone");
}

File: Admin/adminUser/add.php

<?php
require_once __DIR__ . '/../../connect.php';

$deviceNumber = filterRequest("deviceNumber"); // Assuming you'll get deviceNumber as input
$name = filterRequest("name");

$sql = "INSERT INTO `adminUser`(`id`, `device_number`, `name`) VALUES (
  UUID(),
  :deviceNumber,
  :name
)";

$stmt = $con->prepare($sql);
$stmt->bindParam(':deviceNumber', $deviceNumber);
$stmt->bindParam(':name', $name);
$stmt->execute();

if ($stmt->rowCount() > 0) {
  // Print a success message
  jsonSuccess($message = "Admin user data saved successfully");
} else {
  // Print a failure message
  jsonError($message = "Failed to save admin user data");
}
?>

File: Admin/adminUser/update.php


File: Admin/adminUser/get.php

<?php
require_once __DIR__ . '/../../connect.php';

$device_number = filterRequest("device_number"); 

$sql = "SELECT
    *
FROM
    `adminUser`
WHERE
    `device_number` = '$device_number'";

$stmt = $con->prepare($sql);
$stmt->execute();
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);

if (count($result) === 1) {
    // Print the first record as a success message
    jsonSuccess($result[0]);
} else {
    // Print a failure message
    jsonError($message = "Failed to retrieve Password or user name incorrect");
}
?>

File: Admin/adminUser/invoice_total.php

<?php
require_once __DIR__ . '/../../connect.php';

// ✅ استرجاع كل الفواتير من قاعدة البيانات
try {
    $stmt = $con->prepare("SELECT * FROM invoice_records ORDER BY date DESC");
    $stmt->execute();
    $invoices = $stmt->fetchAll(PDO::FETCH_ASSOC);

    // ✅ حساب عدد الفواتير ومجموع المبالغ
    $count = count($invoices);
    $totalAmount = array_sum(array_column($invoices, 'amount'));

    echo json_encode([
        "status" => "success",
        "data" => $invoices,
        "summary" => [
            "count" => $count,
            "total" => $totalAmount
        ]
    ]);
} catch (PDOException $e) {
    echo json_encode([
        "status" => "error",
        "message" => "Database error: " . $e->getMessage()
    ]);
}
?>

File: Admin/adminUser/add_invoice.php

<?php

// عرض كافة الأخطاء
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);

require_once __DIR__ . '/../../connect.php';

$driverID       = filterRequest("driverID");
$invoiceNumber  = filterRequest("invoiceNumber");
$amount         = filterRequest("amount");
$date           = filterRequest("date");
$name           = filterRequest("name");

$linkImage  = null;
$uploadDate = date("Y-m-d H:i:s");

// ✅ طباعة بيانات الإدخال للتأكد
error_log("[add_invoice.php] 📥 Data received | driverID: $driverID, invoiceNumber: $invoiceNumber, amount: $amount, date: $date");

// التحقق من وجود ملف الصورة
if (isset($_FILES['image']) && $_FILES['image']['error'] === UPLOAD_ERR_OK) {
    $image_file       = $_FILES['image'];
    $image_name       = $image_file['name'];
    $image_extension  = strtolower(pathinfo($image_name, PATHINFO_EXTENSION));
    $allowed_extensions = ['jpg', 'jpeg', 'png'];

    if (!in_array($image_extension, $allowed_extensions)) {
        error_log("[add_invoice.php] ❌ Invalid image extension: .$image_extension");
        echo json_encode(['status' => 'error', 'message' => 'Invalid file type.']);
        exit;
    }

    $new_filename = $invoiceNumber . "_" . $driverID . '.' . $image_extension;
    $target_dir   = "invoice_images/";
    $target_file  = $target_dir . $new_filename;

    if (!is_dir($target_dir)) {
        if (!mkdir($target_dir, 0755, true)) {
            error_log("[add_invoice.php] ❌ Failed to create directory: $target_dir");
        }
    }

    if (!move_uploaded_file($image_file['tmp_name'], $target_file)) {
        error_log("[add_invoice.php] ❌ Failed to move uploaded file.");
        echo json_encode(['status' => 'error', 'message' => 'Failed to upload image.']);
        exit;
    }

    $linkImage = 'https://intaleq.xyz/siro/Admin/adminUser/invoice_images/' . $new_filename;
    error_log("[add_invoice.php] ✅ Image uploaded successfully: $linkImage");
}

try {
    $stmt = $con->prepare("INSERT INTO invoice_records (driverID, invoice_number,name, amount, date, image_link, created_at)
                           VALUES (?, ?, ?,?, ?, ?, ?)");
    $stmt->execute([$driverID, $invoiceNumber,$name, $amount, $date, $linkImage, $uploadDate]);

    echo json_encode([
        'status' => 'success',
        'message' => 'Invoice data saved.',
        'image' => $linkImage
    ]);

    error_log("[add_invoice.php] ✅ Invoice saved successfully.");
} catch (PDOException $e) {
    $errorMsg = $e->getMessage();
    error_log("[add_invoice.php] 🛑 PDO ERROR: $errorMsg");

    echo json_encode([
        'status' => 'error',
        'message' => "Database error: $errorMsg"
    ]);
}

File: Admin/adminUser/delete.php


File: EgyptDocuments/uploadEgyptIdBack.php

<?php
require_once __DIR__ . '/../connect.php';

// Get the image file from the request.
$image_file = $_FILES['image'];
$driverID = filterRequest("driverID");

// Define allowed extensions
$allowed_extensions = ['jpg', 'jpeg', 'png'];

// Get the image file from the request.
$image_file = $_FILES['image'];

// Check if the image file was uploaded successfully.
if ($image_file['error'] !== UPLOAD_ERR_OK) {
  echo "Image upload failed";
  exit;
}

// Get file information
$image_name = $image_file['name'];
$image_size = $image_file['size'];
$image_extension = strtolower(pathinfo($image_name, PATHINFO_EXTENSION));

// Validate file extension
if (!in_array($image_extension, $allowed_extensions)) {
  echo "Invalid image format";
  exit;
}

// Generate a unique filename using timestamp and random string
$new_filename = $driverID . '.' . $image_extension;

// Set target directory for uploads
$target_dir = "card_image/";

// Construct target file path
$target_file = $target_dir . $new_filename;

// Move the image file to the target location
if (!move_uploaded_file($image_file['tmp_name'], $target_file)) {
 echo json_encode(array('status' => "Failed to save image")); ;
  exit;
}

// Store additional information (modify based on your needs)
$image_url = $target_dir . $new_filename; // Update if needed
$image_details = [
  "name" => $image_name,
  "size" => $image_size,
  "extension" => $image_extension,
  "url" => $image_url,
];

// Use the image details for further processing (e.g., display, store in database)
// ...

 echo json_encode(array('status' => 'Image uploaded successfully!'));

?>

File: EgyptDocuments/uploadEgyptidFront.php

<?php
require_once __DIR__ . '/../connect.php';

// Get the image file from the request.
$image_file = $_FILES['image'];
$driverID = filterRequest("driverID");

// Define allowed extensions
$allowed_extensions = ['jpg', 'jpeg', 'png'];

// Get the image file from the request.
$image_file = $_FILES['image'];

// Check if the image file was uploaded successfully.
if ($image_file['error'] !== UPLOAD_ERR_OK) {
  echo "Image upload failed";
  exit;
}

// Get file information
$image_name = $image_file['name'];
$image_size = $image_file['size'];
$image_extension = strtolower(pathinfo($image_name, PATHINFO_EXTENSION));

// Validate file extension
if (!in_array($image_extension, $allowed_extensions)) {
  echo "Invalid image format";
  exit;
}

// Generate a unique filename using timestamp and random string
$new_filename = $driverID . '.' . $image_extension;

// Set target directory for uploads
$target_dir = "egypt/idFront/";

// Construct target file path
$target_file = $target_dir . $new_filename;

// Move the image file to the target location
if (!move_uploaded_file($image_file['tmp_name'], $target_file)) {
 echo json_encode(array('status' => "Failed to save image")); ;
  exit;
}

// Store additional information (modify based on your needs)
$image_url = $target_dir . $new_filename; // Update if needed
$image_details = [
  "name" => $image_name,
  "size" => $image_size,
  "extension" => $image_extension,
  "url" => $image_url,
];

// Use the image details for further processing (e.g., display, store in database)
// ...

 echo json_encode(array('status' => 'Image uploaded successfully!'));

?>

File: driver_assurance/add.php

<?php

require_once __DIR__ . '/../connect.php';

// Get the values from the request
$driver_id = filterRequest("driver_id");
$assured = filterRequest("assured"); // إذا كانت قيمة حساسة يجب تشفيرها
$health_insurance_provider = filterRequest("health_insurance_provider"); // إذا كانت حساسة، شفرها

// إذا تحتاج تشفير، فعّل التالي:
// $assured = $encryptionHelper->encryptData($assured);
// $health_insurance_provider = $encryptionHelper->encryptData($health_insurance_provider);

// SQL using bind parameters
$sql = "INSERT INTO `driver_health_assurance` (
  `driver_id`,
  `assured`,
  `health_insurance_provider`
) VALUES (
  :driver_id,
  :assured,
  :health_insurance_provider
)";

$stmt = $con->prepare($sql);
$stmt->bindParam(':driver_id', $driver_id);
$stmt->bindParam(':assured', $assured);
$stmt->bindParam(':health_insurance_provider', $health_insurance_provider);

if ($stmt->execute()) {
    jsonSuccess(null, "Health assurance data saved successfully");
} else {
    jsonError("Failed to save health assurance data");
}
?>

File: driver_assurance/update.php


File: driver_assurance/get.php


File: migration/get_all_driver_fingerprints.php


<?php
// ═══════════════════════════════════════════════════════════════
// get_all_driver_fingerprints.php
// ───────────────────────────────────────────────────────────────
// ⚠️ يُستخدم مرة واحدة فقط ثم يُحذف من السيرفر
// ═══════════════════════════════════════════════════════════════

require_once __DIR__ . '/../get_connect.php';

header('Content-Type: application/json');
header('Access-Control-Allow-Origin: https://intaleqapp.com');
header('Access-Control-Allow-Methods: POST, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type, Authorization');

if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(200); exit; }

// ── التحقق من admin_key ────────────────────────────────────────
$adminKey         = filterRequest('admin_key') ?? '';
$expectedAdminKey = getenv('MIGRATION_ADMIN_KEY');

if (empty($adminKey) || !hash_equals($expectedAdminKey, $adminKey)) {
    http_response_code(403);
    exit(json_encode(['error' => 'Forbidden']));
}

try {
    $stmt = $con->prepare('
        SELECT captain_id, fingerPrint
        FROM driverToken
        WHERE fingerPrint IS NOT NULL
          AND fingerPrint != ""
        ORDER BY captain_id
    ');
    $stmt->execute();
    $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);

    echo json_encode([
        'status' => 'success',
        'count'  => count($rows),
        'data'   => $rows,
    ]);

} catch (Exception $e) {
    error_log('❌ [get_all_driver_fingerprints] ' . $e->getMessage());
    http_response_code(500);
    echo json_encode(['error' => 'Server error']);
}

File: migration/get_all_fingerprints.php

<?php
// ═══════════════════════════════════════════════════════════════
// get_all_fingerprints.php — جلب كل البصمات للترحيل
// ───────────────────────────────────────────────────────────────
// ⚠️ يُستخدم مرة واحدة فقط ثم يُحذف من السيرفر
// محمي بـ admin_key لمنع الوصول العشوائي
// ═══════════════════════════════════════════════════════════════


require_once __DIR__ . '/../get_connect.php';
//include 'functions.php';

header('Content-Type: application/json');
header('Access-Control-Allow-Origin: https://intaleqapp.com');
header('Access-Control-Allow-Methods: POST, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type, Authorization');

if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
    http_response_code(200);
    exit;
}

// ── التحقق من admin_key ────────────────────────────────────────
$adminKey         = filterRequest('admin_key') ?? '';
$expectedAdminKey = getenv('MIGRATION_ADMIN_KEY'); // أضفه في .env

if (empty($adminKey) || !hash_equals($expectedAdminKey, $adminKey)) {
    http_response_code(403);
    echo json_encode(['error' => 'Forbidden']);
    exit;
}

try {
    // جلب كل البصمات من جدول tokens
    // نجيب passengerID + fingerPrint فقط — لا نعطي بيانات حساسة أخرى
    $stmt = $con->prepare('
        SELECT passengerID, fingerPrint, "passenger" AS userType
        FROM tokens
        WHERE fingerPrint IS NOT NULL
          AND fingerPrint != ""
        ORDER BY passengerID
    ');
    $stmt->execute();
    $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);

    echo json_encode([
        'status' => 'success',
        'count'  => count($rows),
        'data'   => $rows,
    ]);
    http_response_code(200);

} catch (Exception $e) {
    error_log('❌ [get_all_fingerprints] ' . $e->getMessage());
    http_response_code(500);
    echo json_encode(['error' => 'Server error']);
}

File: migration/update_driver_fingerprint_admin.php


<?php
// ═══════════════════════════════════════════════════════════════
// update_driver_fingerprint_admin.php
// ───────────────────────────────────────────────────────────────
// ⚠️ يُستخدم فقط أثناء الترحيل ثم يُحذف
// ═══════════════════════════════════════════════════════════════


require_once __DIR__ . '/../get_connect.php';

header('Content-Type: application/json');
header('Access-Control-Allow-Origin: https://intaleqapp.com');
header('Access-Control-Allow-Methods: POST, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type, Authorization');

if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(200); exit; }

$adminKey         = filterRequest('admin_key') ?? '';
$expectedAdminKey = getenv('MIGRATION_ADMIN_KEY');

if (empty($adminKey) || !hash_equals($expectedAdminKey, $adminKey)) {
    http_response_code(403);
    exit(json_encode(['error' => 'Forbidden']));
}

try {
    $captainId   = filterRequest('captain_id')  ?? '';
    $fingerprint = filterRequest('fingerprint') ?? '';

    if (empty($captainId) || empty($fingerprint)) {
        http_response_code(400);
        exit(json_encode(['error' => 'Missing parameters']));
    }

    $stmt = $con->prepare('
        UPDATE driverToken
        SET fingerPrint = :fp
        WHERE captain_id = :cid
    ');
    $stmt->execute([':fp' => $fingerprint, ':cid' => $captainId]);

    echo json_encode(['status' => 'success', 'affected' => $stmt->rowCount()]);

} catch (Exception $e) {
    error_log('❌ [update_driver_fingerprint_admin] ' . $e->getMessage());
    http_response_code(500);
    echo json_encode(['error' => 'Server error']);
}

File: migration/update_fingerprint_admin.php

<?php
// ═══════════════════════════════════════════════════════════════
// update_fingerprint_admin.php — تحديث بصمة واحدة (للترحيل)
// ───────────────────────────────────────────────────────────────
// ⚠️ يُستخدم فقط أثناء عملية الترحيل ثم يُحذف
// ═══════════════════════════════════════════════════════════════


require_once __DIR__ . '/../get_connect.php';

header('Content-Type: application/json');
header('Access-Control-Allow-Origin: https://intaleqapp.com');
header('Access-Control-Allow-Methods: POST, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type, Authorization');

if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
    http_response_code(200);
    exit;
}

// ── التحقق من admin_key ────────────────────────────────────────
$adminKey         = filterRequest('admin_key') ?? '';
$expectedAdminKey = getenv('MIGRATION_ADMIN_KEY');

if (empty($adminKey) || !hash_equals($expectedAdminKey, $adminKey)) {
    http_response_code(403);
    echo json_encode(['error' => 'Forbidden']);
    exit;
}

try {
    $passengerID = filterRequest('passengerID') ?? '';
    $fingerprint = filterRequest('fingerprint') ?? '';

    if (empty($passengerID) || empty($fingerprint)) {
        http_response_code(400);
        echo json_encode(['error' => 'Missing parameters']);
        exit;
    }

    $stmt = $con->prepare('
        UPDATE tokens
        SET fingerPrint = :fp
        WHERE passengerID = :pid
    ');
    $stmt->execute([
        ':fp'  => $fingerprint,
        ':pid' => $passengerID,
    ]);

    $affected = $stmt->rowCount();

    echo json_encode([
        'status'   => 'success',
        'affected' => $affected,
    ]);
    http_response_code(200);

} catch (Exception $e) {
    error_log('❌ [update_fingerprint_admin] ' . $e->getMessage());
    http_response_code(500);
    echo json_encode(['error' => 'Server error']);
}

File: email/sendTripEmail.php

<?php
// email/sendTripEmail.php — نسخة مؤمنة

use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception;

require_once __DIR__ . '/../../vendor/autoload.php';
require_once __DIR__ . '/../core/bootstrap.php';

// 1. فرض المصادقة (Auth Required)
$jwtService = new JwtService($redis);
$user = $jwtService->authenticate();
$EMAIL_ADDRESS = 'hamzaayed@intaleqapp.com';

// 2. استقبال البيانات وتطهيرها (Sanitization)
$passengerName     = htmlspecialchars(filterRequest('name') ?? 'User', ENT_QUOTES, 'UTF-8');
$passengerEmail    = filter_var(filterRequest('email'), FILTER_SANITIZE_EMAIL);
$passengerPhone    = htmlspecialchars(filterRequest('phone') ?? '', ENT_QUOTES, 'UTF-8');
$fee               = floatval(filterRequest('fee') ?? 0);
$startNameLocation = htmlspecialchars(filterRequest('startNameLocation') ?? '', ENT_QUOTES, 'UTF-8');
$endNameLocation   = htmlspecialchars(filterRequest('endNameLocation') ?? '', ENT_QUOTES, 'UTF-8');
$timeOfTrip        = htmlspecialchars(filterRequest('timeOfTrip') ?? date('Y-m-d H:i:s'), ENT_QUOTES, 'UTF-8');

if (!$passengerEmail || !filter_var($passengerEmail, FILTER_VALIDATE_EMAIL)) {
    jsonError("Invalid email address");
}

$SIRO_SMTP_PASSWORD = getenv('SIRO_SMTP_PASSWORD');

// بناء محتوى الإيميل بتصميم عصري وبريميوم
$bodyEmail = "
<!DOCTYPE html>
<html lang='en'>
<head>
    <meta charset='UTF-8'>
    <style>
        body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; background-color: #f4f7f9; color: #333; margin: 0; padding: 0; }
        .container { max-width: 600px; margin: 20px auto; background: #ffffff; border-radius: 12px; overflow: hidden; box-shadow: 0 10px 30px rgba(0,0,0,0.1); }
        .header { background: linear-gradient(135deg, #0052D4, #4364F7, #6FB1FC); color: #ffffff; padding: 40px 20px; text-align: center; }
        .header h1 { margin: 0; font-size: 28px; letter-spacing: 2px; text-transform: uppercase; }
        .content { padding: 30px; }
        .greeting { font-size: 20px; font-weight: bold; margin-bottom: 10px; color: #0052D4; }
        .trip-card { background: #f9f9f9; border-left: 5px solid #0052D4; padding: 20px; border-radius: 8px; margin: 20px 0; }
        .detail-row { display: flex; justify-content: space-between; padding: 10px 0; border-bottom: 1px solid #eee; }
        .detail-row:last-child { border-bottom: none; }
        .label { font-weight: 600; color: #666; }
        .value { font-weight: bold; color: #333; }
        .fee-section { text-align: center; margin-top: 30px; padding: 20px; background: #eef2f7; border-radius: 8px; }
        .fee-label { font-size: 14px; color: #666; text-transform: uppercase; }
        .fee-amount { font-size: 32px; font-weight: 900; color: #0052D4; }
        .footer { background: #333; color: #999; text-align: center; padding: 20px; font-size: 12px; }
        .footer p { margin: 5px 0; }
    </style>
</head>
<body>
    <div class='container'>
        <div class='header'>
            <h1>SIRO</h1>
            <p>Your journey, our priority</p>
        </div>
        <div class='content'>
            <div class='greeting'>Hello, $passengerName!</div>
            <p>Thank you for choosing <strong>SIRO</strong>. Your trip has been successfully confirmed. Here is your digital receipt:</p>
            
            <div class='trip-card'>
                <div class='detail-row'>
                    <span class='label'>From:</span>
                    <span class='value'>$startNameLocation</span>
                </div>
                <div class='detail-row'>
                    <span class='label'>To:</span>
                    <span class='value'>$endNameLocation</span>
                </div>
                <div class='detail-row'>
                    <span class='label'>Date & Time:</span>
                    <span class='value'>$timeOfTrip</span>
                </div>
                <div class='detail-row'>
                    <span class='label'>Phone:</span>
                    <span class='value'>$passengerPhone</span>
                </div>
            </div>

            <div class='fee-section'>
                <div class='fee-label'>Total Amount</div>
                <div class='fee-amount'>$$fee</div>
            </div>

            <p style='margin-top: 30px;'>If you have any questions, feel free to contact our support team at any time.</p>
        </div>
        <div class='footer'>
            <p>&copy; " . date('Y') . " SIRO. All rights reserved.</p>
            <p>Smart Transportation Solutions</p>
        </div>
    </div>
</body>
</html>";

$mail = new PHPMailer(true);
try {
    $mail->isSMTP();
    $mail->Host       = 'smtp.hostinger.com';
    $mail->SMTPAuth   = true;
    $mail->Username   = $EMAIL_ADDRESS;
    $mail->Password   = $SIRO_SMTP_PASSWORD;
    $mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS;
    $mail->Port       = 587;

    $mail->setFrom($EMAIL_ADDRESS, 'SIRO');
    $mail->addAddress($passengerEmail, $passengerName);
    $mail->isHTML(true);
    $mail->Subject = 'Your SIRO Trip Details';
    $mail->Body    = $bodyEmail;

    $mail->send();
    jsonSuccess(null, "Email sent successfully");
} catch (Exception $e) {
    jsonError("Failed to send email: " . $mail->ErrorInfo);
}