<?php
//Prevents caching → Adds headers to ensure fresh response.
// to test this page http://192.168.1.127/html/launcher.php?type=get_config_scripts_sqlite
header("Content-Type: application/json");
header("Cache-Control: no-store, no-cache, must-revalidate, max-age=0");
header("Pragma: no-cache");

$database_path = "/var/www/nebuleair_pro_4g/sqlite/sensors.db";


$type=$_GET['type'];

if ($type == "get_npm_sqlite_data") {
    //echo "Getting data from sqlite database";
    try {
        $db = new PDO("sqlite:$database_path");
        $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    
        // Fetch the last 30 records
        $stmt = $db->query("SELECT timestamp, PM1, PM25, PM10 FROM data_NPM ORDER BY timestamp DESC LIMIT 30");
        $data = $stmt->fetchAll(PDO::FETCH_ASSOC);
        $reversedData = array_reverse($data); // Reverse the order

    
        echo json_encode($reversedData);
    } catch (PDOException $e) {
        echo json_encode(["error" => $e->getMessage()]);
    }
}

/*

*/
//GETING data from config_table (SQLite DB)
if ($type == "get_config_sqlite") {
    try {
        $db = new PDO("sqlite:$database_path");
        $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        
        // Get all main configuration entries
        $config_query = $db->query("SELECT key, value, type FROM config_table");
        $config_data = $config_query->fetchAll(PDO::FETCH_ASSOC);
        
        // Convert data types according to their 'type' field
        $result = [];
        foreach ($config_data as $item) {
            $key = $item['key'];
            $value = $item['value'];
            $type = $item['type'];
            
            // Convert value based on its type
            switch ($type) {
                case 'bool':
                    $parsed_value = ($value == '1' || $value == 'true') ? true : false;
                    break;
                case 'int':
                    $parsed_value = intval($value);
                    break;
                case 'float':
                    $parsed_value = floatval($value);
                    break;
                default:
                    $parsed_value = $value;
            }
            
            $result[$key] = $parsed_value;
        }
        
        // Return JSON response
        header('Content-Type: application/json');
        echo json_encode($result, JSON_PRETTY_PRINT);

    } catch (PDOException $e) {
        // Return error as JSON
        header('Content-Type: application/json');
        echo json_encode(['error' => 'Database error: ' . $e->getMessage()]);
    }
}

// GET language preference from SQLite
if ($type == "get_language") {
    try {
        $db = new PDO("sqlite:$database_path");
        $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

        $stmt = $db->prepare("SELECT value FROM config_table WHERE key = 'language'");
        $stmt->execute();
        $result = $stmt->fetch(PDO::FETCH_ASSOC);

        $language = $result ? $result['value'] : 'fr'; // Default to French
        echo json_encode(['language' => $language]);
    } catch (Exception $e) {
        echo json_encode(['language' => 'fr', 'error' => $e->getMessage()]);
    }
}

// SET language preference in SQLite
if ($type == "set_language") {
    $language = $_GET['language'];

    // Validate language (only allow fr or en)
    if (!in_array($language, ['fr', 'en'])) {
        echo json_encode(['success' => false, 'error' => 'Invalid language']);
        exit;
    }

    try {
        $db = new PDO("sqlite:$database_path");
        $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

        $stmt = $db->prepare("UPDATE config_table SET value = ? WHERE key = 'language'");
        $stmt->execute([$language]);

        echo json_encode(['success' => true, 'language' => $language]);
    } catch (Exception $e) {
        echo json_encode(['success' => false, 'error' => $e->getMessage()]);
    }
}

