<?php
header("Content-Type: application/json; charset=UTF-8");
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Methods: POST, GET, OPTIONS");
header("Access-Control-Allow-Headers: Content-Type");

require 'config.php'; // ✅ استخدام PDO من config.php

// ✅ دالة shutdown لمعالجة الأخطاء القاتلة (Fatal Errors)
register_shutdown_function(function() {
    $error = error_get_last();
    if ($error && ($error['type'] === E_ERROR || $error['type'] === E_PARSE || $error['type'] === E_CORE_ERROR || $error['type'] === E_COMPILE_ERROR)) {
        if (ob_get_length()) ob_clean();
        http_response_code(500);
        header('Content-Type: application/json; charset=utf-8');
        echo json_encode(['status' => 'error', 'message' => 'حدث خطأ قاتل: ' . $error['message']], JSON_UNESCAPED_UNICODE);
        exit;
    }
});

// ثوابت معالجة النويز
if (!defined('NOISE_DISTANCE_THRESHOLD')) {
    define('NOISE_DISTANCE_THRESHOLD', 5); // متر
}
if (!defined('NOISE_ACCURACY_THRESHOLD')) {
    define('NOISE_ACCURACY_THRESHOLD', 80); // متر
}

// ✅ السماح لاختبارات الصحة (HEAD) بالنجاح بدون بيانات
if ($_SERVER['REQUEST_METHOD'] === 'HEAD') {
    http_response_code(200);
    exit;
}

// لا حاجة لـ ensureColumnsExist هنا، يمكن إدارته بشكل منفصل
/*
// التحقق من وجود الأعمدة المطلوبة وإضافتها إذا لم تكن موجودة
function ensureColumnsExist($conn) {
    $columns_to_add = [
        'speed' => 'DECIMAL(10,2) NULL',
        'accuracy' => 'DECIMAL(10,2) NULL', 
        'altitude' => 'DECIMAL(10,2) NULL',
        'heading' => 'DECIMAL(10,2) NULL'
    ];
    
    // التحقق من الأعمدة الموجودة
    $existing_columns = [];
    $result = $conn->query("SHOW COLUMNS FROM locations");
    if ($result) {
        while ($row = $result->fetch_assoc()) {
            $existing_columns[] = $row['Field'];
        }
    }
    
    // إضافة الأعمدة المفقودة
    foreach ($columns_to_add as $column_name => $column_definition) {
        if (!in_array($column_name, $existing_columns)) {
            $sql = "ALTER TABLE locations ADD COLUMN $column_name $column_definition";
            $conn->query($sql);
        }
    }
}

// تشغيل فحص الأعمدة
ensureColumnsExist($conn); 
*/
// استقبال البيانات من الطلب
$input = file_get_contents("php://input");
$data = json_decode($input, true);

// التحقق من صحة JSON
if (json_last_error() !== JSON_ERROR_NONE) {
    error_log("خطأ في تحليل JSON: " . json_last_error_msg());
    http_response_code(400);
    echo json_encode(["status" => "error", "message" => "❌ خطأ في تنسيق البيانات"]);
    exit;
}

if (!$data) {
    http_response_code(400);
    echo json_encode(["status" => "error", "message" => "❌ لم يتم استلام أي بيانات"]);
    exit;
}

// ✅ معالجة إشعارات الأجهزة (إذا كان الطلب لإرسال إشعار)
if (isset($data['alert_type']) && isset($data['device_id']) && isset($data['title']) && isset($data['message'])) {
    // هذا طلب إشعار - معالجته بشكل منفصل
    try {
        $deviceId = trim($data['device_id']);
        $alertType = trim($data['alert_type']);
        $title = trim($data['title']);
        $message = trim($data['message']);
        
        // ✅ الحصول على جميع المستخدمين النشطين لإنشاء التنبيه لكل منهم
        // هذا يضمن أن التنبيهات تظهر لجميع المستخدمين في الداشبورد
        try {
            $userIds = [];
            
            // ✅ البحث عن جميع المستخدمين النشطين (جدول devices لا يحتوي على user_id)
            try {
                $stmtUsers = $conn->query("SELECT id FROM users WHERE id > 0 ORDER BY id ASC");
                $users = $stmtUsers->fetchAll(PDO::FETCH_ASSOC);
                foreach ($users as $user) {
                    $userIds[] = (int)$user['id'];
                }
            } catch (PDOException $e) {
                error_log("⚠️ [add_location.php] Error fetching users: " . $e->getMessage());
                // ✅ إذا فشل، نستخدم user_id = 1 كقيمة افتراضية (عادة admin)
                $userIds[] = 1;
            }
            
            // ✅ إذا لم نجد أي مستخدمين، نستخدم user_id = 1 كقيمة افتراضية
            if (empty($userIds)) {
                $userIds[] = 1;
            }
            
            // ✅ التحقق من عدم وجود تنبيه مشابه حديث لكل مستخدم
            $shouldSkip = false;
            foreach ($userIds as $userId) {
                $stmt = $conn->prepare("
                    SELECT id FROM alerts 
                    WHERE user_id = ? AND device_id = ? AND alert_type = ?
                    AND created_at > DATE_SUB(NOW(), INTERVAL 2 MINUTE)
                    LIMIT 1
                ");
                $stmt->execute([$userId, $deviceId, $alertType]);
                $existingAlert = $stmt->fetch(PDO::FETCH_ASSOC);
                
                if ($existingAlert) {
                    $shouldSkip = true;
                    break;
                }
            }
            
            if ($shouldSkip) {
                echo json_encode([
                    'success' => true,
                    'skipped' => true,
                    'message' => 'تم تخطي التنبيه (مشابه لتنبيه حديث)'
                ]);
                exit;
            }
            
            // ✅ إنشاء التنبيه لكل مستخدم
            if (!class_exists('AlertService')) {
                require_once __DIR__ . '/alerts_service.php';
            }
            
            $createdAlerts = [];
            foreach ($userIds as $userId) {
                try {
                    $alertService = new AlertService($conn, $userId);
                    $alertId = $alertService->createAlert($deviceId, $alertType, $title, $message);
                    
                    if ($alertId) {
                        $createdAlerts[] = $alertId;
                        error_log("✅ تم إنشاء تنبيه جديد: [$alertType] $title - للجهاز: $deviceId (user_id: $userId, alert_id: $alertId)");
                    }
                } catch (Exception $e) {
                    error_log("⚠️ [add_location.php] Failed to create alert for user_id $userId: " . $e->getMessage());
                }
            }
            
            if (!empty($createdAlerts)) {
                echo json_encode([
                    'success' => true,
                    'alert_ids' => $createdAlerts,
                    'message' => '✅ تم إنشاء التنبيه بنجاح لـ ' . count($createdAlerts) . ' مستخدم'
                ]);
            } else {
                error_log("⚠️ [add_location.php] Failed to create alert for all users (device_id: $deviceId)");
                http_response_code(500);
                echo json_encode([
                    'success' => false,
                    'message' => '❌ فشل إنشاء التنبيه'
                ]);
            }
        } catch (Exception $e) {
            error_log("❌ [add_location.php] Exception creating alert: " . $e->getMessage());
            http_response_code(500);
            echo json_encode([
                'success' => false,
                'message' => '❌ خطأ في إنشاء التنبيه: ' . $e->getMessage()
            ]);
        }
        exit;
    } catch (PDOException $e) {
        error_log("❌ خطأ في قاعدة البيانات: " . $e->getMessage());
        http_response_code(500);
        echo json_encode([
            'success' => false,
            'message' => '❌ خطأ في قاعدة البيانات'
        ]);
        exit;
    } catch (Exception $e) {
        error_log("❌ خطأ عام: " . $e->getMessage());
        http_response_code(500);
        echo json_encode([
            'success' => false,
            'message' => '❌ حدث خطأ غير متوقع'
        ]);
        exit;
    }
}

// ✅ إضافة: معالجة الطلبات المجمّعة (Batch Requests)
// هذا يجعل السكربت متوافقاً مع صيغ بيانات مختلفة قد ترسلها بعض الأجهزة
if (isset($data['batch']) && is_array($data['batch'])) {
    error_log("تم استقبال طلب مجمّع يحتوي على " . count($data['batch']) . " موقع.");
    foreach ($data['batch'] as $single_location_data) {
        // استدعاء نفس السكربت لمعالجة كل موقع على حدة
        // هذا يتطلب أن يكون الخادم قادراً على إجراء طلبات لنفسه
        // كحل بديل وأكثر أماناً، يمكننا وضع منطق المعالجة في دالة واستدعائها
        process_location($single_location_data, $conn);
    }
    // إرسال استجابة نجاح عامة للطلب المجمّع
    echo json_encode(["status" => "success", "message" => "✅ تم معالجة الطلب المجمّع"]);
    exit;
}

// طباعة البيانات المستقبلة في سجل الأخطاء للمراقبة
error_log("البيانات المستقبلة: " . print_r($data, true));

// التحقق من وجود الحقول الأساسية المطلوبة
$required_fields = ["device_id", "device_name"];
foreach ($required_fields as $field) {
    if (!isset($data[$field])) {
        error_log("بيانات ناقصة: الحقل المطلوب '$field' غير موجود");
        http_response_code(400);
        echo json_encode(["status" => "error", "message" => "❌ بيانات ناقصة: الحقل المطلوب '$field' غير موجود"]);
        exit;
    }
}

// إضافة قيمة افتراضية لحقل status إذا لم يكن موجوداً
if (!isset($data["status"])) {
    $data["status"] = "active"; // قيمة افتراضية
    error_log("تم إضافة قيمة افتراضية لحقل status: active");
}

// التحقق من وجود إحداثيات الموقع بتنسيقات مختلفة
if (!isset($data["latitude"]) && !isset($data["lat"])) {
    $error_msg = "بيانات ناقصة: لا توجد بيانات خط العرض (latitude أو lat) للجهاز: " . ($data["device_id"] ?? 'غير محدد');
    error_log($error_msg);
    http_response_code(400);
    echo json_encode(["status" => "error", "message" => "❌ بيانات ناقصة: لا توجد بيانات خط العرض"]);
    exit;
}

if (!isset($data["longitude"]) && !isset($data["lng"])) {
    $error_msg = "بيانات ناقصة: لا توجد بيانات خط الطول (longitude أو lng) للجهاز: " . ($data["device_id"] ?? 'غير محدد');
    error_log($error_msg);
    http_response_code(400);
    echo json_encode(["status" => "error", "message" => "❌ بيانات ناقصة: لا توجد بيانات خط الطول"]);
    exit;
}

// تسجيل نجاح استقبال البيانات الأساسية
error_log("تم استقبال بيانات صحيحة للجهاز: " . $data["device_id"] . " - " . $data["device_name"]);

// 🕒 توليد التوقيت بالتنسيق العراقي (24 ساعة)
date_default_timezone_set("Asia/Baghdad");
$timestamp = date("Y-m-d H:i:s");

// ✅ استخدام وقت السيرفر (توقيت بغداد) بدلاً من توقيت الجهاز لضمان دقة الوقت في كل مكان
// نكتب هذا الوقت في حقل timestamp القادم من التطبيق لكي يتم تخزينه في قاعدة البيانات كما هو
$data['timestamp'] = $timestamp;

// ✅ التحقق من اسم الجهاز الحقيقي قبل المعالجة
$device_name = isset($data['device_name']) ? trim($data['device_name']) : '';

// ✅ التحقق من أن اسم الجهاز ليس فارغاً أو "Unknown Device" أو يساوي device_id
if (empty($device_name) || 
    $device_name === 'Unknown Device' || 
    $device_name === 'Unknown' || 
    $device_name === trim($data['device_id'])) {
    
    // ✅ إذا كان الاسم غير صالح، نحاول الحصول على الاسم الحقيقي من قاعدة البيانات
    try {
        $stmt_check = $conn->prepare("SELECT device_name FROM devices WHERE device_id = :device_id LIMIT 1");
        $stmt_check->execute([':device_id' => $data['device_id']]);
        $existing_device = $stmt_check->fetch(PDO::FETCH_ASSOC);
        
        if ($existing_device && 
            !empty(trim($existing_device['device_name'])) && 
            trim($existing_device['device_name']) !== 'Unknown Device' && 
            trim($existing_device['device_name']) !== trim($data['device_id'])) {
            // ✅ استخدام الاسم الحقيقي من قاعدة البيانات
            $device_name = trim($existing_device['device_name']);
            $data['device_name'] = $device_name;
            error_log("✅ [add_location.php] Found real device name from database: $device_name");
        } else {
            // ✅ إذا لم نجد اسم حقيقي، نستخدم القيمة المرسلة (حتى لو كانت "Unknown Device")
            // لكن لا نستخدم device_id كاسم أبداً
            $data['device_name'] = isset($data['device_name']) ? trim($data['device_name']) : 'Unknown Device';
            error_log("⚠️ [add_location.php] No real device name found, using: " . $data['device_name']);
        }
    } catch (Exception $e) {
        error_log("❌ [add_location.php] Error fetching device name from database: " . $e->getMessage());
        // ✅ في حالة الخطأ، نستخدم القيمة المرسلة
        $data['device_name'] = isset($data['device_name']) ? trim($data['device_name']) : 'Unknown Device';
    }
} else {
    // ✅ الاسم صالح، نستخدمه كما هو
    $data['device_name'] = $device_name;
    error_log("✅ [add_location.php] Using provided device name: $device_name");
}

// استدعاء دالة المعالجة الرئيسية
process_location($data, $conn);


// ✅ تم نقل منطق المعالجة إلى دالة منفصلة لدعم الطلبات الفردية والمجمّعة
function process_location($data, $conn) {
// ✅ استخدام Prepared Statements مع PDO
try {
    $conn->beginTransaction();

    // 1. تحديث أو إضافة الجهاز في جدول devices باستخدام ON DUPLICATE KEY UPDATE
    $stmt_device = $conn->prepare(
        "INSERT INTO devices (device_id, device_name, first_seen, last_seen, status) 
         VALUES (:device_id, :device_name, :ts, :ts, 'active')
         ON DUPLICATE KEY UPDATE 
         device_name = VALUES(device_name), last_seen = VALUES(last_seen), status = 'active'"
    );
    $stmt_device->execute([
        ':device_id'   => $data['device_id'],
        ':device_name' => $data['device_name'],
        ':ts'          => $data['timestamp'] ?? date("Y-m-d H:i:s") // استخدام وقت البيانات إن وجد
    ]);

    // التحقق إذا كان الجهاز جديداً لإطلاق إشارة التحديث
    if ($stmt_device->rowCount() === 1) { // 1 for INSERT, 2 for UPDATE
        file_put_contents('new_device_flag.txt', time());
        error_log("تم اكتشاف جهاز جديد: " . $data['device_name'] . " (" . $data['device_id'] . ")");
    }

    // جلب آخر موقع مسجل للجهاز لمقارنته
    $prevLocation = fetch_last_location($conn, $data['device_id']);

    $rawLatitude  = (float)($data['latitude'] ?? $data['lat'] ?? 0.0);
    $rawLongitude = (float)($data['longitude'] ?? $data['lng'] ?? 0.0);
    $currentSpeed     = isset($data['speed']) ? (float)$data['speed'] : null;
    $currentTimestamp = $data['timestamp'] ?? $data['ts'] ?? date("Y-m-d H:i:s");

    $rawDistanceFromPrev = null;
    if ($prevLocation) {
        $rawDistanceFromPrev = haversine_distance(
            (float)$prevLocation['latitude'],
            (float)$prevLocation['longitude'],
            $rawLatitude,
            $rawLongitude
        );
    }

    [$currentLatitude, $currentLongitude, $isNoisyPoint] = sanitize_coordinates(
        $prevLocation,
        $rawLatitude,
        $rawLongitude,
        $rawDistanceFromPrev,
        $data['accuracy'] ?? null
    );

    if ($isNoisyPoint) {
        $deviationText = $rawDistanceFromPrev !== null ? round($rawDistanceFromPrev, 2) . 'm' : 'unknown';
        error_log("تم تعديل نقطة تحتوي على نويز للجهاز {$data['device_id']} (انحراف {$deviationText})");
    }

    $distanceForStatus = null;
    if ($prevLocation) {
        $distanceForStatus = haversine_distance(
            (float)$prevLocation['latitude'],
            (float)$prevLocation['longitude'],
            $currentLatitude,
            $currentLongitude
        );
    }

    $statusSequence = resolve_status_sequence(
        $prevLocation,
        $currentLatitude,
        $currentLongitude,
        $currentSpeed,
        $distanceForStatus
    );

    // 2. إدراج البيانات في جدول locations بناءً على الحالة المحسوبة
    $stmt_loc = $conn->prepare(
        "INSERT INTO locations (device_id, device_name, latitude, longitude, timestamp, status, battery, speed, accuracy, altitude, heading) 
         VALUES (:device_id, :device_name, :latitude, :longitude, :timestamp, :status, :battery, :speed, :accuracy, :altitude, :heading)"
    );

    foreach ($statusSequence as $calculatedStatus) {
        $stmt_loc->execute([
            ':device_id'   => $data['device_id'],
            ':device_name' => $data['device_name'], // ✅ تم التحقق من الاسم مسبقاً
        ':latitude'    => $currentLatitude,
        ':longitude'   => $currentLongitude,
            ':timestamp'   => $currentTimestamp,
            ':status'      => $calculatedStatus,
            ':battery'     => $data['battery'] ?? null,
            ':speed'       => $currentSpeed,
            ':accuracy'    => $data['accuracy'] ?? null,
            ':altitude'    => $data['altitude'] ?? null,
            ':heading'     => $data['heading'] ?? null
        ]);
    }

    $conn->commit();

    http_response_code(201); // Created
    echo json_encode([
        "status"  => "success",
        "message" => "✅ تم حفظ الموقع بنجاح",
        "states"  => $statusSequence
    ]);
    error_log("تم حفظ الموقع بنجاح للجهاز: " . $data['device_name'] . " بالحالات: " . implode(',', $statusSequence));

} catch (PDOException $e) {
    if ($conn->inTransaction()) {
        $conn->rollBack();
    }
    error_log("خطأ في إدراج البيانات (PDO): " . $e->getMessage());
    http_response_code(500);
    echo json_encode(["status" => "error", "message" => "❌ خطأ في حفظ البيانات في الخادم"]);
}
}

/**
 * جلب آخر موقع مسجل للجهاز.
 */
function fetch_last_location(PDO $conn, $deviceId) {
    $stmt = $conn->prepare(
        "SELECT latitude, longitude, status, timestamp 
         FROM locations 
         WHERE device_id = :device_id 
         ORDER BY timestamp DESC 
         LIMIT 1"
    );
    $stmt->execute([':device_id' => $deviceId]);
    return $stmt->fetch(PDO::FETCH_ASSOC) ?: null;
}

/**
 * حساب المسافة بين موقعين بالمتر باستخدام معادلة هافرسين.
 */
function haversine_distance($lat1, $lon1, $lat2, $lon2) {
    $earthRadius = 6371000; // بالمتر

    $dLat = deg2rad($lat2 - $lat1);
    $dLon = deg2rad($lon2 - $lon1);

    $a = sin($dLat / 2) * sin($dLat / 2) +
         cos(deg2rad($lat1)) * cos(deg2rad($lat2)) *
         sin($dLon / 2) * sin($dLon / 2);

    $c = 2 * atan2(sqrt($a), sqrt(1 - $a));

    return $earthRadius * $c;
}

/**
 * تحديد تسلسل الحالات الواجب تخزينها (حركة/توقف) بعد تنقية الإحداثيات.
 */
function resolve_status_sequence($prevLocation, $currentLat, $currentLon, $currentSpeed, $distanceTravelled = null) {
    $stopSpeedThreshold    = 1;   // متر/ثانية تقريباً
    $stopDistanceThreshold = 10;  // أمتار

    if ($distanceTravelled === null && $prevLocation) {
        $distanceTravelled = haversine_distance(
            (float)$prevLocation['latitude'],
            (float)$prevLocation['longitude'],
            $currentLat,
            $currentLon
        );
    }

    $wasStopped  = $prevLocation && in_array($prevLocation['status'], ['stop_enter', 'stop_hold'], true);
    $isSpeedLow  = $currentSpeed !== null && $currentSpeed < $stopSpeedThreshold;
    $isDistanceLow = $distanceTravelled !== null && $distanceTravelled < $stopDistanceThreshold;

    // نعتبر الجهاز متوقف إذا كان البطء واضحاً أو لم يقطع مسافة تذكر
    $isStationary = $isSpeedLow || $isDistanceLow;

    if ($isStationary) {
        return $wasStopped ? ['stop_hold'] : ['stop_enter'];
    }

    if ($wasStopped) {
        return ['stop_exit', 'move'];
    }

    return ['move'];
}

/**
 * تنقية الإحداثيات للتخلص من النويز الناتج عن انحرافات صغيرة أو دقة ضعيفة.
 */
function sanitize_coordinates($prevLocation, $rawLat, $rawLon, $rawDistanceFromPrev, $accuracy) {
    $lat = $rawLat;
    $lon = $rawLon;
    $isNoisy = false;

    if ($prevLocation) {
        $accuracyValue = $accuracy !== null ? (float)$accuracy : null;

        $isMinorDrift = $rawDistanceFromPrev !== null && $rawDistanceFromPrev < NOISE_DISTANCE_THRESHOLD;
        $isLowAccuracy = $accuracyValue !== null && $accuracyValue > NOISE_ACCURACY_THRESHOLD;

        if ($isMinorDrift || $isLowAccuracy) {
            $lat = (float)$prevLocation['latitude'];
            $lon = (float)$prevLocation['longitude'];
            $isNoisy = true;
        }
    }

    return [$lat, $lon, $isNoisy];
}