/*

*/
//GETING data from config_scrips_table (SQLite DB)
if ($type == "get_config_scripts_sqlite") {

    try {
        $db = new PDO("sqlite:$database_path");
        $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        
        // Get all main configuration entries
        $config_query = $db->query("SELECT * FROM config_scripts_table");
        $config_data = $config_query->fetchAll(PDO::FETCH_ASSOC);
        
        // Convert data types according to their 'type' field
        $result = [];
        foreach ($config_data as $item) {
            $script_path = $item['script_path'];
            $enabled = $item['enabled'];
            
            // Convert the enabled field to a proper boolean
            $result[$script_path] = ($enabled == 1);
        }
        
        // Return JSON response
        header('Content-Type: application/json');
        echo json_encode($result, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
        
    } catch (PDOException $e) {
        // Return error as JSON
        header('Content-Type: application/json');
        echo json_encode(['error' => 'Database error: ' . $e->getMessage()]);
    }

}

/*

*/
//GETING data from envea_sondes_table (SQLite DB)
if ($type == "get_envea_sondes_table_sqlite") {

    try {
        $db = new PDO("sqlite:$database_path");
        $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        
         // Get all entries from envea_sondes_table
         $query = $db->query("SELECT id, connected, port, name, coefficient FROM envea_sondes_table");
         $data = $query->fetchAll(PDO::FETCH_ASSOC);
        
        // Convert data types appropriately
        $result = [];
        foreach ($data as $item) {
            // Create object for each sonde with proper data types
            $sonde = [
                'id' => (int)$item['id'],
                'connected' => $item['connected'] == 1,  // Convert to boolean
                'port' => $item['port'],
                'name' => $item['name'],
                'coefficient' => (float)$item['coefficient']  // Convert to float
            ];
            
            // Add to results array
            $result[] = $sonde;
        }
        
        
        // Return JSON response
        header('Content-Type: application/json');
        echo json_encode($result, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
        
    } catch (PDOException $e) {
        // Return error as JSON
        header('Content-Type: application/json');
        echo json_encode(['error' => 'Database error: ' . $e->getMessage()]);
    }

}




//UPDATING the config_table from SQLite DB
if ($type == "update_config_sqlite") {
    $param = $_GET['param'] ?? null;
    $value = $_GET['value'] ?? null;
    
    if ($param === null || $value === null) {
        echo json_encode(["error" => "Missing parameter or value"]);
        exit;
    }
    
    try {
        $db = new PDO("sqlite:$database_path");
        $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        
        // First, check if parameter exists and get its type
        $checkStmt = $db->prepare("SELECT type FROM config_table WHERE key = :param");
        $checkStmt->bindParam(':param', $param);
        $checkStmt->execute();
        $result = $checkStmt->fetch(PDO::FETCH_ASSOC);
        
        if ($result) {
            // Parameter exists, determine type and update
            $type = $result['type'];
            
            // Convert value according to type if needed
            $convertedValue = $value;
            if ($type == "bool") {
                // Convert various boolean representations to 0/1
                $convertedValue = (filter_var($value, FILTER_VALIDATE_BOOLEAN)) ? "1" : "0";
            } elseif ($type == "int") {
                $convertedValue = (string)intval($value);
            } elseif ($type == "float") {
                $convertedValue = (string)floatval($value);
            }
            
            // Update the value
            $updateStmt = $db->prepare("UPDATE config_table SET value = :value WHERE key = :param");
            $updateStmt->bindParam(':value', $convertedValue);
            $updateStmt->bindParam(':param', $param);
            $updateStmt->execute();
            
            echo json_encode([
                "success" => true,
                "message" => "Configuration updated successfully",
                "param" => $param,
                "value" => $convertedValue,
                "type" => $type
            ]);
        } else {
            echo json_encode([
                "error" => "Parameter not found in configuration",
                "param" => $param
            ]);
        }
    } catch (PDOException $e) {
        echo json_encode(["error" => $e->getMessage()]);
    }
}


//UPDATING the envea_sondes_table table from SQLite DB
if ($type == "update_sonde") {
    $id = $_GET['id'] ?? null;
    $field = $_GET['field'] ?? null;
    $value = $_GET['value'] ?? null;
    
   // Validate parameters
    if ($id === null || $field === null || $value === null) {
        echo json_encode([
            "success" => false,
            "error" => "Missing required parameters (id, field, or value)"
        ]);
        exit;
    }

    // Validate field name (whitelist approach for security)
    $allowed_fields = ['connected', 'port', 'name', 'coefficient'];
    if (!in_array($field, $allowed_fields)) {
        echo json_encode([
            "success" => false,
            "error" => "Invalid field name: " . $field
        ]);
        exit;
    }

    try {
        // Connect to the database
        $db = new PDO("sqlite:$database_path");
        $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        
        // Check if the sonde exists
        $checkStmt = $db->prepare("SELECT id FROM envea_sondes_table WHERE id = :id");
        $checkStmt->bindParam(':id', $id, PDO::PARAM_INT);
        $checkStmt->execute();
        
        if (!$checkStmt->fetch()) {
            echo json_encode([
                "success" => false,
                "error" => "Sonde with ID $id not found"
            ]);
            exit;
        }
        
        // Process value based on field type
        if ($field == 'connected') {
            // Convert to integer (0 or 1)
            $processedValue = filter_var($value, FILTER_VALIDATE_BOOLEAN) ? 1 : 0;
            $paramType = PDO::PARAM_INT;
        } else if ($field == 'coefficient') {
            // Convert to float
            $processedValue = floatval($value);
            $paramType = PDO::PARAM_STR; // SQLite doesn't have PARAM_FLOAT
        } else {
            // For text fields (port, name)
            $processedValue = $value;
            $paramType = PDO::PARAM_STR;
        }
        
        // Update the sonde record
        $updateStmt = $db->prepare("UPDATE envea_sondes_table SET $field = :value WHERE id = :id");
        $updateStmt->bindParam(':value', $processedValue, $paramType);
        $updateStmt->bindParam(':id', $id, PDO::PARAM_INT);
        $updateStmt->execute();
        
        // Return success response
        echo json_encode([
            "success" => true,
            "message" => "Sonde $id updated successfully",
            "field" => $field,
            "value" => $processedValue
        ]);
        
    } catch (PDOException $e) {
        // Return error as JSON
        echo json_encode([
            "success" => false,
            "error" => "Database error: " . $e->getMessage()
        ]);
    }
}

//update the config (old JSON updating)
if ($type == "update_config") {
    echo "updating.... ";
    $param=$_GET['param'];
    $value=$_GET['value'];
    $configFile = '../config.json';
    // Convert value to boolean, integer, or string
    if ($value === "true") {
        $value = true; // Convert "true" string to boolean true
    } elseif ($value === "false") {
        $value = false; // Convert "false" string to boolean false
    } elseif (is_numeric($value)) {
        $value = $value + 0; // Convert numeric strings to int or float
    }
    $configData = json_decode(file_get_contents($configFile), true);
    $configData[$param] = $value;
    file_put_contents($configFile, json_encode($configData, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));
    echo "Config updated!";
}

if ($type == "getModem_busy") {
    $command = 'sudo /usr/bin/python3 /var/www/nebuleair_pro_4g/SARA/check_running.py';
    $output = shell_exec($command);
    echo $output;
}

if ($type == "RTC_time") {
    $time = shell_exec("date '+%d/%m/%Y %H:%M:%S'");
    echo $time;
}

if ($type == "sys_RTC_module_time") {
    $command = 'sudo /usr/bin/python3 /var/www/nebuleair_pro_4g/RTC/read.py';
    $output = shell_exec($command);
    echo $output;
}

if ($type == "sara_ping") {
    $command = 'sudo /usr/bin/python3 /var/www/nebuleair_pro_4g/SARA/sara_ping.py';
    $output = shell_exec($command);
    echo $output;
}

if ($type == "sara_psd_setup") {
    $command = 'sudo /usr/bin/python3 /var/www/nebuleair_pro_4g/SARA/R5/setPDP.py';
    $output = shell_exec($command);
    echo $output;
}

if ($type == "sara_test_udp") {
    $command = 'sudo /usr/bin/python3 -u /var/www/nebuleair_pro_4g/SARA/sara_test_udp.py';
    $output = shell_exec($command);
    echo $output;
}

if ($type == "sara_ping_miotiq") {
    $command = 'sudo /usr/bin/python3 -u /var/www/nebuleair_pro_4g/SARA/sara_ping_miotiq.py';
    $output = shell_exec($command);
    echo $output;
}

if ($type == "sara_check_pdp") {
    $command = 'sudo /usr/bin/python3 -u /var/www/nebuleair_pro_4g/SARA/sara_check_pdp.py';
    $output = shell_exec($command);
    echo $output;
}


if ($type == "git_pull") {
    $command = 'sudo git pull';
    $output = shell_exec($command);
    echo $output;
}

if ($type == "update_firmware") {
    // Execute the comprehensive update script
    $command = 'sudo /var/www/nebuleair_pro_4g/update_firmware.sh 2>&1';
    $output = shell_exec($command);
    
    // Return the output as JSON for better web display
    header('Content-Type: application/json');
    echo json_encode([
        'success' => true,
        'output' => $output,
        'timestamp' => date('Y-m-d H:i:s')
    ]);
}

if ($type == "upload_firmware") {
    // Firmware update via ZIP file upload (offline mode)
    if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
        echo json_encode(['success' => false, 'message' => 'POST method required']);
        exit;
    }

    // Check file upload
    if (!isset($_FILES['firmware_file']) || $_FILES['firmware_file']['error'] !== UPLOAD_ERR_OK) {
        $max_upload = ini_get('upload_max_filesize');
        $upload_errors = [
            UPLOAD_ERR_INI_SIZE => "Le fichier depasse la limite serveur (actuellement $max_upload). Effectuez d'abord une mise a jour via WiFi (bouton Update firmware) pour debloquer l'upload hors-ligne.",
            UPLOAD_ERR_FORM_SIZE => 'File exceeds form upload limit',
            UPLOAD_ERR_PARTIAL => 'File was only partially uploaded',
            UPLOAD_ERR_NO_FILE => 'No file was uploaded',
            UPLOAD_ERR_NO_TMP_DIR => 'Missing temporary folder',
            UPLOAD_ERR_CANT_WRITE => 'Failed to write file to disk',
        ];
        $error_code = $_FILES['firmware_file']['error'] ?? UPLOAD_ERR_NO_FILE;
        $error_msg = $upload_errors[$error_code] ?? 'Unknown upload error';
        echo json_encode(['success' => false, 'message' => $error_msg]);
        exit;
    }

    $file = $_FILES['firmware_file'];

    // Validate extension
    $ext = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
    if ($ext !== 'zip') {
        echo json_encode(['success' => false, 'message' => 'Only .zip files are allowed']);
        exit;
    }

    // Validate size (50MB max)
    if ($file['size'] > 50 * 1024 * 1024) {
        echo json_encode(['success' => false, 'message' => 'File too large (max 50MB)']);
        exit;
    }

    // Get current version before update
    $old_version = 'unknown';
    if (file_exists('/var/www/nebuleair_pro_4g/VERSION')) {
        $old_version = trim(file_get_contents('/var/www/nebuleair_pro_4g/VERSION'));
    }

    // Prepare extraction directory
    $tmp_dir = '/tmp/nebuleair_update';
    $extract_dir = "$tmp_dir/extracted";
    shell_exec("rm -rf $tmp_dir");
    mkdir($extract_dir, 0755, true);

    // Move uploaded file
    $zip_path = "$tmp_dir/firmware.zip";
    if (!move_uploaded_file($file['tmp_name'], $zip_path)) {
        echo json_encode(['success' => false, 'message' => 'Failed to move uploaded file']);
        exit;
    }

    // Extract ZIP
    $unzip_output = shell_exec("unzip -o '$zip_path' -d '$extract_dir' 2>&1");

    // Detect project root folder (Gitea creates nebuleair_pro_4g-main/ inside the zip)
    $source_dir = $extract_dir;
    $entries = scandir($extract_dir);
    $subdirs = array_filter($entries, function($e) use ($extract_dir) {
        return $e !== '.' && $e !== '..' && is_dir("$extract_dir/$e");
    });

    if (count($subdirs) === 1) {
        $subdir = reset($subdirs);
        $candidate = "$extract_dir/$subdir";
        if (file_exists("$candidate/VERSION")) {
            $source_dir = $candidate;
        }
    }

    // Validate VERSION exists in the archive
    if (!file_exists("$source_dir/VERSION")) {
        shell_exec("rm -rf $tmp_dir");
        echo json_encode(['success' => false, 'message' => 'Invalid archive: VERSION file not found']);
        exit;
    }

    $new_version = trim(file_get_contents("$source_dir/VERSION"));

    // Execute update script
    $command = "sudo /var/www/nebuleair_pro_4g/update_firmware_from_file.sh '$source_dir' 2>&1";
    $output = shell_exec($command);

    // Cleanup (also done in script, but just in case)
    shell_exec("rm -rf $tmp_dir");

    echo json_encode([
        'success' => true,
        'output' => $output,
        'old_version' => $old_version,
        'new_version' => $new_version,
        'timestamp' => date('Y-m-d H:i:s')
    ]);
    exit;
}

if ($type == "set_RTC_withNTP") {
    $command = 'sudo /usr/bin/python3 /var/www/nebuleair_pro_4g/RTC/set_with_NTP.py';
    $output = shell_exec($command);
    echo $output;
}

if ($type == "set_RTC_withBrowser") {
    $time = $_GET['time'];
    // Validate time format
    if (!strtotime($time)) {
        echo json_encode(['success' => false, 'message' => 'Invalid time format']);
        exit;
    }
    // Convert to RTC-compatible format (e.g., 'YYYY-MM-DD HH:MM:SS')
    $rtc_time = date('Y-m-d H:i:s', strtotime($time));

     // Execute Python script to update the RTC
    $command = escapeshellcmd("sudo /usr/bin/python3 /var/www/nebuleair_pro_4g/RTC/set_with_browserTime.py '$rtc_time'");
    $output = shell_exec($command);
    if ($output === null) {
        echo json_encode(['success' => false, 'message' => 'Failed to update RTC']);
    } else {
        echo json_encode(['success' => true, 'message' => 'RTC updated successfully']);
    }
}


if ($type == "clear_loopLogs") {
    $response = array();
    
    try {
        $logPath = '/var/www/nebuleair_pro_4g/logs/master.log';
        
        // Check if file exists and is writable
        if (!file_exists($logPath)) {
            throw new Exception("Log file does not exist");
        }
        
        if (!is_writable($logPath)) {
            throw new Exception("Log file is not writable");
        }
        
        // Execute the command
        $command = 'truncate -s 0 ' . escapeshellarg($logPath);
        $output = shell_exec($command . ' 2>&1');
        
        // Check if there was any error output
        if (!empty($output)) {
            throw new Exception("Command error: " . $output);
        }
        
        // Success response
        $response = array(
            'status' => 'success',
            'message' => 'Logs cleared successfully',
            'timestamp' => date('Y-m-d H:i:s')
        );
    } catch (Exception $e) {
        // Error response
        $response = array(
            'status' => 'error',
            'message' => $e->getMessage(),
            'timestamp' => date('Y-m-d H:i:s')
        );
    }
    
    // Set content type to JSON
    header('Content-Type: application/json');
    
    // Return the JSON response
    echo json_encode($response);
    exit;
}

if ($type == "database_size") {
    
    // Path to the SQLite database file
    $databasePath = '/var/www/nebuleair_pro_4g/sqlite/sensors.db';

    // Check if the file exists
    if (file_exists($databasePath)) {
        try {
            // Connect to the SQLite database
            $db = new PDO("sqlite:$databasePath");

            // Get the file size in bytes
            $fileSizeBytes = filesize($databasePath);

            // Convert the file size to human-readable formats
            $fileSizeKilobytes = $fileSizeBytes / 1024;  // KB
            $fileSizeMegabytes = $fileSizeKilobytes / 1024;  // MB


            // Prepare the JSON response
            $data = [
                'path' => $databasePath,
                'size_bytes' => $fileSizeBytes,
                'size_kilobytes' => round($fileSizeKilobytes, 2),
                'size_megabytes' => round($fileSizeMegabytes, 2),
            ];

            // Output the JSON response
            echo json_encode($data, JSON_PRETTY_PRINT);
        } catch (PDOException $e) {
            // Handle database connection errors
            echo json_encode([
                'error' => 'Database query failed: ' . $e->getMessage()
            ]);
        }
    } else {
        // Handle error if the file doesn't exist
        echo json_encode([
            'error' => 'Database file not found',
            'path' => $databasePath
        ]);
}
  
    
}

if ($type == "db_table_stats") {
    $databasePath = '/var/www/nebuleair_pro_4g/sqlite/sensors.db';

    if (file_exists($databasePath)) {
        try {
            $db = new PDO("sqlite:$databasePath");

            // Database file size
            $fileSizeBytes = filesize($databasePath);
            $fileSizeMB = round($fileSizeBytes / (1024 * 1024), 2);

            // Sensor data tables to inspect
            $tables = ['data_NPM', 'data_NPM_5channels', 'data_BME280', 'data_envea', 'data_WIND', 'data_MPPT', 'data_NOISE', 'data_MHZ19'];

            $tableStats = [];
            foreach ($tables as $tableName) {
                // Check if table exists
                $check = $db->query("SELECT name FROM sqlite_master WHERE type='table' AND name='$tableName'");
                if ($check->fetch()) {
                    $countResult = $db->query("SELECT COUNT(*) as cnt FROM $tableName")->fetch();
                    $count = (int)$countResult['cnt'];

                    $oldest = null;
                    $newest = null;
                    if ($count > 0) {
                        // Exclude 'not connected' rows: these are sensor readings collected
                        // while the RTC service was down. They are lexicographically > real
                        // timestamps so they corrupt MAX() (and MIN() too, less obviously).
                        $oldestResult = $db->query("SELECT MIN(timestamp) as ts FROM $tableName WHERE timestamp != 'not connected'")->fetch();
                        $newestResult = $db->query("SELECT MAX(timestamp) as ts FROM $tableName WHERE timestamp != 'not connected'")->fetch();
                        $oldest = $oldestResult['ts'];
                        $newest = $newestResult['ts'];
                    }

                    $tableStats[] = [
                        'name' => $tableName,
                        'count' => $count,
                        'oldest' => $oldest,
                        'newest' => $newest
                    ];
                }
            }

            echo json_encode([
                'success' => true,
                'size_mb' => $fileSizeMB,
                'size_bytes' => $fileSizeBytes,
                'tables' => $tableStats
            ]);
        } catch (PDOException $e) {
            echo json_encode(['success' => false, 'error' => 'Database query failed: ' . $e->getMessage()]);
        }
    } else {
        echo json_encode(['success' => false, 'error' => 'Database file not found']);
    }
}

if ($type == "download_full_table") {
    $databasePath = '/var/www/nebuleair_pro_4g/sqlite/sensors.db';
    $table = $_GET['table'] ?? '';

    // Whitelist of allowed tables
    $allowedTables = ['data_NPM', 'data_NPM_5channels', 'data_BME280', 'data_envea', 'data_WIND', 'data_MPPT', 'data_NOISE', 'data_MHZ19'];

    if (!in_array($table, $allowedTables)) {
        header('Content-Type: application/json');
        echo json_encode(['error' => 'Invalid table name']);
        exit;
    }

    // CSV headers per table
    $csvHeaders = [
        'data_NPM' => 'TimestampUTC,PM1,PM2.5,PM10,Temperature_sensor,Humidity_sensor',
        'data_NPM_5channels' => 'TimestampUTC,PM_ch1,PM_ch2,PM_ch3,PM_ch4,PM_ch5',
        'data_BME280' => 'TimestampUTC,Temperature,Humidity,Pressure',
        'data_envea' => 'TimestampUTC,NO2,H2S,NH3,CO,O3,SO2',
        'data_WIND' => 'TimestampUTC,Wind_speed_kmh,Wind_direction_V',
        'data_MPPT' => 'TimestampUTC,Battery_voltage,Battery_current,Solar_voltage,Solar_power,Charger_status',
        'data_NOISE' => 'TimestampUTC,Current_LEQ,DB_A_value',
        'data_MHZ19' => 'TimestampUTC,CO2_ppm'
    ];

    try {
        $db = new PDO("sqlite:$databasePath");
        $rows = $db->query("SELECT * FROM $table ORDER BY timestamp ASC")->fetchAll(PDO::FETCH_NUM);

        header('Content-Type: text/csv; charset=utf-8');
        header('Content-Disposition: attachment; filename="' . $table . '_full.csv"');

        $output = fopen('php://output', 'w');
        // Write header
        fputcsv($output, explode(',', $csvHeaders[$table]));
        // Write data rows
        foreach ($rows as $row) {
            fputcsv($output, $row);
        }
        fclose($output);
    } catch (PDOException $e) {
        header('Content-Type: application/json');
        echo json_encode(['error' => 'Database query failed: ' . $e->getMessage()]);
    }
    exit;
}

if ($type == "linux_disk") {
    $command = 'df -h /';
    $output = shell_exec($command);
    echo $output;
}

if ($type == "linux_memory") {
    $command = 'free -h';
    $output = shell_exec($command);
    echo $output;
}

if ($type == "wifi_status") {
    header('Content-Type: application/json');

    $result = array(
        'connected' => false,
        'mode' => 'unknown',
        'ssid' => '',
        'ip' => '',
        'hostname' => ''
    );

    // Get hostname
    $result['hostname'] = trim(shell_exec('hostname'));

    // Get wlan0 connection info
    $connection = trim(shell_exec("nmcli -t -f GENERAL.CONNECTION device show wlan0 2>/dev/null | cut -d: -f2"));

    if (!empty($connection) && $connection != '--') {
        $result['connected'] = true;
        $result['ssid'] = $connection;

        // Check if it's a hotspot
        if (strpos(strtolower($connection), 'hotspot') !== false || strpos($connection, 'nebuleair') !== false) {
            $result['mode'] = 'hotspot';
        } else {
            $result['mode'] = 'wifi';
        }

        // Get IP address
        $ip = trim(shell_exec("nmcli -t -f IP4.ADDRESS device show wlan0 2>/dev/null | head -1 | cut -d: -f2 | cut -d/ -f1"));
        if (!empty($ip)) {
            $result['ip'] = $ip;
        }
    } else {
        // Check if eth0 is connected
        $eth_ip = trim(shell_exec("nmcli -t -f IP4.ADDRESS device show eth0 2>/dev/null | head -1 | cut -d: -f2 | cut -d/ -f1"));
        if (!empty($eth_ip)) {
            $result['connected'] = true;
            $result['mode'] = 'ethernet';
            $result['ssid'] = 'Ethernet';
            $result['ip'] = $eth_ip;
        }
    }

    echo json_encode($result);
}

if ($type == "sshTunnel") {
    $ssh_port=$_GET['ssh_port'];
    $command = 'sudo ssh -i /var/www/.ssh/id_rsa -f -N -R "'.$ssh_port.':localhost:22" -p 50221 -o StrictHostKeyChecking=no "airlab_server1@aircarto.fr"';
    $output = shell_exec($command);
    echo $output;
}

if ($type == "reboot") {
    $command = 'sudo reboot';
    $output = shell_exec($command);
}

if ($type == "npm") {
    $command = 'sudo /usr/bin/python3 /var/www/nebuleair_pro_4g/NPM/get_data_modbus_v3.py --dry-run';
    $output = shell_exec($command);
    echo $output;
}

if ($type == "npm_firmware") {
    $port=$_GET['port'];
    $command = 'sudo /usr/bin/python3 /var/www/nebuleair_pro_4g/NPM/firmware_version.py ' . $port;
    $output = shell_exec($command);
    echo $output;
}

if ($type == "envea") {
    $port=$_GET['port'];
    $name=$_GET['name'];
    $command = 'sudo /usr/bin/python3 /var/www/nebuleair_pro_4g/envea/read_value.py ' . $port;
    $output = shell_exec($command);
    echo $output;
}

if ($type == "envea_debug") {
    $command = 'sudo /usr/bin/python3 /var/www/nebuleair_pro_4g/envea/read_value_v2.py -d 2>&1';
    $output = shell_exec($command);
    echo $output;
}

if ($type == "noise") {
    $command = 'sudo /usr/bin/python3 /var/www/nebuleair_pro_4g/sound_meter/read.py';
    $output = shell_exec($command);
    echo $output;
}

if ($type == "BME280") {
    $command = 'sudo /usr/bin/python3 /var/www/nebuleair_pro_4g/BME280/read.py';
    $output = shell_exec($command);
    echo $output;
}

if ($type == "mhz19") {
    $command = 'sudo /usr/bin/python3 /var/www/nebuleair_pro_4g/MH-Z19/get_data.py ttyAMA4';
    $output = shell_exec($command);
    echo $output;
}


if ($type == "table_mesure") {
    $table=$_GET['table'];
    $limit=$_GET['limit'];
    $download=$_GET['download'];

    if ($download==="false") {
        $command = 'sudo /usr/bin/python3 /var/www/nebuleair_pro_4g/sqlite/read.py '.$table.' '.$limit;
        $output = shell_exec($command);
        echo $output;
    } else{
        $start_date=$_GET['start_date'];
        $end_date=$_GET['end_date'];
        $command = 'sudo /usr/bin/python3 /var/www/nebuleair_pro_4g/sqlite/read_select_date.py '.$table.' '.$start_date.' '.$end_date;
        $output = shell_exec($command);
        echo $output;
    }

}

# SARA R4 COMMANDS
if ($type == "sara") {
    $port=$_GET['port'];
    $sara_command=$_GET['command'];
    $sara_command = escapeshellcmd($sara_command);
    $timeout=$_GET['timeout'];
    $command = 'sudo /usr/bin/python3 /var/www/nebuleair_pro_4g/SARA/sara.py ' . $port . ' ' . $sara_command . ' ' . $timeout;
    $output = shell_exec($command);
    echo $output;
}

# SARA HARDWARE REBOOT (GPIO 16)
if ($type == "sara_hardware_reboot") {
    $command = 'sudo /usr/bin/python3 /var/www/nebuleair_pro_4g/SARA/reboot/hardware_reboot.py';
    $output = shell_exec($command);
    echo $output;
}

# SARA R4 COMMANDS (MQTT)
if ($type == "sara_getMQTT_config") {
    $port=$_GET['port'];
    $timeout=$_GET['timeout'];
    $command = '/usr/bin/python3 /var/www/nebuleair_pro_4g/SARA/MQTT/get_config.py ' . $port .  ' ' . $timeout;
    $output = shell_exec($command);
    echo $output;
}

# SARA R4 COMMANDS (MQTT)
if ($type == "sara_getMQTT_login_logout") {
    $port=$_GET['port'];
    $timeout=$_GET['timeout'];
    $login_logout=$_GET['login_logout'];
    $command = 'sudo /usr/bin/python3 /var/www/nebuleair_pro_4g/SARA/MQTT/login_logout.py ' . $port .  ' ' . $login_logout .  ' ' . $timeout;
    $output = shell_exec($command);
    echo $output;
}

# SARA R4 COMMANDS (MQTT -> publish)
if ($type == "sara_MQTT_publish") {
    $port=$_GET['port'];
    $timeout=$_GET['timeout'];
    $message=$_GET['message'];
    $command = 'sudo /usr/bin/python3 /var/www/nebuleair_pro_4g/SARA/MQTT/publish.py ' . $port .  ' ' . $message .  ' ' . $timeout;
    $output = shell_exec($command);
    echo $output;
}

#Connect to network
if ($type == "sara_connectNetwork") {
    $port=$_GET['port'];
    $timeout=$_GET['timeout'];
    $networkID=$_GET['networkID'];
    $param="SARA_R4_neworkID";

    //echo "updating SARA_R4_networkID in config file";

    //OLD way to store data (JSON file)

    // Convert `networkID` to an integer (or float if needed)
    //$networkID = is_numeric($networkID) ? (strpos($networkID, '.') !== false ? (float)$networkID : (int)$networkID) : 0;
    #save to config.json
    //$configFile = '/var/www/nebuleair_pro_4g/config.json';
    // Read the JSON file
    //$jsonData = file_get_contents($configFile);
    // Decode JSON data into an associative array
    //$config = json_decode($jsonData, true);
    // Check if decoding was successful
    //if ($config === null) {
    //    die("Error: Could not decode JSON file.");
    //}
    // Update the value of SARA_R4_networkID
    //$config['SARA_R4_neworkID'] = $networkID; // Replace 42 with the desired value
    // Encode the array back to JSON with pretty printing
    //$newJsonData = json_encode($config, JSON_PRETTY_PRINT);
    // Check if encoding was successful
    //if ($newJsonData === false) {
    //    die("Error: Could not encode JSON data.");
    //}

    // Write the updated JSON back to the file
    //if (file_put_contents($configFile, $newJsonData) === false) {
    //    die("Error: Could not write to JSON file.");
    //}

    //echo "SARA_R4_networkID updated successfully.";

    //NEW way to store data -> use SQLITE
    try {
        $db = new PDO("sqlite:$database_path");
        $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

        $updateStmt = $db->prepare("UPDATE config_table SET value = :value WHERE key = :param");
        $updateStmt->bindParam(':value', $networkID);
        $updateStmt->bindParam(':param', $param);
        $updateStmt->execute();
        echo "SARA_R4_networkID updated successfully.";

    } catch (PDOException $e) {
        // Return error as JSON
        header('Content-Type: application/json');
        echo json_encode(['error' => 'Database error: ' . $e->getMessage()]);
    }

    //echo "connecting to network... please wait...";
    $command = 'sudo /usr/bin/python3 /var/www/nebuleair_pro_4g/SARA/sara_connectNetwork.py ' . $port . ' ' . $networkID . ' ' . $timeout;
    $output = shell_exec($command);
    echo $output;

    
}

#Setup Hostnmae
if ($type == "sara_setupHostname") {
    $port=$_GET['port'];
    $server_hostname=$_GET['networkID'];
    $profileID=$_GET['profileID'];

    //echo "connecting to network... please wait...";
    $command = 'sudo /usr/bin/python3 /var/www/nebuleair_pro_4g/SARA/sara_setURL.py ' . $port . ' ' . $server_hostname . ' ' . $profileID;
    $output = shell_exec($command);
    echo $output;

    
}

#SET THE URL for messaging (profile id 2)
if ($type == "sara_setURL") {
    $port=$_GET['port'];
    $url=$_GET['url'];
    $profile_id = 2;
    $command = 'sudo /usr/bin/python3 /var/www/nebuleair_pro_4g/SARA/sara_setURL.py ' . $port . ' ' . $url . ' ' . $profile_id;
    $output = shell_exec($command);
    echo $output;
}

#SET APN
if ($type == "sara_APN") {
    $port=$_GET['port'];
    $timeout=$_GET['timeout'];
    $APN_address=$_GET['APN_address'];
    $command = 'sudo /usr/bin/python3 /var/www/nebuleair_pro_4g/SARA/sara_setAPN.py ' . $port . ' ' . $APN_address . ' ' . $timeout;
    $output = shell_exec($command);
    echo $output;
}

#TO WRITE MESSAGE TO MEMORY
if ($type == "sara_writeMessage") {
    $port=$_GET['port'];
    $message=$_GET['message'];
    $message = escapeshellcmd($message);
    $type2=$_GET['type2'];

    if ($type2 === "write") {
        $command = 'sudo /usr/bin/python3 /var/www/nebuleair_pro_4g/SARA/sara_writeMessage.py ' . $port . ' ' . $message;
        $output = shell_exec($command);
    }
    if ($type2 === "read") {
        $command = 'sudo /usr/bin/python3 /var/www/nebuleair_pro_4g/SARA/sara_readMessage.py ' . $port . ' ' . $message;
        $output = shell_exec($command);
    }
    if ($type2 === "erase") {
        $command = 'sudo /usr/bin/python3 /var/www/nebuleair_pro_4g/SARA/sara_eraseMessage.py ' . $port . ' ' . $message;
        $output = shell_exec($command);
    }
    
    echo $output;
}

#Send the typed message to server (for ntfy notification)
if ($type == "sara_sendMessage") {
    $port=$_GET['port'];
    $endpoint=$_GET['endpoint'];
    $endpoint = escapeshellcmd($endpoint);
    $profile_id = 2;
    $command = 'sudo /usr/bin/python3 /var/www/nebuleair_pro_4g/SARA/sara_sendMessage.py ' . $port . ' ' . $endpoint. ' ' . $profile_id;
    $output = shell_exec($command);
    echo $output;
}

if ($type == "internet") {
    // eth0
    $eth0_connStatus = str_replace("\n", "", shell_exec('nmcli -g GENERAL.STATE device show eth0 2>/dev/null'));
    $eth0_IPAddr = str_replace("\n", "", shell_exec('nmcli -g IP4.ADDRESS device show eth0 2>/dev/null'));

    // wlan0 basic
    $wlan0_connStatus = str_replace("\n", "", shell_exec('nmcli -g GENERAL.STATE device show wlan0 2>/dev/null'));
    $wlan0_IPAddr = str_replace("\n", "", shell_exec('nmcli -g IP4.ADDRESS device show wlan0 2>/dev/null'));

    // wlan0 detailed info (connection name, signal, frequency, security, gateway, etc.)
    $wlan0_connection = str_replace("\n", "", shell_exec("nmcli -t -f GENERAL.CONNECTION device show wlan0 2>/dev/null | cut -d: -f2"));
    $wlan0_gateway = str_replace("\n", "", shell_exec('nmcli -g IP4.GATEWAY device show wlan0 2>/dev/null'));

    // Get active WiFi details (signal, frequency, security) from nmcli
    $wifi_signal = '';
    $wifi_freq = '';
    $wifi_security = '';
    $wifi_ssid = '';
    $wifi_output = shell_exec('nmcli -t -f ACTIVE,SSID,SIGNAL,FREQ,SECURITY device wifi list ifname wlan0 2>/dev/null');
    if ($wifi_output) {
        $lines = explode("\n", trim($wifi_output));
        foreach ($lines as $line) {
            // Active connection line starts with "yes:" (nmcli -t uses : separator)
            if (strpos($line, 'yes:') === 0) {
                // Format: yes:SSID:SIGNAL:FREQ:SECURITY
                // Use explode with limit to handle SSIDs containing ':'
                $parts = explode(':', $line);
                if (count($parts) >= 5) {
                    $wifi_ssid = $parts[1];
                    $wifi_signal = $parts[2];
                    $wifi_freq = $parts[3];
                    $wifi_security = $parts[4];
                }
                break;
            }
        }
    }

    // Hostname
    $hostname = trim(shell_exec('hostname 2>/dev/null'));

    $data = array(
        "ethernet" => array(
            "connection" => $eth0_connStatus,
            "IP" => $eth0_IPAddr
        ),
        "wifi" => array(
            "connection" => $wlan0_connStatus,
            "IP" => $wlan0_IPAddr,
            "ssid" => $wifi_ssid ?: $wlan0_connection,
            "signal" => $wifi_signal,
            "frequency" => $wifi_freq,
            "security" => $wifi_security,
            "gateway" => $wlan0_gateway,
            "hostname" => $hostname
        )
    );

    echo json_encode($data);
}

# IMPORTANT
# c'est ici que la connexion vers le WIFI du client s'effectue.
if ($type == "wifi_connect") {
    $SSID=$_GET['SSID'];
    $PASS=$_GET['pass'];

    // Get device name and hostname for instructions
    try {
        $db = new PDO("sqlite:$database_path");
        $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        $stmt = $db->prepare("SELECT value FROM config_table WHERE key = 'deviceName'");
        $stmt->execute();
        $result = $stmt->fetch(PDO::FETCH_ASSOC);
        $deviceName = $result ? $result['value'] : 'NebuleAir';
        $db = null;
    } catch (PDOException $e) {
        $deviceName = 'NebuleAir';
    }
    $hostname = trim(shell_exec('hostname 2>/dev/null')) ?: 'aircarto';

    // Launch connection script in background
    $script_path = '/var/www/nebuleair_pro_4g/connexion.sh';
    $log_file = '/var/www/nebuleair_pro_4g/logs/app.log';
    shell_exec("$script_path $SSID $PASS >> $log_file 2>&1 &");

    // Return JSON response with instructions
    header('Content-Type: application/json');
    echo json_encode([
        'success' => true,
        'ssid' => $SSID,
        'deviceName' => $deviceName,
        'hostname' => $hostname,
        'message' => 'Connection attempt started',
        'instructions' => [
            'fr' => [
                'title' => 'Connexion en cours...',
                'step1' => "Le capteur tente de se connecter au réseau « $SSID »",
                'step2' => "Vous allez être déconnecté du hotspot dans quelques secondes",
                'step3' => "Reconnectez-vous au WiFi « $SSID » sur votre appareil",
                'step4' => "Accédez au capteur via http://$hostname.local/html/ ou cherchez son IP dans votre routeur",
                'warning' => "Si la connexion échoue, le capteur recréera automatiquement le hotspot"
            ],
            'en' => [
                'title' => 'Connection in progress...',
                'step1' => "The sensor is attempting to connect to network « $SSID »",
                'step2' => "You will be disconnected from the hotspot in a few seconds",
                'step3' => "Reconnect your device to WiFi « $SSID »",
                'step4' => "Access the sensor via http://$hostname.local/html/ or find its IP in your router",
                'warning' => "If connection fails, the sensor will automatically recreate the hotspot"
            ]
        ]
    ]);
}


if ($type == "wifi_forget") {
    // Get device name from database
    try {
        $db = new PDO("sqlite:$database_path");
        $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        $stmt = $db->prepare("SELECT value FROM config_table WHERE key = 'deviceName'");
        $stmt->execute();
        $result = $stmt->fetch(PDO::FETCH_ASSOC);
        $deviceName = $result ? $result['value'] : 'NebuleAir';
        $db = null;
    } catch (PDOException $e) {
        $deviceName = 'NebuleAir';
    }

    // Launch forget script in background
    $script_path = '/var/www/nebuleair_pro_4g/forget_wifi.sh';
    $log_file = '/var/www/nebuleair_pro_4g/logs/app.log';
    shell_exec("bash $script_path >> $log_file 2>&1 &");

    header('Content-Type: application/json');
    echo json_encode([
        'success' => true,
        'deviceName' => $deviceName,
        'instructions' => [
            'fr' => [
                'title' => 'Réseau WiFi oublié',
                'step1' => "Le capteur oublie le réseau WiFi actuel",
                'step2' => "Le hotspot va démarrer automatiquement",
                'step3' => "Connectez-vous au WiFi « $deviceName » (mot de passe : nebuleaircfg)",
                'step4' => "Accédez au capteur via http://10.42.0.1/html/",
                'warning' => "Le capteur ne se reconnectera plus automatiquement à ce réseau"
            ],
            'en' => [
                'title' => 'WiFi network forgotten',
                'step1' => "The sensor is forgetting the current WiFi network",
                'step2' => "The hotspot will start automatically",
                'step3' => "Connect to WiFi « $deviceName » (password: nebuleaircfg)",
                'step4' => "Access the sensor via http://10.42.0.1/html/",
                'warning' => "The sensor will no longer auto-connect to this network"
            ]
        ]
    ]);
}


if ($type == "wifi_scan") {

    $jsonData = [];

    // Check if wlan0 is in hotspot mode — if so, use cached CSV from boot scan
    // (live scan is impossible while wlan0 is serving the hotspot)
    $wlan0_connection = trim(shell_exec("nmcli -t -f GENERAL.CONNECTION device show wlan0 2>/dev/null | cut -d: -f2"));
    $is_hotspot = (strpos(strtolower($wlan0_connection), 'hotspot') !== false);

    if ($is_hotspot) {
        // Read cached scan from boot (wifi_list.csv)
        $csv_path = '/var/www/nebuleair_pro_4g/wifi_list.csv';
        if (file_exists($csv_path)) {
            $lines = file($csv_path, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
            // Skip header line (SSID,SIGNAL,SECURITY)
            for ($i = 1; $i < count($lines); $i++) {
                $parts = str_getcsv($lines[$i]);
                if (count($parts) >= 2 && !empty(trim($parts[0]))) {
                    $jsonData[] = [
                        'SSID' => trim($parts[0]),
                        'SIGNAL' => trim($parts[1]),
                        'SECURITY' => isset($parts[2]) ? trim($parts[2]) : '--',
                        'cached' => true
                    ];
                }
            }
        }
    } else {
        // Live scan (wlan0 is free)
        $output = shell_exec('timeout 10 nmcli -f SSID,SIGNAL,SECURITY device wifi list ifname wlan0 2>/dev/null');

        if ($output) {
            $lines = explode("\n", trim($output));
            for ($i = 1; $i < count($lines); $i++) {
                $line = trim($lines[$i]);
                if (empty($line)) continue;

                $parts = preg_split('/\s{2,}/', $line, 3);
                if (count($parts) >= 2) {
                    $jsonData[] = [
                        'SSID' => trim($parts[0]),
                        'SIGNAL' => trim($parts[1]),
                        'SECURITY' => isset($parts[2]) ? trim($parts[2]) : '--'
                    ];
                }
            }
        }
    }

    header('Content-Type: application/json');
    echo json_encode($jsonData, JSON_PRETTY_PRINT);

}

if ($type == "wifi_scan_old") {

    $output = shell_exec('nmcli device wifi list ifname wlan0');
    // Split the output into lines
    $lines = explode("\n", trim($output));
    
    // Initialize an array to hold the results
    $wifiNetworks = [];
    
    // Loop through each line and extract the relevant information
    foreach ($lines as $index => $line) {
        // Skip the header line
        if ($index === 0) {
            continue;
        }
    
        // Split the line by whitespace and filter empty values
        $columns = preg_split('/\s+/', $line);
        
        // If the line has enough columns, store the relevant data
        if (count($columns) >= 5) {
            $wifiNetworks[] = [
                'SSID' => $columns[2], // Network name
                'BARS' => $columns[8],
                'SIGNAL' => $columns[7], // Signal strength
                
            ];
        }
    }
    $json_data = json_encode($wifiNetworks);

    echo $json_data;

}

/*
  _____                   _             _ 
 |_   _|__ _ __ _ __ ___ (_)_ __   __ _| |
   | |/ _ \ '__| '_ ` _ \| | '_ \ / _` | |
   | |  __/ |  | | | | | | | | | | (_| | |
   |_|\___|_|  |_| |_| |_|_|_| |_|\__,_|_|
                                          
*/

// Execute shell command with security restrictions
if ($type == "execute_command") {
    // Verify that the request is using POST method
    if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
        echo json_encode(['success' => false, 'message' => 'Invalid request method']);
        exit;
    }
    
    // Get the command from POST data
    $command = isset($_POST['command']) ? $_POST['command'] : '';
    
    if (empty($command)) {
        echo json_encode(['success' => false, 'message' => 'No command provided']);
        exit;
    }
    
    // List of allowed commands (prefixes)
    $allowedCommands = [
        'ls', 'cat', 'cd', 'pwd', 'df', 'free', 'ifconfig', 'ip', 'ps', 'date', 'uptime', 
        'systemctl status', 'whoami', 'hostname', 'uname', 'grep', 'tail', 'head', 'find',
        'less', 'more', 'du', 'echo', 'git'
    ];
    
    // Check if command is allowed
    $allowed = false;
    foreach ($allowedCommands as $allowedCmd) {
        if (strpos($command, $allowedCmd) === 0) {
            $allowed = true;
            break;
        }
    }
    
    // Special case for systemctl restart and reboot
    if (strpos($command, 'systemctl restart') === 0 || $command === 'reboot') {
        // These commands don't return output through shell_exec since they change process state
        // We'll just acknowledge them
        if ($command === 'reboot') {
            // Execute the command with exec to avoid waiting for output
            exec('sudo reboot > /dev/null 2>&1 &');
            echo json_encode([
                'success' => true,
                'output' => 'System is rebooting...'
            ]);
        } else {
            // For systemctl restart, execute it and acknowledge
            $serviceName = str_replace('systemctl restart ', '', $command);
            exec('sudo systemctl restart ' . escapeshellarg($serviceName) . ' > /dev/null 2>&1 &');
            echo json_encode([
                'success' => true,
                'output' => 'Service ' . $serviceName . ' is restarting...'
            ]);
        }
        exit;
    }
    
    // Check for prohibited patterns
    $prohibitedPatterns = [
        'sudo rm', ';', '&&', '||', '|', '>', '>>', '&',
        'wget', 'curl', 'nc', 'ssh', 'scp', 'ftp', 'telnet',
        'iptables', 'passwd', 'chown', 'chmod', 'mkfs', ' dd ',
        'mount', 'umount', 'kill', 'killall'
    ];
    
    foreach ($prohibitedPatterns as $pattern) {
        if (strpos($command, $pattern) !== false) {
            echo json_encode([
                'success' => false,
                'message' => 'Command contains prohibited operation: ' . $pattern
            ]);
            exit;
        }
    }
    
    if (!$allowed) {
        echo json_encode([
            'success' => false,
            'message' => 'Command not allowed for security reasons'
        ]);
        exit;
    }
    
    // Execute the command with timeout protection
    $descriptorspec = [
        0 => ["pipe", "r"],  // stdin
        1 => ["pipe", "w"],  // stdout
        2 => ["pipe", "w"]   // stderr
    ];
    
    // Escape the command to prevent shell injection
    $escapedCommand = escapeshellcmd($command);
    
    // Add timeout of 5 seconds to prevent long-running commands
    $process = proc_open("timeout 5 $escapedCommand", $descriptorspec, $pipes);
    
    if (is_resource($process)) {
        // Close stdin pipe
        fclose($pipes[0]);
        
        // Get output from stdout
        $output = stream_get_contents($pipes[1]);
        fclose($pipes[1]);
        
        // Get any errors
        $errors = stream_get_contents($pipes[2]);
        fclose($pipes[2]);
        
        // Close the process
        $returnValue = proc_close($process);
        
        // Check for errors
        if ($returnValue !== 0) {
            // If there was an error, but we have output, consider it a partial success
            if (!empty($output)) {
                echo json_encode([
                    'success' => true,
                    'output' => $output . "\n" . $errors . "\nCommand exited with code $returnValue"
                ]);
            } else {
                echo json_encode([
                    'success' => false,
                    'message' => empty($errors) ? "Command failed with exit code $returnValue" : $errors
                ]);
            }
        } else {
            // Success
            echo json_encode([
                'success' => true,
                'output' => $output
            ]);
        }
    } else {
        echo json_encode([
            'success' => false,
            'message' => 'Failed to execute command'
        ]);
    }
}

/*
   ____            _                 ____                      _          __  __                                                   _   
  / ___| _   _ ___| |_ ___ _ __ ___ |  _ \  / ___|  ___ _ ____   _(_) ___ ___|  \/  | __ _ _ __   __ _  __ _  ___ _ __ ___   ___ _ __ | |_ 
  \___ \| | | / __| __/ _ \ '_ ` _ \| | | | \___ \ / _ \ '__\ \ / / |/ __/ _ \ |\/| |/ _` | '_ \ / _` |/ _` |/ _ \ '_ ` _ \ / _ \ '_ \| __|
   ___) | |_| \__ \ ||  __/ | | | | | |_| |  ___) |  __/ |   \ V /| | (_|  __/ |  | | (_| | | | | (_| | (_| |  __/ | | | | |  __/ | | | |_ 
  |____/ \__, |___/\__\___|_| |_| |_|____/  |____/ \___|_|    \_/ |_|\___\___|_|  |_|\__,_|_| |_|\__,_|\__, |\___|_| |_| |_|\___|_| |_|\__|
         |___/                                                                                          |___/                              
*/

// Get systemd services status
if ($type == "get_systemd_services") {
    try {
        // List of NebuleAir services to monitor with descriptions and frequencies
        // Optional 'display_name' overrides the auto-generated cleaned-up name.
        $services = [
            'nebuleair-npm-data.timer' => [
                'description' => 'Collects particulate matter data from NextPM sensor',
                'frequency' => 'Every 10 seconds'
            ],
            'nebuleair-envea-data.timer' => [
                'description' => 'Reads environmental data from Envea sensors',
                'frequency' => 'Every 10 seconds'
            ],
            'nebuleair-sara-data.timer' => [
                'description' => 'Transmits collected data via 4G cellular modem',
                'frequency' => 'Every 60 seconds'
            ],
            'nebuleair-bme280-data.timer' => [
                'description' => 'Monitors temperature and humidity (BME280)',
                'frequency' => 'Every 2 minutes'
            ],
            'nebuleair-mppt-data.timer' => [
                'description' => 'Tracks solar panel and battery status',
                'frequency' => 'Every 2 minutes'
            ],
            'nebuleair-noise-data.timer' => [
                'description' => 'Get Data from noise sensor',
                'frequency' => 'Every minute'
            ],
            'nebuleair-mhz19-data.timer' => [
                'description' => 'Reads CO2 concentration from MH-Z19 sensor',
                'frequency' => 'Every 2 minutes'
            ],
            'nebuleair-db-cleanup-data.timer' => [
                'description' => 'Cleans up old data from database',
                'frequency' => 'Daily'
            ],
            'nebuleair-wifi-powersave.timer' => [
                'display_name' => 'Wifi powersave',
                'description' => 'Enables WiFi power-saving mode to reduce battery consumption',
                'frequency' => '10 min after boot'
            ],
            'nebuleair-cpu-power.service' => [
                'display_name' => 'Cpu power',
                'description' => 'Applies CPU power mode from DB config at boot',
                'frequency' => 'At boot'
            ],
            'rtc_save_to_db.service' => [
                'display_name' => 'Rtc save to db',
                'description' => 'Reads DS3231 RTC over I2C and saves timestamp to DB',
                'frequency' => 'Continuous (1Hz)'
            ]
        ];

        $serviceStatus = [];

        foreach ($services as $service => $serviceInfo) {
            // Get service active status
            $activeCmd = "systemctl is-active " . escapeshellarg($service) . " 2>/dev/null";
            $activeStatus = trim(shell_exec($activeCmd));
            $isActive = ($activeStatus === 'active');

            // Get service enabled status
            $enabledCmd = "systemctl is-enabled " . escapeshellarg($service) . " 2>/dev/null";
            $enabledStatus = trim(shell_exec($enabledCmd));
            $isEnabled = ($enabledStatus === 'enabled');

            // Display name: explicit override if provided, otherwise auto-cleanup
            if (isset($serviceInfo['display_name'])) {
                $displayName = $serviceInfo['display_name'];
            } else {
                $displayName = str_replace(['.timer', '.service', 'nebuleair-', '-data'], '', $service);
                $displayName = ucfirst(str_replace('-', ' ', $displayName));
            }

            $serviceStatus[] = [
                'name' => $service,
                'display_name' => $displayName,
                'description' => $serviceInfo['description'],
                'frequency' => $serviceInfo['frequency'],
                'active' => $isActive,
                'enabled' => $isEnabled
            ];
        }
        
        echo json_encode([
            'success' => true,
            'services' => $serviceStatus
        ], JSON_PRETTY_PRINT);
        
    } catch (Exception $e) {
        echo json_encode([
            'success' => false,
            'error' => $e->getMessage()
        ]);
    }
}

// Restart a systemd service
if ($type == "restart_systemd_service") {
    $service = $_GET['service'] ?? null;
    
    if (empty($service)) {
        echo json_encode([
            'success' => false,
            'error' => 'No service specified'
        ]);
        exit;
    }
    
    // Validate service name (security check)
    $allowedServices = [
        'nebuleair-npm-data.timer',
        'nebuleair-envea-data.timer',
        'nebuleair-sara-data.timer',
        'nebuleair-bme280-data.timer',
        'nebuleair-mppt-data.timer',
        'nebuleair-noise-data.timer',
        'nebuleair-mhz19-data.timer',
        'nebuleair-db-cleanup-data.timer',
        'nebuleair-wifi-powersave.timer',
        'nebuleair-cpu-power.service',
        'rtc_save_to_db.service'
    ];

    if (!in_array($service, $allowedServices)) {
        echo json_encode([
            'success' => false,
            'error' => 'Invalid service name'
        ]);
        exit;
    }

    try {
        // Restart the service
        $command = "sudo systemctl restart " . escapeshellarg($service) . " 2>&1";
        $output = shell_exec($command);
        
        // Check if restart was successful
        $statusCmd = "systemctl is-active " . escapeshellarg($service) . " 2>/dev/null";
        $status = trim(shell_exec($statusCmd));
        
        if ($status === 'active' || empty($output)) {
            echo json_encode([
                'success' => true,
                'message' => "Service $service restarted successfully"
            ]);
        } else {
            echo json_encode([
                'success' => false,
                'error' => "Failed to restart service: $output"
            ]);
        }
        
    } catch (Exception $e) {
        echo json_encode([
            'success' => false,
            'error' => $e->getMessage()
        ]);
    }
}

// Enable/disable a systemd service
if ($type == "toggle_systemd_service") {
    $service = $_GET['service'] ?? null;
    $enable = $_GET['enable'] ?? null;
    
    if (empty($service) || $enable === null) {
        echo json_encode([
            'success' => false,
            'error' => 'Missing service name or enable parameter'
        ]);
        exit;
    }
    
    // Validate service name (security check)
    $allowedServices = [
        'nebuleair-npm-data.timer',
        'nebuleair-envea-data.timer',
        'nebuleair-sara-data.timer',
        'nebuleair-bme280-data.timer',
        'nebuleair-mppt-data.timer',
        'nebuleair-noise-data.timer',
        'nebuleair-mhz19-data.timer',
        'nebuleair-db-cleanup-data.timer',
        'nebuleair-wifi-powersave.timer',
        'nebuleair-cpu-power.service',
        'rtc_save_to_db.service'
    ];

    if (!in_array($service, $allowedServices)) {
        echo json_encode([
            'success' => false,
            'error' => 'Invalid service name'
        ]);
        exit;
    }

    try {
        $enable = filter_var($enable, FILTER_VALIDATE_BOOLEAN);
        $action = $enable ? 'enable' : 'disable';
        
        // Enable/disable the service
        $command = "sudo systemctl $action " . escapeshellarg($service) . " 2>&1";
        $output = shell_exec($command);
        
        // If disabling, also stop the service
        if (!$enable) {
            $stopCommand = "sudo systemctl stop " . escapeshellarg($service) . " 2>&1";
            $stopOutput = shell_exec($stopCommand);
        }
        
        // If enabling, also start the service
        if ($enable) {
            $startCommand = "sudo systemctl start " . escapeshellarg($service) . " 2>&1";
            $startOutput = shell_exec($startCommand);
        }
        
        // Check if the operation was successful
        $statusCmd = "systemctl is-enabled " . escapeshellarg($service) . " 2>/dev/null";
        $status = trim(shell_exec($statusCmd));
        
        $expectedStatus = $enable ? 'enabled' : 'disabled';
        
        if ($status === $expectedStatus) {
            echo json_encode([
                'success' => true,
                'message' => "Service $service " . ($enable ? 'enabled and started' : 'disabled and stopped') . " successfully"
            ]);
        } else {
            echo json_encode([
                'success' => false,
                'error' => "Failed to $action service: $output"
            ]);
        }
        
    } catch (Exception $e) {
        echo json_encode([
            'success' => false,
            'error' => $e->getMessage()
        ]);
    }
}

// Empty all sensor tables (preserve config and timestamp tables)
if ($type == "empty_sensor_tables") {
    try {
        // Execute the empty sensor tables script
        $command = 'sudo /usr/bin/python3 /var/www/nebuleair_pro_4g/sqlite/empty_sensor_tables.py 2>&1';
        $output = shell_exec($command);

        // Try to extract JSON result from output
        $json_start = strpos($output, '[JSON_RESULT]');
        if ($json_start !== false) {
            $json_data = substr($output, $json_start + strlen('[JSON_RESULT]'));
            $json_data = trim($json_data);

            // Find the first { and last }
            $first_brace = strpos($json_data, '{');
            $last_brace = strrpos($json_data, '}');

            if ($first_brace !== false && $last_brace !== false) {
                $json_data = substr($json_data, $first_brace, $last_brace - $first_brace + 1);
                $result = json_decode($json_data, true);

                if ($result !== null) {
                    echo json_encode($result);
                } else {
                    // JSON decode failed, return raw output
                    echo json_encode([
                        'success' => true,
                        'message' => 'Tables emptied',
                        'output' => $output
                    ]);
                }
            } else {
                echo json_encode([
                    'success' => true,
                    'message' => 'Tables emptied',
                    'output' => $output
                ]);
            }
        } else {
            // No JSON marker found, return raw output
            echo json_encode([
                'success' => true,
                'message' => 'Tables emptied',
                'output' => $output
            ]);
        }

    } catch (Exception $e) {
        echo json_encode([
            'success' => false,
            'error' => 'Script execution failed: ' . $e->getMessage()
        ]);
    }
}

/*
  _____                       ____       _            _   _
 | ____|_ ____   _____  __ _  |  _ \  ___| |_ ___  ___| |_(_) ___  _ __
 |  _| | '_ \ \ / / _ \/ _` | | | | |/ _ \ __/ _ \/ __| __| |/ _ \| '_ \
 | |___| | | \ V /  __/ (_| | | |_| |  __/ ||  __/ (__| |_| | (_) | | | |
 |_____|_| |_|\_/ \___|\__,_| |____/ \___|\__\___|\___|\__|_|\___/|_| |_|

*/

// Detect Envea devices on specified port
if ($type == "detect_envea_device") {
    $port = $_GET['port'] ?? null;
    
    if (empty($port)) {
        echo json_encode([
            'success' => false,
            'error' => 'No port specified'
        ]);
        exit;
    }
    
    // Validate port name (security check)
    $allowedPorts = ['ttyAMA2', 'ttyAMA3', 'ttyAMA4', 'ttyAMA5'];
    
    if (!in_array($port, $allowedPorts)) {
        echo json_encode([
            'success' => false,
            'error' => 'Invalid port name'
        ]);
        exit;
    }
    
    try {
        // Execute the envea detection script
        $command = "sudo /usr/bin/python3 /var/www/nebuleair_pro_4g/envea/read_ref.py " . escapeshellarg($port) . " 2>&1";
        $output = shell_exec($command);
        
        // Check if we got any meaningful output
        $detected = false;
        $device_info = '';
        $raw_data = $output;
        
        if (!empty($output)) {
            // Look for indicators that a device is connected
            if (strpos($output, 'Connexion ouverte') !== false) {
                // Connection was successful
                if (strpos($output, 'Données reçues brutes') !== false && 
                    strpos($output, 'b\'\'') === false) {
                    // We received actual data (not empty)
                    $detected = true;
                    $device_info = 'Envea CAIRSENS Device';
                    
                    // Try to extract device type from ASCII data if available
                    if (preg_match('/Valeurs converties en ASCII : (.+)/', $output, $matches)) {
                        $ascii_data = trim($matches[1]);
                        if (!empty($ascii_data) && $ascii_data !== '........') {
                            $device_info = "Envea Device: " . $ascii_data;
                        }
                    }
                } else {
                    // Connection successful but no data
                    $device_info = 'Port accessible but no Envea device detected';
                }
            } else if (strpos($output, 'Erreur de connexion série') !== false) {
                // Serial connection error
                $device_info = 'Serial connection error - port may be busy or not available';
            } else {
                // Other output
                $device_info = 'Unexpected response from port';
            }
        } else {
            // No output at all
            $device_info = 'No response from port';
        }
        
        echo json_encode([
            'success' => true,
            'port' => $port,
            'detected' => $detected,
            'device_info' => $device_info,
            'data' => $raw_data,
            'timestamp' => date('Y-m-d H:i:s')
        ], JSON_PRETTY_PRINT);
        
    } catch (Exception $e) {
        echo json_encode([
            'success' => false,
            'error' => 'Script execution failed: ' . $e->getMessage(),
            'port' => $port
        ]);
    }
}

/*
   ____ ____  _   _   ____                       __  __                                                   _
  / ___|  _ \| | | | |  _ \ _____      _____ _ _|  \/  | __ _ _ __   __ _  __ _  ___ _ __ ___   ___ _ __ | |_
 | |   | |_) | | | | | |_) / _ \ \ /\ / / _ \ '__| |\/| |/ _` | '_ \ / _` |/ _` |/ _ \ '_ ` _ \ / _ \ '_ \| __|
 | |___|  __/| |_| | |  __/ (_) \ V  V /  __/ |  | |  | | (_| | | | | (_| | (_| |  __/ | | | | |  __/ | | | |_
  \____|_|    \___/  |_|   \___/ \_/\_/ \___|_|  |_|  |_|\__,_|_| |_|\__,_|\__, |\___|_| |_| |_|\___|_| |_|\__|
                                                                            |___/
*/

// Get firmware version from VERSION file
if ($type == "get_firmware_version") {
    $versionFile = '/var/www/nebuleair_pro_4g/VERSION';
    if (file_exists($versionFile)) {
        $version = trim(file_get_contents($versionFile));
        echo json_encode([
            'success' => true,
            'version' => $version
        ]);
    } else {
        echo json_encode([
            'success' => false,
            'version' => 'unknown'
        ]);
    }
}

// Get changelog from changelog.json
if ($type == "get_changelog") {
    $changelogFile = '/var/www/nebuleair_pro_4g/changelog.json';
    if (file_exists($changelogFile)) {
        $changelog = json_decode(file_get_contents($changelogFile), true);
        if ($changelog !== null) {
            echo json_encode([
                'success' => true,
                'changelog' => $changelog
            ]);
        } else {
            echo json_encode([
                'success' => false,
                'error' => 'Invalid changelog format'
            ]);
        }
    } else {
        echo json_encode([
            'success' => false,
            'error' => 'Changelog file not found'
        ]);
    }
}

// Get current CPU power mode
if ($type == "get_cpu_power_mode") {
    try {
        $command = 'sudo /usr/bin/python3 /var/www/nebuleair_pro_4g/power/set_cpu_mode.py get 2>&1';
        $output = shell_exec($command);

        // Try to parse JSON output
        $result = json_decode($output, true);

        if ($result && isset($result['success']) && $result['success']) {
            echo json_encode([
                'success' => true,
                'mode' => $result['config_mode'] ?? 'unknown',
                'cpu_state' => $result['cpu_state'] ?? null
            ], JSON_PRETTY_PRINT);
        } else {
            echo json_encode([
                'success' => false,
                'error' => 'Failed to get CPU power mode',
                'output' => $output
            ]);
        }
    } catch (Exception $e) {
        echo json_encode([
            'success' => false,
            'error' => 'Script execution failed: ' . $e->getMessage()
        ]);
    }
}

// Set CPU power mode
if ($type == "set_cpu_power_mode") {
    $mode = $_GET['mode'] ?? null;

    if (empty($mode)) {
        echo json_encode([
            'success' => false,
            'error' => 'No mode specified'
        ]);
        exit;
    }

    // Validate mode (whitelist)
    $allowedModes = ['normal', 'powersave'];

    if (!in_array($mode, $allowedModes)) {
        echo json_encode([
            'success' => false,
            'error' => 'Invalid mode. Allowed: normal, powersave'
        ]);
        exit;
    }

    try {
        // Execute the CPU power mode script
        $command = 'sudo /usr/bin/python3 /var/www/nebuleair_pro_4g/power/set_cpu_mode.py ' . escapeshellarg($mode) . ' 2>&1';
        $output = shell_exec($command);

        // Try to parse JSON output
        $result = json_decode($output, true);

        if ($result && isset($result['success']) && $result['success']) {
            echo json_encode([
                'success' => true,
                'mode' => $mode,
                'message' => "CPU power mode set to: $mode",
                'description' => $result['description'] ?? ''
            ], JSON_PRETTY_PRINT);
        } else {
            echo json_encode([
                'success' => false,
                'error' => $result['error'] ?? 'Failed to set CPU power mode',
                'output' => $output
            ]);
        }
    } catch (Exception $e) {
        echo json_encode([
            'success' => false,
            'error' => 'Script execution failed: ' . $e->getMessage()
        ]);
    }
}

if ($type == "screen_control") {
    $action = $_GET['action'];
    if ($action == "start") {
        // Run as background process with sudo (requires nopasswd in sudoers)
        // Redirecting to a temp log file to debug startup issues
        $command = 'export DISPLAY=:0 && nohup sudo /usr/bin/python3 /var/www/nebuleair_pro_4g/screen_control/screen.py > /tmp/screen_control.log 2>&1 &';
        shell_exec($command);
        echo "Started. Check /tmp/screen_control.log for details.";
    } elseif ($action == "stop") {
        $command = 'sudo pkill -f "screen.py" 2>&1';
        $output = shell_exec($command);
        echo "Stopped. Output: " . $output;
    }
}
