/*
 * Bluehound - Continuous BLE/Classic Bluetooth scanner with time-searchable logging
 * Built for embedded devices with WiFi streaming support
 */

#include <simpleble/SimpleBLE.h>
#include <sqlite3.h>
#include <iostream>
#include <string>
#include <chrono>
#include <thread>
#include <iomanip>
#include <sstream>
#include <csignal>
#include <atomic>
#include <mutex>
#include <vector>
#include <set>
#include <map>
#include <cmath>

// HTTP server library - using cpp-httplib (single header)
#include "httplib.h"

// Classic Bluetooth support
#include "classic_bluetooth.h"

// Configuration
struct Config {
    int scan_duration_ms = 5000;  // Scan for 5 seconds per cycle
    int scan_interval_ms = 1000;   // Wait 1 second between scans
    std::string db_path = "ble_scans.db";
    int http_port = 8080;
    bool enable_http_server = true;
    int max_db_entries = 1000000;  // Rotate after 1M entries
};

// Global state
std::atomic<bool> running(true);
std::mutex db_mutex;
std::set<std::string> enumerated_devices;  // Track devices we've already enumerated
std::mutex enumerated_mutex;
Config config;

// Forward declarations
std::string get_timestamp();

// Signal handler for graceful shutdown
void signal_handler(int signal) {
    std::cout << "\nReceived signal " << signal << ", shutting down gracefully..." << std::endl;
    running = false;
}

// BLE UUID Decoder - Standard Services
std::string decode_service_uuid(const std::string& uuid) {
    static const std::map<std::string, std::string> services = {
        {"1800", "Generic Access"},
        {"1801", "Generic Attribute"},
        {"1804", "Tx Power"},
        {"180A", "Device Information"},
        {"180D", "Heart Rate"},
        {"180F", "Battery Service"},
        {"1810", "Blood Pressure"},
        {"1812", "Human Interface Device"},
        {"1816", "Cycling Speed and Cadence"},
        {"1818", "Cycling Power"},
        {"181A", "Environmental Sensing"},
        {"181B", "Body Composition"},
        {"181C", "User Data"},
        {"181D", "Weight Scale"}
    };

    std::string upper_uuid = uuid;
    std::transform(upper_uuid.begin(), upper_uuid.end(), upper_uuid.begin(), ::toupper);

    // Extract 16-bit UUID from 128-bit format (0000XXXX-0000-1000-8000-00805f9b34fb)
    if (upper_uuid.length() >= 8 && upper_uuid.substr(0, 4) == "0000") {
        upper_uuid = upper_uuid.substr(4, 4);
    } else if (upper_uuid.length() > 4) {
        return "";  // Custom vendor UUID
    }

    auto it = services.find(upper_uuid);
    return (it != services.end()) ? it->second : "";
}

// BLE UUID Decoder - Standard Characteristics
std::string decode_characteristic_uuid(const std::string& uuid) {
    static const std::map<std::string, std::string> characteristics = {
        {"2A00", "Device Name"},
        {"2A01", "Appearance"},
        {"2A04", "Peripheral Preferred Connection Parameters"},
        {"2A05", "Service Changed"},
        {"2A07", "Tx Power Level"},
        {"2A19", "Battery Level"},
        {"2A23", "System ID"},
        {"2A24", "Model Number String"},
        {"2A25", "Serial Number String"},
        {"2A26", "Firmware Revision String"},
        {"2A27", "Hardware Revision String"},
        {"2A28", "Software Revision String"},
        {"2A29", "Manufacturer Name String"},
        {"2A37", "Heart Rate Measurement"},
        {"2A38", "Body Sensor Location"},
        {"2A49", "Blood Pressure Feature"},
        {"2A4A", "HID Information"},
        {"2A50", "PnP ID"},
        {"2A6E", "Temperature"},
        {"2A6F", "Humidity"},
        {"2A9E", "Weight Measurement"}
    };

    std::string upper_uuid = uuid;
    std::transform(upper_uuid.begin(), upper_uuid.end(), upper_uuid.begin(), ::toupper);

    // Extract 16-bit UUID from 128-bit format (0000XXXX-0000-1000-8000-00805f9b34fb)
    if (upper_uuid.length() >= 8 && upper_uuid.substr(0, 4) == "0000") {
        upper_uuid = upper_uuid.substr(4, 4);
    } else if (upper_uuid.length() > 4) {
        return "";  // Custom vendor UUID
    }

    auto it = characteristics.find(upper_uuid);
    return (it != characteristics.end()) ? it->second : "";
}

// Get characteristic description
std::string get_characteristic_description(const std::string& uuid) {
    static const std::map<std::string, std::string> descriptions = {
        {"2A19", "Battery charge level (0-100%)"},
        {"2A00", "Human-readable device name"},
        {"2A29", "Name of device manufacturer"},
        {"2A24", "Device model number"},
        {"2A26", "Firmware version"},
        {"2A37", "Heart rate in beats per minute"},
        {"2A6E", "Temperature in Celsius"},
        {"2A6F", "Relative humidity percentage"},
        {"2A50", "Product ID information"},
        {"2A07", "Transmit power level"}
    };

    std::string upper_uuid = uuid;
    std::transform(upper_uuid.begin(), upper_uuid.end(), upper_uuid.begin(), ::toupper);

    // Extract 16-bit UUID from 128-bit format
    if (upper_uuid.length() >= 8 && upper_uuid.substr(0, 4) == "0000") {
        upper_uuid = upper_uuid.substr(4, 4);
    } else if (upper_uuid.length() > 4) {
        return "";
    }

    auto it = descriptions.find(upper_uuid);
    return (it != descriptions.end()) ? it->second : "";
}

// Security Assessment Structure
struct Vulnerability {
    std::string name;
    std::string severity;  // HIGH, MEDIUM, LOW
    std::string description;
    std::string cve;
};

struct SecurityAssessment {
    std::string device_address;
    std::string risk_level;  // HIGH, MEDIUM, LOW, NONE
    std::vector<Vulnerability> vulnerabilities;
    std::vector<std::string> recommendations;
};

// Apple Continuity Data Structure
struct AppleContinuityData {
    std::string device_type;
    std::string device_model;
    int battery_level;
    bool battery_charging;
    bool airpods_in_ear;
    bool airpods_case_lid_open;
    std::string airpods_case_battery;
    std::string airpods_left_battery;
    std::string airpods_right_battery;
    std::string proximity_pairing_status;
    std::string handoff_data;
    std::string nearby_action;
    std::string raw_data;
};

// Decode Apple Continuity/Proximity data
AppleContinuityData decode_apple_continuity(const SimpleBLE::ByteArray& data) {
    AppleContinuityData result;
    result.battery_level = -1;
    result.battery_charging = false;
    result.airpods_in_ear = false;
    result.airpods_case_lid_open = false;

    if (data.empty()) return result;

    // Convert to hex string for analysis
    std::stringstream hex_stream;
    for (uint8_t byte : data) {
        hex_stream << std::hex << std::setw(2) << std::setfill('0') << (int)byte;
    }
    result.raw_data = hex_stream.str();

    // Apple uses different message types in manufacturer data
    if (data.size() < 2) return result;

    uint8_t message_type = data[0];

    // Type 0x02: Handoff
    if (message_type == 0x02) {
        result.handoff_data = "Handoff enabled (clipboard, call switching)";
    }
    // Type 0x05: AirDrop
    else if (message_type == 0x05) {
        result.handoff_data = "AirDrop discoverable";
    }
    // Type 0x07: AirPods/AirTag
    else if (message_type == 0x07 && data.size() >= 27) {
        // AirPods status
        result.device_type = "AirPods";

        uint8_t status = data[6];
        result.airpods_in_ear = (status & 0x01) != 0;
        result.airpods_case_lid_open = (status & 0x02) != 0;

        // Battery levels (4-bit each, 0-10 scale)
        uint8_t battery_data = data[7];
        result.battery_level = (battery_data >> 4) * 10;  // Left AirPod

        if (data.size() >= 10) {
            int left = (data[8] >> 4) & 0x0F;
            int right = data[8] & 0x0F;
            int case_battery = (data[9] >> 4) & 0x0F;

            if (left <= 10) result.airpods_left_battery = std::to_string(left * 10) + "%";
            if (right <= 10) result.airpods_right_battery = std::to_string(right * 10) + "%";
            if (case_battery <= 10) result.airpods_case_battery = std::to_string(case_battery * 10) + "%";
        }
    }
    // Type 0x09: AirPlay
    else if (message_type == 0x09) {
        result.handoff_data = "AirPlay target available";
    }
    // Type 0x0C: Proximity Pairing
    else if (message_type == 0x0C && data.size() >= 3) {
        result.proximity_pairing_status = "Proximity pairing active";
        uint8_t device_type_byte = data[2];

        switch (device_type_byte) {
            case 0x01: result.device_type = "iPhone"; break;
            case 0x02: result.device_type = "iPad"; break;
            case 0x03: result.device_type = "Apple Watch"; break;
            case 0x0E: result.device_type = "AirPods"; break;
            case 0x0F: result.device_type = "AirPods Pro"; break;
            case 0x13: result.device_type = "AirPods Max"; break;
            default: result.device_type = "Unknown Apple Device"; break;
        }
    }
    // Type 0x10: Nearby Action
    else if (message_type == 0x10) {
        result.nearby_action = "Device requesting action (AirTag, FindMy)";
    }

    return result;
}

// Check if service list contains a specific service
bool has_service(const std::vector<std::string>& services, const std::string& target) {
    for (const auto& service : services) {
        std::string lower_service = service;
        std::string lower_target = target;
        std::transform(lower_service.begin(), lower_service.end(), lower_service.begin(), ::tolower);
        std::transform(lower_target.begin(), lower_target.end(), lower_target.begin(), ::tolower);

        if (lower_service.find(lower_target) != std::string::npos) {
            return true;
        }
    }
    return false;
}

// Assess device security based on services and characteristics
SecurityAssessment assess_device_security(
    const std::string& address,
    const std::vector<std::string>& services,
    bool is_paired,
    bool is_connectable,
    const std::string& device_name
) {
    SecurityAssessment assessment;
    assessment.device_address = address;

    // Check for OBEX services (HIGH risk - file transfer)
    if (has_service(services, "obex object push") || has_service(services, "1105")) {
        assessment.vulnerabilities.push_back({
            "Unsecured File Transfer",
            "HIGH",
            "Device accepts file transfers without authentication",
            "CVE-2020-13543"
        });
        assessment.recommendations.push_back("Disable OBEX Object Push service");
        assessment.recommendations.push_back("Enable PIN protection for file transfers");
    }

    if (has_service(services, "obex file transfer") || has_service(services, "1106")) {
        assessment.vulnerabilities.push_back({
            "File System Access",
            "HIGH",
            "Full filesystem access via OBEX FTP",
            ""
        });
        assessment.recommendations.push_back("Disable OBEX File Transfer service");
        assessment.recommendations.push_back("Restrict filesystem access permissions");
    }

    // Check for Serial Port service (MEDIUM risk)
    if (has_service(services, "serial port") || has_service(services, "1101")) {
        assessment.vulnerabilities.push_back({
            "Open Serial Port",
            "MEDIUM",
            "Serial port service available without authentication",
            ""
        });
        assessment.recommendations.push_back("Disable unused serial port services");
        assessment.recommendations.push_back("Require authentication for SPP connections");
    }

    // Check for HID service (MEDIUM risk - input injection)
    if (has_service(services, "human interface device") || has_service(services, "1812")) {
        assessment.vulnerabilities.push_back({
            "HID Service Exposed",
            "MEDIUM",
            "HID service allows input injection attacks",
            ""
        });
        assessment.recommendations.push_back("Verify HID pairing before accepting connections");
        assessment.recommendations.push_back("Disable HID if not needed");
    }

    // Check for Audio services (LOW risk - eavesdropping)
    if (has_service(services, "audio") || has_service(services, "110a") || has_service(services, "110b")) {
        assessment.vulnerabilities.push_back({
            "Audio Streaming",
            "LOW",
            "Audio service allows unauthorized streaming",
            ""
        });
        assessment.recommendations.push_back("Require pairing for audio connections");
        assessment.recommendations.push_back("Set device to non-discoverable when not in use");
    }

    // Check for unpaired but connectable devices (LOW risk)
    if (!is_paired && is_connectable) {
        assessment.vulnerabilities.push_back({
            "Discoverable Mode",
            "LOW",
            "Device is discoverable and not paired",
            ""
        });
        assessment.recommendations.push_back("Set device to non-discoverable mode");
        assessment.recommendations.push_back("Enable pairing timeout");
    }

    // Check for Android devices (potential BlueBorne)
    std::string lower_name = device_name;
    std::transform(lower_name.begin(), lower_name.end(), lower_name.begin(), ::tolower);
    if (lower_name.find("android") != std::string::npos && services.size() > 5) {
        assessment.vulnerabilities.push_back({
            "Potential BlueBorne Vulnerability",
            "HIGH",
            "Android device may be vulnerable to RCE if unpatched",
            "CVE-2017-1000251"
        });
        assessment.recommendations.push_back("Update device to latest firmware immediately");
        assessment.recommendations.push_back("Apply BlueBorne security patches");
    }

    // Calculate overall risk level
    bool has_high = false;
    bool has_medium = false;

    for (const auto& vuln : assessment.vulnerabilities) {
        if (vuln.severity == "HIGH") has_high = true;
        if (vuln.severity == "MEDIUM") has_medium = true;
    }

    if (has_high) {
        assessment.risk_level = "HIGH";
    } else if (has_medium) {
        assessment.risk_level = "MEDIUM";
    } else if (!assessment.vulnerabilities.empty()) {
        assessment.risk_level = "LOW";
    } else {
        assessment.risk_level = "NONE";
    }

    // Add general recommendations for high/medium risk
    if (assessment.risk_level == "HIGH" || assessment.risk_level == "MEDIUM") {
        assessment.recommendations.push_back("Disable Bluetooth when not in use");
        assessment.recommendations.push_back("Keep device firmware updated");
    }

    // Remove duplicate recommendations
    std::sort(assessment.recommendations.begin(), assessment.recommendations.end());
    assessment.recommendations.erase(
        std::unique(assessment.recommendations.begin(), assessment.recommendations.end()),
        assessment.recommendations.end()
    );

    return assessment;
}

// Passive vulnerability assessment (no connection required)
SecurityAssessment assess_device_passive(
    const std::string& address,
    const std::string& device_name,
    const std::string& company_name,
    bool is_connectable,
    const std::string& manufacturer_data
) {
    SecurityAssessment assessment;
    assessment.device_address = address;

    std::string lower_name = device_name;
    std::string lower_company = company_name;
    std::transform(lower_name.begin(), lower_name.end(), lower_name.begin(), ::tolower);
    std::transform(lower_company.begin(), lower_company.end(), lower_company.begin(), ::tolower);

    // Known vulnerable devices by name/manufacturer
    if (lower_name.find("android") != std::string::npos) {
        assessment.vulnerabilities.push_back({
            "Potential BlueBorne Target",
            "HIGH",
            "Android device potentially vulnerable to BlueBorne if unpatched (2017)",
            "CVE-2017-1000251"
        });
        assessment.recommendations.push_back("Update Android to latest security patches");
        assessment.recommendations.push_back("Verify BlueBorne fix is applied");
    }

    // Old Samsung devices
    if (lower_company.find("samsung") != std::string::npos &&
        (lower_name.find("galaxy s") != std::string::npos || lower_name.find("galaxy note") != std::string::npos)) {
        assessment.vulnerabilities.push_back({
            "Legacy Samsung Device",
            "MEDIUM",
            "Older Samsung devices had Bluetooth vulnerabilities in 2019-2020",
            "CVE-2019-16400"
        });
        assessment.recommendations.push_back("Check for firmware updates");
    }

    // Apple devices with older iOS
    if (lower_company.find("apple") != std::string::npos &&
        (lower_name.find("iphone") != std::string::npos || lower_name.find("ipad") != std::string::npos)) {
        assessment.vulnerabilities.push_back({
            "Apple BLE Privacy Concern",
            "LOW",
            "Apple devices may leak tracking information via BLE advertising",
            ""
        });
        assessment.recommendations.push_back("Keep iOS updated");
        assessment.recommendations.push_back("Disable Bluetooth when not in use");
    }

    // Fitness trackers - common privacy issues
    if (lower_name.find("fitbit") != std::string::npos ||
        lower_name.find("garmin") != std::string::npos ||
        lower_name.find("xiaomi") != std::string::npos) {
        assessment.vulnerabilities.push_back({
            "Fitness Tracker Privacy",
            "LOW",
            "Fitness devices may broadcast health data in clear text",
            ""
        });
        assessment.recommendations.push_back("Check privacy settings in companion app");
    }

    // IoT devices - typically less secure
    if (lower_name.find("smart") != std::string::npos ||
        lower_name.find("lock") != std::string::npos ||
        lower_name.find("sensor") != std::string::npos) {
        assessment.vulnerabilities.push_back({
            "IoT Device Security",
            "MEDIUM",
            "IoT devices often have outdated firmware and weak security",
            ""
        });
        assessment.recommendations.push_back("Update firmware regularly");
        assessment.recommendations.push_back("Check manufacturer security bulletins");
    }

    // Devices that are connectable but not bonded - easy targets
    if (is_connectable) {
        assessment.vulnerabilities.push_back({
            "Connectable Without Pairing",
            "LOW",
            "Device accepts connections without requiring pairing first",
            ""
        });
        assessment.recommendations.push_back("Enable pairing requirements");
        assessment.recommendations.push_back("Set device to non-discoverable when not in use");
    }

    // Check for weak random address (privacy issue)
    if (address.find("00:00:00") != std::string::npos ||
        address.find("FF:FF:FF") != std::string::npos) {
        assessment.vulnerabilities.push_back({
            "Weak Random Address",
            "LOW",
            "Device may not properly randomize Bluetooth address",
            ""
        });
        assessment.recommendations.push_back("Check device privacy settings");
    }

    // Calculate risk level
    bool has_high = false;
    bool has_medium = false;
    for (const auto& vuln : assessment.vulnerabilities) {
        if (vuln.severity == "HIGH") has_high = true;
        if (vuln.severity == "MEDIUM") has_medium = true;
    }

    if (has_high) {
        assessment.risk_level = "HIGH";
    } else if (has_medium) {
        assessment.risk_level = "MEDIUM";
    } else if (!assessment.vulnerabilities.empty()) {
        assessment.risk_level = "LOW";
    } else {
        assessment.risk_level = "NONE";
    }

    // Remove duplicate recommendations
    std::sort(assessment.recommendations.begin(), assessment.recommendations.end());
    assessment.recommendations.erase(
        std::unique(assessment.recommendations.begin(), assessment.recommendations.end()),
        assessment.recommendations.end()
    );

    return assessment;
}

// Active vulnerability assessment (attempts connection)
SecurityAssessment assess_device_active(
    sqlite3* db,
    SimpleBLE::Peripheral& peripheral,
    const SecurityAssessment& passive_assessment
) {
    SecurityAssessment assessment = passive_assessment;
    std::string address = peripheral.address();

    try {
        std::cout << "[ACTIVE SCAN] Testing " << address << " for vulnerabilities..." << std::endl;

        // Test 1: Can we connect without pairing?
        bool connected_unpaired = false;
        if (!peripheral.is_paired()) {
            try {
                peripheral.connect();
                if (peripheral.is_connected()) {
                    connected_unpaired = true;
                    assessment.vulnerabilities.push_back({
                        "Connects Without Pairing",
                        "MEDIUM",
                        "Device accepts connections without requiring pairing/authentication",
                        ""
                    });
                    assessment.recommendations.push_back("Require pairing before allowing connections");
                    std::cout << "[ACTIVE SCAN] ✓ Connected without pairing" << std::endl;
                }
            } catch (...) {
                std::cout << "[ACTIVE SCAN] ✗ Connection requires pairing" << std::endl;
            }
        }

        // Test 2: Enumerate services (if connected)
        if (peripheral.is_connected()) {
            try {
                auto services = peripheral.services();
                std::vector<std::string> service_names;

                for (auto& service : services) {
                    std::string service_uuid = service.uuid();
                    std::string service_name = decode_service_uuid(service_uuid);
                    if (!service_name.empty()) {
                        service_names.push_back(service_name);
                    }
                    service_names.push_back(service_uuid);

                    // Check for OBEX services
                    if (service_uuid.find("1105") != std::string::npos ||
                        service_uuid.find("1106") != std::string::npos) {
                        assessment.vulnerabilities.push_back({
                            "OBEX Service Accessible",
                            "HIGH",
                            "File transfer service accessible without authentication",
                            "CVE-2020-13543"
                        });
                        assessment.recommendations.push_back("Disable OBEX services");
                        std::cout << "[ACTIVE SCAN] ✓ OBEX service found" << std::endl;
                    }

                    // Check for Serial Port
                    if (service_uuid.find("1101") != std::string::npos) {
                        assessment.vulnerabilities.push_back({
                            "Serial Port Accessible",
                            "MEDIUM",
                            "Serial port service accessible without authentication",
                            ""
                        });
                        assessment.recommendations.push_back("Disable serial port or require authentication");
                        std::cout << "[ACTIVE SCAN] ✓ Serial Port found" << std::endl;
                    }

                    // Check for HID
                    if (service_uuid.find("1812") != std::string::npos) {
                        assessment.vulnerabilities.push_back({
                            "HID Service Accessible",
                            "MEDIUM",
                            "Keyboard/mouse service accessible - potential input injection",
                            ""
                        });
                        assessment.recommendations.push_back("Verify HID pairing requirements");
                        std::cout << "[ACTIVE SCAN] ✓ HID service found" << std::endl;
                    }
                }

                // Test 3: Try to read characteristics without pairing
                if (connected_unpaired && !services.empty()) {
                    int readable_without_auth = 0;
                    for (auto& service : services) {
                        auto characteristics = service.characteristics();
                        for (auto& characteristic : characteristics) {
                            if (characteristic.can_read()) {
                                try {
                                    SimpleBLE::ByteArray data = peripheral.read(
                                        SimpleBLE::BluetoothUUID(service.uuid()),
                                        SimpleBLE::BluetoothUUID(characteristic.uuid())
                                    );
                                    readable_without_auth++;
                                } catch (...) {
                                    // Read failed - good, requires auth
                                }
                            }
                        }
                    }

                    if (readable_without_auth > 0) {
                        assessment.vulnerabilities.push_back({
                            "Unauthenticated Characteristic Access",
                            "HIGH",
                            std::string("Can read ") + std::to_string(readable_without_auth) +
                            " characteristics without authentication",
                            ""
                        });
                        assessment.recommendations.push_back("Enable authentication for all characteristics");
                        std::cout << "[ACTIVE SCAN] ✓ " << readable_without_auth
                                  << " characteristics readable without auth" << std::endl;
                    }
                }

            } catch (const std::exception& e) {
                std::cerr << "[ACTIVE SCAN] Error enumerating services: " << e.what() << std::endl;
            }

            // Disconnect after testing
            try {
                peripheral.disconnect();
            } catch (...) {}
        }

        std::cout << "[ACTIVE SCAN] Complete for " << address << std::endl;

    } catch (const std::exception& e) {
        std::cerr << "[ACTIVE SCAN] Error: " << e.what() << std::endl;
    }

    // Recalculate risk level
    bool has_high = false;
    bool has_medium = false;
    for (const auto& vuln : assessment.vulnerabilities) {
        if (vuln.severity == "HIGH") has_high = true;
        if (vuln.severity == "MEDIUM") has_medium = true;
    }

    if (has_high) {
        assessment.risk_level = "HIGH";
    } else if (has_medium) {
        assessment.risk_level = "MEDIUM";
    } else if (!assessment.vulnerabilities.empty()) {
        assessment.risk_level = "LOW";
    } else {
        assessment.risk_level = "NONE";
    }

    // Remove duplicate vulnerabilities and recommendations
    std::sort(assessment.recommendations.begin(), assessment.recommendations.end());
    assessment.recommendations.erase(
        std::unique(assessment.recommendations.begin(), assessment.recommendations.end()),
        assessment.recommendations.end()
    );

    return assessment;
}

// Classic Bluetooth vulnerability assessment
SecurityAssessment assess_classic_device(const ClassicBluetooth::ClassicDevice& device) {
    SecurityAssessment assessment;
    assessment.device_address = device.address;
    assessment.risk_level = "NONE";

    // Check for OBEX services (file transfer without auth)
    for (const auto& service : device.services) {
        if (service.uuid == "1105") {  // OBEX Object Push
            Vulnerability vuln;
            vuln.name = "OBEX Object Push Service";
            vuln.severity = "HIGH";
            vuln.description = "Device accepts file transfers without authentication via OBEX Object Push";
            vuln.cve = "CVE-2020-13543";
            assessment.vulnerabilities.push_back(vuln);
            assessment.recommendations.push_back("Disable OBEX Object Push service");
            assessment.recommendations.push_back("Enable PIN protection for file transfers");
        }

        if (service.uuid == "1106") {  // OBEX File Transfer
            Vulnerability vuln;
            vuln.name = "OBEX File Transfer Service";
            vuln.severity = "HIGH";
            vuln.description = "Full filesystem access available via OBEX FTP without proper authentication";
            vuln.cve = "CVE-2020-13543";
            assessment.vulnerabilities.push_back(vuln);
            assessment.recommendations.push_back("Disable OBEX File Transfer service");
            assessment.recommendations.push_back("Restrict filesystem access permissions");
        }

        if (service.uuid == "1101") {  // Serial Port Profile (SPP)
            Vulnerability vuln;
            vuln.name = "Serial Port Profile Exposed";
            vuln.severity = "MEDIUM";
            vuln.description = "Serial port service allows unauthorized command execution";
            assessment.vulnerabilities.push_back(vuln);
            assessment.recommendations.push_back("Disable unused Serial Port services");
            assessment.recommendations.push_back("Require authentication for SPP connections");
        }

        if (service.uuid == "1812") {  // HID Service
            Vulnerability vuln;
            vuln.name = "HID Service Accessible";
            vuln.severity = "MEDIUM";
            vuln.description = "Human Interface Device service allows input injection attacks";
            assessment.vulnerabilities.push_back(vuln);
            assessment.recommendations.push_back("Verify HID pairing before accepting connections");
            assessment.recommendations.push_back("Disable HID if not needed");
        }

        if (service.uuid == "1103") {  // Dialup Networking
            Vulnerability vuln;
            vuln.name = "Dialup Networking Service";
            vuln.severity = "LOW";
            vuln.description = "Legacy DUN service may have security weaknesses";
            assessment.vulnerabilities.push_back(vuln);
            assessment.recommendations.push_back("Disable DUN if not actively used");
        }
    }

    // Check for Android devices (BlueBorne risk)
    if (device.device_class.major_class == "Phone" && device.device_class.minor_class == "Smartphone") {
        // Check if device name suggests Android
        std::string name_lower = device.name;
        std::transform(name_lower.begin(), name_lower.end(), name_lower.begin(), ::tolower);

        if (name_lower.find("android") != std::string::npos ||
            name_lower.find("galaxy") != std::string::npos ||
            name_lower.find("pixel") != std::string::npos) {
            Vulnerability vuln;
            vuln.name = "Potential BlueBorne Target";
            vuln.severity = "HIGH";
            vuln.description = "Android device may be vulnerable to BlueBorne remote code execution if unpatched";
            vuln.cve = "CVE-2017-1000251";
            assessment.vulnerabilities.push_back(vuln);
            assessment.recommendations.push_back("Update Android to latest security patches");
            assessment.recommendations.push_back("Verify BlueBorne patches are applied");
        }
    }

    // Check for IoT/Smart devices
    if (device.device_class.major_class == "Peripheral" || device.device_class.major_class == "Toy") {
        Vulnerability vuln;
        vuln.name = "IoT Device Security Risk";
        vuln.severity = "MEDIUM";
        vuln.description = "IoT and peripheral devices often have outdated firmware and weak security";
        assessment.vulnerabilities.push_back(vuln);
        assessment.recommendations.push_back("Check for firmware updates");
        assessment.recommendations.push_back("Review device pairing and authentication settings");
    }

    // Calculate risk level
    for (const auto& vuln : assessment.vulnerabilities) {
        if (vuln.severity == "HIGH") {
            assessment.risk_level = "HIGH";
            break;
        } else if (vuln.severity == "MEDIUM" && assessment.risk_level != "HIGH") {
            assessment.risk_level = "MEDIUM";
        } else if (vuln.severity == "LOW" && assessment.risk_level == "NONE") {
            assessment.risk_level = "LOW";
        }
    }

    // Add general recommendations for Classic BT
    if (!assessment.vulnerabilities.empty()) {
        assessment.recommendations.push_back("Disable Bluetooth when not in use");
        assessment.recommendations.push_back("Keep device firmware updated");
        assessment.recommendations.push_back("Set device to non-discoverable mode when not pairing");
    }

    // Remove duplicate recommendations
    std::sort(assessment.recommendations.begin(), assessment.recommendations.end());
    assessment.recommendations.erase(
        std::unique(assessment.recommendations.begin(), assessment.recommendations.end()),
        assessment.recommendations.end()
    );

    return assessment;
}

// Store security assessment in database
void store_security_assessment(sqlite3* db, const SecurityAssessment& assessment) {
    std::lock_guard<std::mutex> lock(db_mutex);

    // Convert vulnerabilities to JSON string
    std::stringstream vulns_json;
    vulns_json << "[";
    for (size_t i = 0; i < assessment.vulnerabilities.size(); i++) {
        if (i > 0) vulns_json << ",";
        vulns_json << "{\"name\":\"" << assessment.vulnerabilities[i].name << "\","
                   << "\"severity\":\"" << assessment.vulnerabilities[i].severity << "\","
                   << "\"description\":\"" << assessment.vulnerabilities[i].description << "\"";
        if (!assessment.vulnerabilities[i].cve.empty()) {
            vulns_json << ",\"cve\":\"" << assessment.vulnerabilities[i].cve << "\"";
        }
        vulns_json << "}";
    }
    vulns_json << "]";

    // Convert recommendations to JSON array
    std::stringstream recs_json;
    recs_json << "[";
    for (size_t i = 0; i < assessment.recommendations.size(); i++) {
        if (i > 0) recs_json << ",";
        recs_json << "\"" << assessment.recommendations[i] << "\"";
    }
    recs_json << "]";

    const char* upsert_sql = R"(
        INSERT INTO security_assessments (device_address, risk_level, vulnerabilities, recommendations, last_assessed)
        VALUES (?, ?, ?, ?, datetime('now'))
        ON CONFLICT(device_address)
        DO UPDATE SET risk_level = excluded.risk_level,
                      vulnerabilities = excluded.vulnerabilities,
                      recommendations = excluded.recommendations,
                      last_assessed = datetime('now');
    )";

    sqlite3_stmt* stmt;
    if (sqlite3_prepare_v2(db, upsert_sql, -1, &stmt, nullptr) == SQLITE_OK) {
        sqlite3_bind_text(stmt, 1, assessment.device_address.c_str(), -1, SQLITE_TRANSIENT);
        sqlite3_bind_text(stmt, 2, assessment.risk_level.c_str(), -1, SQLITE_TRANSIENT);
        sqlite3_bind_text(stmt, 3, vulns_json.str().c_str(), -1, SQLITE_TRANSIENT);
        sqlite3_bind_text(stmt, 4, recs_json.str().c_str(), -1, SQLITE_TRANSIENT);
        sqlite3_step(stmt);
        sqlite3_finalize(stmt);
    }
}

// Map company ID to company name
std::string get_company_name(uint16_t company_id) {
    static const std::map<uint16_t, std::string> companies = {
        {0x0001, "Nokia"}, {0x0002, "Intel"}, {0x0004, "TDK"},
        {0x0006, "Microsoft"}, {0x0007, "Lucent"}, {0x0008, "Motorola"},
        {0x0009, "Infineon"}, {0x000A, "Qualcomm"}, {0x000B, "Silicon Wave"},
        {0x000C, "Digianswer"}, {0x000D, "Texas Instruments"}, {0x000F, "Broadcom"},
        {0x0012, "CSR"}, {0x0013, "Atmel"}, {0x0014, "Mitsubishi"},
        {0x0015, "RTX"}, {0x0018, "GCT Semiconductor"}, {0x0019, "Marvell"},
        {0x001D, "Sony"}, {0x001E, "Hanback"}, {0x0020, "ST Microelectronics"},
        {0x0025, "NXP"}, {0x002E, "Plantronics"}, {0x0030, "Dynastream"},
        {0x0031, "Timex"}, {0x0039, "Bose"}, {0x003A, "Sony Ericsson"},
        {0x003C, "Harman"}, {0x003D, "NXP Semiconductors"}, {0x0046, "MediaTek"},
        {0x004C, "Apple"}, {0x004E, "LG Electronics"}, {0x0050, "Huawei"},
        {0x005B, "Toshiba"}, {0x005D, "Polar Electro"}, {0x0067, "HP"},
        {0x0075, "Samsung"}, {0x007C, "HTC"}, {0x0080, "Lenovo"},
        {0x00E0, "Google"}, {0x00E5, "Garmin"}, {0x0106, "Xiaomi"},
        {0x0117, "Fitbit"}, {0x0131, "Tile"}, {0x0157, "Xiaomi"},
        {0x0171, "Amazon"}, {0x01A0, "OnePlus"}, {0x0276, "Fitbit"},
        {0x02E5, "Garmin"}, {0x0499, "Ruuvi Innovations"}
    };

    auto it = companies.find(company_id);
    return (it != companies.end()) ? it->second : "Unknown";
}

// Calculate estimated distance from TX power and RSSI
double calculate_distance(int16_t tx_power, int16_t rssi) {
    // If TX power is invalid or not advertised, use RSSI-only estimation
    if (tx_power == -32768 || tx_power == 0) {
        // Empirical RSSI to distance mapping (calibrated for typical BLE devices at 0 dBm TX)
        // Based on real-world measurements
        if (rssi >= -35) return 0.5;   // Immediate proximity (< 0.5m)
        if (rssi >= -45) return 1.0;   // Very close (0.5-1m)
        if (rssi >= -55) return 2.0;   // Close (1-2m)
        if (rssi >= -65) return 5.0;   // Near (2-5m)
        if (rssi >= -75) return 10.0;  // Medium (5-10m)
        if (rssi >= -85) return 20.0;  // Far (10-20m)
        return 30.0;                   // Very far (>20m)
    }

    // If TX power is available, use path loss formula
    // Formula: distance = 10 ^ ((TX_Power - RSSI) / (10 * N))
    // N = 2.0 for free space, 3.0-4.0 for indoor with obstacles
    const double N = 2.0;  // More accurate for typical indoor environments

    double distance = std::pow(10.0, (tx_power - rssi) / (10.0 * N));
    return distance;
}

// Get address type as string
std::string get_address_type_string(SimpleBLE::BluetoothAddressType type) {
    switch (type) {
        case SimpleBLE::BluetoothAddressType::PUBLIC:
            return "PUBLIC";
        case SimpleBLE::BluetoothAddressType::RANDOM:
            return "RANDOM";
        default:
            return "UNSPECIFIED";
    }
}

// Enumerate characteristics for a connected device
bool enumerate_characteristics(sqlite3* db, SimpleBLE::Peripheral& peripheral) {
    std::lock_guard<std::mutex> lock(db_mutex);

    std::string address = peripheral.address();
    std::string name = peripheral.identifier();

    try {
        auto services = peripheral.services();

        for (auto& service : services) {
            std::string service_uuid = service.uuid();
            auto characteristics = service.characteristics();

            for (auto& characteristic : characteristics) {
                std::string char_uuid = characteristic.uuid();

                // Build properties string
                std::stringstream props;
                bool can_read = characteristic.can_read();
                bool can_write = characteristic.can_write_request() || characteristic.can_write_command();
                bool can_notify = characteristic.can_notify();
                bool can_indicate = characteristic.can_indicate();

                if (can_read) props << "READ,";
                if (can_write) props << "WRITE,";
                if (can_notify) props << "NOTIFY,";
                if (can_indicate) props << "INDICATE,";

                std::string properties = props.str();
                if (!properties.empty()) {
                    properties.pop_back();  // Remove trailing comma
                }

                // Insert into database
                const char* insert_sql = R"(
                    INSERT OR REPLACE INTO device_characteristics
                    (device_address, device_name, service_uuid, characteristic_uuid, properties)
                    VALUES (?, ?, ?, ?, ?);
                )";

                sqlite3_stmt* stmt;
                int rc = sqlite3_prepare_v2(db, insert_sql, -1, &stmt, nullptr);
                if (rc == SQLITE_OK) {
                    sqlite3_bind_text(stmt, 1, address.c_str(), -1, SQLITE_TRANSIENT);
                    sqlite3_bind_text(stmt, 2, name.c_str(), -1, SQLITE_TRANSIENT);
                    sqlite3_bind_text(stmt, 3, service_uuid.c_str(), -1, SQLITE_TRANSIENT);
                    sqlite3_bind_text(stmt, 4, char_uuid.c_str(), -1, SQLITE_TRANSIENT);
                    sqlite3_bind_text(stmt, 5, properties.c_str(), -1, SQLITE_TRANSIENT);
                    sqlite3_step(stmt);
                    sqlite3_finalize(stmt);
                }
            }
        }

        std::cout << "[" << get_timestamp() << "] Enumerated characteristics for " << address << std::endl;
        return true;
    } catch (const std::exception& e) {
        std::cerr << "Error enumerating characteristics for " << address << ": " << e.what() << std::endl;
        return false;
    }
}

// Connect to device and enumerate characteristics (runs in background)
void connect_and_enumerate(sqlite3* db, SimpleBLE::Peripheral peripheral) {
    std::string address = peripheral.address();

    try {
        std::cout << "[" << get_timestamp() << "] Attempting to connect to " << address << "..." << std::endl;

        peripheral.connect();

        if (peripheral.is_connected()) {
            std::cout << "[" << get_timestamp() << "] Connected to " << address << std::endl;

            enumerate_characteristics(db, peripheral);

            // Run ACTIVE security assessment after enumeration
            try {
                // First, get passive assessment from database
                SecurityAssessment passive_assessment;
                passive_assessment.device_address = address;
                passive_assessment.risk_level = "NONE";

                // Load existing passive assessment if available
                {
                    std::lock_guard<std::mutex> lock(db_mutex);
                    const char* query = "SELECT risk_level, vulnerabilities FROM security_assessments WHERE device_address = ?;";
                    sqlite3_stmt* stmt;
                    if (sqlite3_prepare_v2(db, query, -1, &stmt, nullptr) == SQLITE_OK) {
                        sqlite3_bind_text(stmt, 1, address.c_str(), -1, SQLITE_TRANSIENT);
                        if (sqlite3_step(stmt) == SQLITE_ROW) {
                            passive_assessment.risk_level = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 0));
                            // Parse vulnerabilities JSON if needed
                        }
                        sqlite3_finalize(stmt);
                    }
                }

                // Perform active assessment
                SecurityAssessment assessment = assess_device_active(db, peripheral, passive_assessment);

                store_security_assessment(db, assessment);
                std::cout << "[" << get_timestamp() << "] Active security assessment: " << address
                          << " - Risk: " << assessment.risk_level
                          << " (" << assessment.vulnerabilities.size() << " vulnerabilities)" << std::endl;

                // Try to extract additional tracking information
                try {
                    std::cout << "[INFO EXTRACT] Attempting to read device information..." << std::endl;

                    std::string manufacturer_name = "";
                    std::string model_number = "";
                    std::string firmware_version = "";
                    std::string hardware_version = "";
                    std::string serial_number = "";

                    // Look for Device Information Service (0x180A)
                    auto services = peripheral.services();
                    for (auto& service : services) {
                        std::string service_uuid = service.uuid();

                        // Device Information Service
                        if (service_uuid.find("180a") != std::string::npos ||
                            service_uuid.find("180A") != std::string::npos) {

                            auto characteristics = service.characteristics();
                            for (auto& characteristic : characteristics) {
                                std::string char_uuid = characteristic.uuid();

                                try {
                                    if (characteristic.can_read()) {
                                        SimpleBLE::ByteArray data = peripheral.read(
                                            SimpleBLE::BluetoothUUID(service.uuid()),
                                            SimpleBLE::BluetoothUUID(characteristic.uuid())
                                        );

                                        std::string value(data.begin(), data.end());

                                        // Manufacturer Name (0x2A29)
                                        if (char_uuid.find("2a29") != std::string::npos ||
                                            char_uuid.find("2A29") != std::string::npos) {
                                            manufacturer_name = value;
                                            std::cout << "[INFO EXTRACT] Manufacturer: " << value << std::endl;
                                        }
                                        // Model Number (0x2A24)
                                        else if (char_uuid.find("2a24") != std::string::npos ||
                                                 char_uuid.find("2A24") != std::string::npos) {
                                            model_number = value;
                                            std::cout << "[INFO EXTRACT] Model: " << value << std::endl;
                                        }
                                        // Firmware Version (0x2A26)
                                        else if (char_uuid.find("2a26") != std::string::npos ||
                                                 char_uuid.find("2A26") != std::string::npos) {
                                            firmware_version = value;
                                            std::cout << "[INFO EXTRACT] Firmware: " << value << std::endl;
                                        }
                                        // Hardware Version (0x2A27)
                                        else if (char_uuid.find("2a27") != std::string::npos ||
                                                 char_uuid.find("2A27") != std::string::npos) {
                                            hardware_version = value;
                                            std::cout << "[INFO EXTRACT] Hardware: " << value << std::endl;
                                        }
                                        // Serial Number (0x2A25)
                                        else if (char_uuid.find("2a25") != std::string::npos ||
                                                 char_uuid.find("2A25") != std::string::npos) {
                                            serial_number = value;
                                            std::cout << "[INFO EXTRACT] Serial: " << value << std::endl;
                                        }
                                    }
                                } catch (...) {
                                    // Some characteristics may require pairing/encryption
                                }
                            }
                        }
                    }

                    // Store tracking data
                    {
                        std::lock_guard<std::mutex> lock(db_mutex);
                        const char* upsert_sql = R"(
                            INSERT INTO device_tracking_data
                            (device_address, manufacturer_name, device_model, firmware_version, hardware_version, serial_number, last_updated)
                            VALUES (?, ?, ?, ?, ?, ?, datetime('now'))
                            ON CONFLICT(device_address)
                            DO UPDATE SET
                                manufacturer_name = COALESCE(excluded.manufacturer_name, manufacturer_name),
                                device_model = COALESCE(excluded.device_model, device_model),
                                firmware_version = COALESCE(excluded.firmware_version, firmware_version),
                                hardware_version = COALESCE(excluded.hardware_version, hardware_version),
                                serial_number = COALESCE(excluded.serial_number, serial_number),
                                last_updated = datetime('now');
                        )";

                        sqlite3_stmt* stmt;
                        if (sqlite3_prepare_v2(db, upsert_sql, -1, &stmt, nullptr) == SQLITE_OK) {
                            sqlite3_bind_text(stmt, 1, address.c_str(), -1, SQLITE_TRANSIENT);
                            sqlite3_bind_text(stmt, 2, manufacturer_name.empty() ? nullptr : manufacturer_name.c_str(), -1, SQLITE_TRANSIENT);
                            sqlite3_bind_text(stmt, 3, model_number.empty() ? nullptr : model_number.c_str(), -1, SQLITE_TRANSIENT);
                            sqlite3_bind_text(stmt, 4, firmware_version.empty() ? nullptr : firmware_version.c_str(), -1, SQLITE_TRANSIENT);
                            sqlite3_bind_text(stmt, 5, hardware_version.empty() ? nullptr : hardware_version.c_str(), -1, SQLITE_TRANSIENT);
                            sqlite3_bind_text(stmt, 6, serial_number.empty() ? nullptr : serial_number.c_str(), -1, SQLITE_TRANSIENT);
                            sqlite3_step(stmt);
                            sqlite3_finalize(stmt);
                        }
                    }

                } catch (const std::exception& e) {
                    std::cerr << "[INFO EXTRACT] Error: " << e.what() << std::endl;
                }

            } catch (const std::exception& e) {
                std::cerr << "Error assessing security for " << address << ": " << e.what() << std::endl;
            }

            std::this_thread::sleep_for(std::chrono::seconds(1));
            peripheral.disconnect();
            std::cout << "[" << get_timestamp() << "] Disconnected from " << address << std::endl;
        }
    } catch (const std::exception& e) {
        std::cerr << "Error connecting to " << address << ": " << e.what() << std::endl;
    }
}

// Get current timestamp in ISO 8601 format
std::string get_timestamp() {
    auto now = std::chrono::system_clock::now();
    auto time_t_now = std::chrono::system_clock::to_time_t(now);
    auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(
        now.time_since_epoch()) % 1000;

    std::stringstream ss;
    ss << std::put_time(std::localtime(&time_t_now), "%Y-%m-%d %H:%M:%S");
    ss << '.' << std::setfill('0') << std::setw(3) << ms.count();
    return ss.str();
}

// Initialize SQLite database
bool init_database(sqlite3** db) {
    int rc = sqlite3_open(config.db_path.c_str(), db);
    if (rc != SQLITE_OK) {
        std::cerr << "Cannot open database: " << sqlite3_errmsg(*db) << std::endl;
        return false;
    }

    const char* create_table_sql = R"(
        CREATE TABLE IF NOT EXISTS ble_scans (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            timestamp DATETIME DEFAULT CURRENT_TIMESTAMP,
            device_address TEXT NOT NULL,
            device_name TEXT,
            rssi INTEGER,
            manufacturer_data TEXT,
            scan_date DATE,
            scan_time TIME,
            scan_hour INTEGER,
            scan_minute INTEGER,
            address_type TEXT,
            tx_power INTEGER,
            mtu INTEGER,
            is_connectable BOOLEAN,
            service_uuids TEXT,
            company_id INTEGER,
            company_name TEXT,
            estimated_distance REAL,
            protocol_type TEXT DEFAULT 'BLE',
            device_class_major TEXT,
            device_class_minor TEXT,
            device_class_cod INTEGER,
            sdp_services TEXT
        );

        CREATE INDEX IF NOT EXISTS idx_timestamp ON ble_scans(timestamp);
        CREATE INDEX IF NOT EXISTS idx_scan_date ON ble_scans(scan_date);
        CREATE INDEX IF NOT EXISTS idx_scan_time ON ble_scans(scan_time);
        CREATE INDEX IF NOT EXISTS idx_device_address ON ble_scans(device_address);
        CREATE INDEX IF NOT EXISTS idx_scan_hour ON ble_scans(scan_hour);
        CREATE INDEX IF NOT EXISTS idx_company_name ON ble_scans(company_name);

        CREATE TABLE IF NOT EXISTS device_distance_history (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            timestamp DATETIME DEFAULT CURRENT_TIMESTAMP,
            device_address TEXT NOT NULL,
            device_name TEXT,
            rssi INTEGER,
            tx_power INTEGER,
            estimated_distance REAL,
            scan_date DATE,
            scan_hour INTEGER
        );

        CREATE INDEX IF NOT EXISTS idx_distance_timestamp ON device_distance_history(timestamp);
        CREATE INDEX IF NOT EXISTS idx_distance_device ON device_distance_history(device_address);
        CREATE INDEX IF NOT EXISTS idx_distance_date ON device_distance_history(scan_date);

        CREATE TABLE IF NOT EXISTS device_characteristics (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            discovered_at DATETIME DEFAULT CURRENT_TIMESTAMP,
            device_address TEXT NOT NULL,
            device_name TEXT,
            service_uuid TEXT,
            characteristic_uuid TEXT,
            properties TEXT,
            UNIQUE(device_address, service_uuid, characteristic_uuid)
        );

        CREATE INDEX IF NOT EXISTS idx_char_device ON device_characteristics(device_address);

        CREATE TABLE IF NOT EXISTS device_nicknames (
            device_address TEXT PRIMARY KEY,
            nickname TEXT NOT NULL,
            created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
            updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
        );

        CREATE TABLE IF NOT EXISTS security_assessments (
            device_address TEXT PRIMARY KEY,
            risk_level TEXT NOT NULL,
            vulnerabilities TEXT,
            recommendations TEXT,
            last_assessed DATETIME DEFAULT CURRENT_TIMESTAMP
        );

        CREATE INDEX IF NOT EXISTS idx_security_risk ON security_assessments(risk_level);

        CREATE TABLE IF NOT EXISTS device_tracking_data (
            device_address TEXT PRIMARY KEY,
            device_type TEXT,
            device_model TEXT,
            manufacturer_name TEXT,
            firmware_version TEXT,
            hardware_version TEXT,
            serial_number TEXT,
            apple_continuity_data TEXT,
            pairing_status TEXT,
            last_seen_location TEXT,
            tracking_identifiers TEXT,
            additional_info TEXT,
            last_updated DATETIME DEFAULT CURRENT_TIMESTAMP
        );

        CREATE INDEX IF NOT EXISTS idx_tracking_device ON device_tracking_data(device_address);
    )";

    char* err_msg = nullptr;
    rc = sqlite3_exec(*db, create_table_sql, nullptr, nullptr, &err_msg);
    if (rc != SQLITE_OK) {
        std::cerr << "SQL error: " << err_msg << std::endl;
        sqlite3_free(err_msg);
        return false;
    }

    std::cout << "Database initialized: " << config.db_path << std::endl;
    return true;
}

// Log BLE scan result to database with enhanced fields
bool log_scan_result(sqlite3* db, SimpleBLE::Peripheral& peripheral) {
    std::lock_guard<std::mutex> lock(db_mutex);

    auto now = std::chrono::system_clock::now();
    auto time_t_now = std::chrono::system_clock::to_time_t(now);
    auto tm_now = std::localtime(&time_t_now);

    std::string address = peripheral.address();
    std::string name = peripheral.identifier();
    int rssi = peripheral.rssi();
    int16_t tx_power = peripheral.tx_power();
    uint16_t mtu = peripheral.mtu();
    bool is_connectable = peripheral.is_connectable();
    std::string address_type = get_address_type_string(peripheral.address_type());

    // Extract manufacturer data
    std::string manufacturer_data = "";
    uint16_t company_id = 0;
    std::string company_name = "";
    auto mfg_data = peripheral.manufacturer_data();
    if (!mfg_data.empty()) {
        std::stringstream ss;
        for (const auto& pair : mfg_data) {
            company_id = pair.first;  // Use the first company ID found
            company_name = get_company_name(company_id);
            ss << std::hex << std::setfill('0') << std::setw(4) << pair.first << ":";
            for (uint8_t byte : pair.second) {
                ss << std::hex << std::setfill('0') << std::setw(2) << (int)byte;
            }
            ss << ";";
        }
        manufacturer_data = ss.str();
    }

    // Get service UUIDs
    std::string service_uuids = "";
    auto services = peripheral.services();
    if (!services.empty()) {
        std::stringstream ss;
        for (size_t i = 0; i < services.size(); i++) {
            ss << services[i].uuid();
            if (i < services.size() - 1) ss << ",";
        }
        service_uuids = ss.str();
    }

    // Calculate estimated distance
    double estimated_distance = calculate_distance(tx_power, rssi);

    const char* insert_sql = R"(
        INSERT INTO ble_scans
        (device_address, device_name, rssi, manufacturer_data, scan_date, scan_time, scan_hour, scan_minute,
         address_type, tx_power, mtu, is_connectable, service_uuids, company_id, company_name, estimated_distance)
        VALUES (?, ?, ?, ?, date('now', 'localtime'), time('now', 'localtime'), ?, ?,
                ?, ?, ?, ?, ?, ?, ?, ?);
    )";

    sqlite3_stmt* stmt;
    int rc = sqlite3_prepare_v2(db, insert_sql, -1, &stmt, nullptr);
    if (rc != SQLITE_OK) {
        std::cerr << "Failed to prepare statement: " << sqlite3_errmsg(db) << std::endl;
        return false;
    }

    sqlite3_bind_text(stmt, 1, address.c_str(), -1, SQLITE_TRANSIENT);
    sqlite3_bind_text(stmt, 2, name.c_str(), -1, SQLITE_TRANSIENT);
    sqlite3_bind_int(stmt, 3, rssi);
    sqlite3_bind_text(stmt, 4, manufacturer_data.c_str(), -1, SQLITE_TRANSIENT);
    sqlite3_bind_int(stmt, 5, tm_now->tm_hour);
    sqlite3_bind_int(stmt, 6, tm_now->tm_min);
    sqlite3_bind_text(stmt, 7, address_type.c_str(), -1, SQLITE_TRANSIENT);
    sqlite3_bind_int(stmt, 8, tx_power);
    sqlite3_bind_int(stmt, 9, mtu);
    sqlite3_bind_int(stmt, 10, is_connectable ? 1 : 0);
    sqlite3_bind_text(stmt, 11, service_uuids.c_str(), -1, SQLITE_TRANSIENT);
    sqlite3_bind_int(stmt, 12, company_id);
    sqlite3_bind_text(stmt, 13, company_name.c_str(), -1, SQLITE_TRANSIENT);
    if (estimated_distance >= 0) {
        sqlite3_bind_double(stmt, 14, estimated_distance);
    } else {
        sqlite3_bind_null(stmt, 14);
    }

    rc = sqlite3_step(stmt);
    sqlite3_finalize(stmt);

    if (rc != SQLITE_DONE) {
        std::cerr << "Failed to insert data: " << sqlite3_errmsg(db) << std::endl;
        return false;
    }

    // Also log to distance history if distance is available
    if (estimated_distance >= 0) {
        const char* distance_sql = R"(
            INSERT INTO device_distance_history
            (device_address, device_name, rssi, tx_power, estimated_distance, scan_date, scan_hour)
            VALUES (?, ?, ?, ?, ?, date('now', 'localtime'), ?);
        )";

        sqlite3_stmt* dist_stmt;
        rc = sqlite3_prepare_v2(db, distance_sql, -1, &dist_stmt, nullptr);
        if (rc == SQLITE_OK) {
            sqlite3_bind_text(dist_stmt, 1, address.c_str(), -1, SQLITE_TRANSIENT);
            sqlite3_bind_text(dist_stmt, 2, name.c_str(), -1, SQLITE_TRANSIENT);
            sqlite3_bind_int(dist_stmt, 3, rssi);
            sqlite3_bind_int(dist_stmt, 4, tx_power);
            sqlite3_bind_double(dist_stmt, 5, estimated_distance);
            sqlite3_bind_int(dist_stmt, 6, tm_now->tm_hour);
            sqlite3_step(dist_stmt);
            sqlite3_finalize(dist_stmt);
        }
    }

    return true;
}

// Log Classic Bluetooth device to database
bool log_classic_device(sqlite3* db, const ClassicBluetooth::ClassicDevice& device) {
    std::lock_guard<std::mutex> lock(db_mutex);

    auto now = std::chrono::system_clock::now();
    auto time_t_now = std::chrono::system_clock::to_time_t(now);
    auto tm_now = std::localtime(&time_t_now);

    // Serialize SDP services to JSON
    std::stringstream sdp_json;
    sdp_json << "[";
    for (size_t i = 0; i < device.services.size(); i++) {
        sdp_json << "{\"uuid\":\"" << device.services[i].uuid << "\","
                 << "\"name\":\"" << device.services[i].name << "\","
                 << "\"rfcomm_channel\":" << (int)device.services[i].rfcomm_channel << "}";
        if (i < device.services.size() - 1) sdp_json << ",";
    }
    sdp_json << "]";

    const char* insert_sql = R"(
        INSERT INTO ble_scans
        (device_address, device_name, rssi, scan_date, scan_time, scan_hour, scan_minute,
         is_connectable, company_name, protocol_type, device_class_major, device_class_minor,
         device_class_cod, sdp_services)
        VALUES (?, ?, ?, date('now', 'localtime'), time('now', 'localtime'), ?, ?,
                ?, ?, 'CLASSIC', ?, ?, ?, ?);
    )";

    sqlite3_stmt* stmt;
    int rc = sqlite3_prepare_v2(db, insert_sql, -1, &stmt, nullptr);
    if (rc != SQLITE_OK) {
        std::cerr << "Failed to prepare statement: " << sqlite3_errmsg(db) << std::endl;
        return false;
    }

    sqlite3_bind_text(stmt, 1, device.address.c_str(), -1, SQLITE_TRANSIENT);
    sqlite3_bind_text(stmt, 2, device.name.c_str(), -1, SQLITE_TRANSIENT);
    sqlite3_bind_int(stmt, 3, device.rssi);
    sqlite3_bind_int(stmt, 4, tm_now->tm_hour);
    sqlite3_bind_int(stmt, 5, tm_now->tm_min);
    sqlite3_bind_int(stmt, 6, device.is_connected ? 1 : 0);
    sqlite3_bind_text(stmt, 7, "Classic Bluetooth", -1, SQLITE_TRANSIENT);
    sqlite3_bind_text(stmt, 8, device.device_class.major_class.c_str(), -1, SQLITE_TRANSIENT);
    sqlite3_bind_text(stmt, 9, device.device_class.minor_class.c_str(), -1, SQLITE_TRANSIENT);
    sqlite3_bind_int(stmt, 10, device.device_class.class_of_device);
    sqlite3_bind_text(stmt, 11, sdp_json.str().c_str(), -1, SQLITE_TRANSIENT);

    rc = sqlite3_step(stmt);
    sqlite3_finalize(stmt);

    if (rc != SQLITE_DONE) {
        std::cerr << "Failed to insert Classic device: " << sqlite3_errmsg(db) << std::endl;
        return false;
    }

    return true;
}

// Perform BLE scan
void perform_scan(sqlite3* db) {
    auto adapters = SimpleBLE::Adapter::get_adapters();

    if (adapters.empty()) {
        std::cerr << "No Bluetooth adapters found" << std::endl;
        return;
    }

    auto adapter = adapters[0];
    std::cout << "Using adapter: " << adapter.identifier() << " [" << adapter.address() << "]" << std::endl;

    adapter.set_callback_on_scan_found([&](SimpleBLE::Peripheral peripheral) {
        std::string address = peripheral.address();
        std::string name = peripheral.identifier();
        int rssi = peripheral.rssi();
        int16_t tx_power = peripheral.tx_power();
        double distance = calculate_distance(tx_power, rssi);
        bool is_connectable = peripheral.is_connectable();

        std::cout << "[" << get_timestamp() << "] Found: " << address
                  << " | Name: " << (name.empty() ? "<unnamed>" : name)
                  << " | RSSI: " << rssi << " dBm";

        if (distance >= 0) {
            std::cout << " | Distance: ~" << std::fixed << std::setprecision(1) << distance << "m";
        }

        // Extract company name and decode Apple data
        std::string company_name = "Unknown";
        AppleContinuityData apple_data;
        auto mfg_data = peripheral.manufacturer_data();
        if (!mfg_data.empty()) {
            for (const auto& pair : mfg_data) {
                company_name = get_company_name(pair.first);
                std::cout << " | " << company_name;

                // If Apple device, decode continuity data
                if (pair.first == 0x004C) {  // Apple company ID
                    apple_data = decode_apple_continuity(pair.second);

                    // Log decoded Apple data
                    if (!apple_data.device_type.empty()) {
                        std::cout << " [" << apple_data.device_type << "]";
                    }
                    if (apple_data.battery_level >= 0) {
                        std::cout << " [Battery: " << apple_data.battery_level << "%]";
                    }
                    if (!apple_data.airpods_left_battery.empty()) {
                        std::cout << " [L:" << apple_data.airpods_left_battery
                                  << " R:" << apple_data.airpods_right_battery
                                  << " Case:" << apple_data.airpods_case_battery << "]";
                    }

                    // Store Apple continuity data
                    try {
                        std::lock_guard<std::mutex> lock(db_mutex);
                        std::stringstream apple_json;
                        apple_json << "{"
                                   << "\"device_type\":\"" << apple_data.device_type << "\","
                                   << "\"battery\":" << apple_data.battery_level << ","
                                   << "\"airpods_left\":\"" << apple_data.airpods_left_battery << "\","
                                   << "\"airpods_right\":\"" << apple_data.airpods_right_battery << "\","
                                   << "\"airpods_case\":\"" << apple_data.airpods_case_battery << "\","
                                   << "\"in_ear\":" << (apple_data.airpods_in_ear ? "true" : "false") << ","
                                   << "\"case_open\":" << (apple_data.airpods_case_lid_open ? "true" : "false") << ","
                                   << "\"handoff\":\"" << apple_data.handoff_data << "\","
                                   << "\"raw\":\"" << apple_data.raw_data << "\""
                                   << "}";

                        const char* upsert_sql = R"(
                            INSERT INTO device_tracking_data (device_address, device_type, apple_continuity_data, last_updated)
                            VALUES (?, ?, ?, datetime('now'))
                            ON CONFLICT(device_address)
                            DO UPDATE SET apple_continuity_data = excluded.apple_continuity_data, last_updated = datetime('now');
                        )";

                        sqlite3_stmt* stmt;
                        if (sqlite3_prepare_v2(db, upsert_sql, -1, &stmt, nullptr) == SQLITE_OK) {
                            sqlite3_bind_text(stmt, 1, address.c_str(), -1, SQLITE_TRANSIENT);
                            sqlite3_bind_text(stmt, 2, apple_data.device_type.c_str(), -1, SQLITE_TRANSIENT);
                            sqlite3_bind_text(stmt, 3, apple_json.str().c_str(), -1, SQLITE_TRANSIENT);
                            sqlite3_step(stmt);
                            sqlite3_finalize(stmt);
                        }
                    } catch (...) {}
                }
                break;  // Show first company only
            }
        }

        if (is_connectable) {
            std::cout << " | Connectable";
        }

        std::cout << std::endl;

        log_scan_result(db, peripheral);

        // Perform PASSIVE security assessment immediately (no connection needed)
        try {
            SecurityAssessment passive_assessment = assess_device_passive(
                address,
                peripheral.identifier(),
                company_name,
                is_connectable,
                ""  // manufacturer_data - could extract from peripheral if available
            );

            // Store passive assessment
            store_security_assessment(db, passive_assessment);
            std::cout << "[PASSIVE SCAN] " << address << " - Risk: " << passive_assessment.risk_level;
            if (!passive_assessment.vulnerabilities.empty()) {
                std::cout << " (" << passive_assessment.vulnerabilities.size() << " issues)";
            }
            std::cout << std::endl;
        } catch (const std::exception& e) {
            std::cerr << "Error in passive assessment: " << e.what() << std::endl;
        }

        // Optionally connect to connectable devices we haven't enumerated yet
        if (is_connectable) {
            std::lock_guard<std::mutex> lock(enumerated_mutex);
            if (enumerated_devices.find(address) == enumerated_devices.end()) {
                enumerated_devices.insert(address);

                // Launch connection in background thread
                std::thread([db, peripheral]() mutable {
                    connect_and_enumerate(db, peripheral);
                }).detach();
            }
        }
    });

    // Initialize Classic Bluetooth scanner
    ClassicBluetooth::Scanner classic_scanner;
    classic_scanner.set_device_found_callback([db](const ClassicBluetooth::ClassicDevice& device) {
        std::cout << "[" << get_timestamp() << "] Classic BT Found: " << device.address
                  << " | Name: " << device.name
                  << " | RSSI: " << device.rssi << " dBm"
                  << " | Class: " << device.device_class.major_class
                  << " (" << device.device_class.minor_class << ")"
                  << " | Services: " << device.services.size()
                  << std::endl;

        // Perform security assessment
        SecurityAssessment assessment = assess_classic_device(device);
        if (!assessment.vulnerabilities.empty()) {
            std::cout << "[CLASSIC SECURITY] " << device.address
                      << " - Risk: " << assessment.risk_level
                      << " (" << assessment.vulnerabilities.size() << " vulnerabilities)"
                      << std::endl;
            store_security_assessment(db, assessment);
        }

        // Log to database
        log_classic_device(db, device);
    });

    int scan_cycle = 0;
    while (running) {
        try {
            // BLE scan every cycle
            std::cout << "\n[" << get_timestamp() << "] Starting BLE scan..." << std::endl;
            adapter.scan_for(config.scan_duration_ms);
            std::cout << "[" << get_timestamp() << "] BLE scan complete." << std::endl;

            // Classic Bluetooth inquiry every 3 cycles (less frequent due to longer duration)
            if (scan_cycle % 3 == 0) {
                std::cout << "[" << get_timestamp() << "] Starting Classic Bluetooth inquiry..." << std::endl;
                classic_scanner.start_inquiry(10);  // 10 second inquiry

                // Wait for inquiry to complete
                std::this_thread::sleep_for(std::chrono::seconds(11));
                std::cout << "[" << get_timestamp() << "] Classic Bluetooth inquiry complete." << std::endl;
            }

            scan_cycle++;
            std::cout << "[" << get_timestamp() << "] Scan cycle " << scan_cycle << " complete. Waiting..." << std::endl;
            std::this_thread::sleep_for(std::chrono::milliseconds(config.scan_interval_ms));
        } catch (const std::exception& e) {
            std::cerr << "Scan error: " << e.what() << std::endl;
            std::this_thread::sleep_for(std::chrono::seconds(5));
        }
    }
}

// HTTP API handlers
void setup_http_server(httplib::Server& server, sqlite3* db) {
    // Add CORS headers to all responses
    server.set_post_routing_handler([](const httplib::Request&, httplib::Response& res) {
        res.set_header("Access-Control-Allow-Origin", "*");
        res.set_header("Access-Control-Allow-Methods", "GET, POST, DELETE, OPTIONS");
        res.set_header("Access-Control-Allow-Headers", "Content-Type");
    });

    // Handle preflight OPTIONS requests for CORS
    server.Options(R"(/.*)", [](const httplib::Request&, httplib::Response& res) {
        res.status = 204;
    });

    // Health check endpoint
    server.Get("/health", [](const httplib::Request&, httplib::Response& res) {
        res.set_content("{\"status\":\"ok\"}", "application/json");
    });

    // Get recent scans
    server.Get("/scans/recent", [db](const httplib::Request& req, httplib::Response& res) {
        int limit = 100;
        if (req.has_param("limit")) {
            limit = std::stoi(req.get_param_value("limit"));
        }

        std::lock_guard<std::mutex> lock(db_mutex);

        std::string query = "SELECT timestamp, device_address, device_name, rssi, address_type, "
                           "tx_power, mtu, is_connectable, service_uuids, company_name, estimated_distance, "
                           "protocol_type, device_class_major, device_class_minor, sdp_services "
                           "FROM ble_scans ORDER BY timestamp DESC LIMIT ?;";

        sqlite3_stmt* stmt;
        if (sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, nullptr) != SQLITE_OK) {
            res.status = 500;
            res.set_content("{\"error\":\"Database error\"}", "application/json");
            return;
        }

        sqlite3_bind_int(stmt, 1, limit);

        std::stringstream json;
        json << "{\"scans\":[";
        bool first = true;

        while (sqlite3_step(stmt) == SQLITE_ROW) {
            if (!first) json << ",";
            first = false;

            json << "{\"timestamp\":\"" << sqlite3_column_text(stmt, 0) << "\","
                 << "\"address\":\"" << sqlite3_column_text(stmt, 1) << "\","
                 << "\"name\":\"" << (sqlite3_column_text(stmt, 2) ? (const char*)sqlite3_column_text(stmt, 2) : "") << "\","
                 << "\"rssi\":" << sqlite3_column_int(stmt, 3) << ","
                 << "\"address_type\":\"" << (sqlite3_column_text(stmt, 4) ? (const char*)sqlite3_column_text(stmt, 4) : "") << "\","
                 << "\"tx_power\":" << sqlite3_column_int(stmt, 5) << ","
                 << "\"mtu\":" << sqlite3_column_int(stmt, 6) << ","
                 << "\"is_connectable\":" << (sqlite3_column_int(stmt, 7) ? "true" : "false") << ","
                 << "\"service_uuids\":\"" << (sqlite3_column_text(stmt, 8) ? (const char*)sqlite3_column_text(stmt, 8) : "") << "\","
                 << "\"company_name\":\"" << (sqlite3_column_text(stmt, 9) ? (const char*)sqlite3_column_text(stmt, 9) : "") << "\"";

            if (sqlite3_column_type(stmt, 10) != SQLITE_NULL) {
                json << ",\"distance\":" << std::fixed << std::setprecision(1) << sqlite3_column_double(stmt, 10);
            }

            json << ",\"protocol_type\":\"" << (sqlite3_column_text(stmt, 11) ? (const char*)sqlite3_column_text(stmt, 11) : "BLE") << "\"";

            if (sqlite3_column_type(stmt, 12) != SQLITE_NULL) {
                json << ",\"device_class_major\":\"" << sqlite3_column_text(stmt, 12) << "\"";
            }
            if (sqlite3_column_type(stmt, 13) != SQLITE_NULL) {
                json << ",\"device_class_minor\":\"" << sqlite3_column_text(stmt, 13) << "\"";
            }
            if (sqlite3_column_type(stmt, 14) != SQLITE_NULL) {
                json << ",\"sdp_services\":" << sqlite3_column_text(stmt, 14);
            }

            json << "}";
        }

        json << "]}";
        sqlite3_finalize(stmt);

        res.set_content(json.str(), "application/json");
    });

    // Query by date
    server.Get("/scans/date/:date", [db](const httplib::Request& req, httplib::Response& res) {
        std::string date = req.path_params.at("date");

        std::lock_guard<std::mutex> lock(db_mutex);

        std::string query = "SELECT timestamp, device_address, device_name, rssi FROM ble_scans "
                           "WHERE scan_date = ? ORDER BY timestamp;";

        sqlite3_stmt* stmt;
        if (sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, nullptr) != SQLITE_OK) {
            res.status = 500;
            res.set_content("{\"error\":\"Database error\"}", "application/json");
            return;
        }

        sqlite3_bind_text(stmt, 1, date.c_str(), -1, SQLITE_TRANSIENT);

        std::stringstream json;
        json << "{\"date\":\"" << date << "\",\"scans\":[";
        bool first = true;

        while (sqlite3_step(stmt) == SQLITE_ROW) {
            if (!first) json << ",";
            first = false;

            json << "{\"timestamp\":\"" << sqlite3_column_text(stmt, 0) << "\","
                 << "\"address\":\"" << sqlite3_column_text(stmt, 1) << "\","
                 << "\"name\":\"" << sqlite3_column_text(stmt, 2) << "\","
                 << "\"rssi\":" << sqlite3_column_int(stmt, 3) << "}";
        }

        json << "]}";
        sqlite3_finalize(stmt);

        res.set_content(json.str(), "application/json");
    });

    // Query by hour range
    server.Get("/scans/hour/:hour", [db](const httplib::Request& req, httplib::Response& res) {
        int hour = std::stoi(req.path_params.at("hour"));

        std::lock_guard<std::mutex> lock(db_mutex);

        std::string query = "SELECT timestamp, device_address, device_name, rssi FROM ble_scans "
                           "WHERE scan_hour = ? ORDER BY timestamp DESC LIMIT 1000;";

        sqlite3_stmt* stmt;
        if (sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, nullptr) != SQLITE_OK) {
            res.status = 500;
            res.set_content("{\"error\":\"Database error\"}", "application/json");
            return;
        }

        sqlite3_bind_int(stmt, 1, hour);

        std::stringstream json;
        json << "{\"hour\":" << hour << ",\"scans\":[";
        bool first = true;

        while (sqlite3_step(stmt) == SQLITE_ROW) {
            if (!first) json << ",";
            first = false;

            json << "{\"timestamp\":\"" << sqlite3_column_text(stmt, 0) << "\","
                 << "\"address\":\"" << sqlite3_column_text(stmt, 1) << "\","
                 << "\"name\":\"" << sqlite3_column_text(stmt, 2) << "\","
                 << "\"rssi\":" << sqlite3_column_int(stmt, 3) << "}";
        }

        json << "]}";
        sqlite3_finalize(stmt);

        res.set_content(json.str(), "application/json");
    });

    // Statistics endpoint
    server.Get("/stats", [db](const httplib::Request&, httplib::Response& res) {
        std::lock_guard<std::mutex> lock(db_mutex);

        std::string query = "SELECT COUNT(*) as total, "
                           "COUNT(DISTINCT device_address) as unique_devices, "
                           "MIN(timestamp) as first_scan, "
                           "MAX(timestamp) as last_scan FROM ble_scans;";

        sqlite3_stmt* stmt;
        if (sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, nullptr) != SQLITE_OK) {
            res.status = 500;
            res.set_content("{\"error\":\"Database error\"}", "application/json");
            return;
        }

        std::stringstream json;
        if (sqlite3_step(stmt) == SQLITE_ROW) {
            json << "{\"total_scans\":" << sqlite3_column_int(stmt, 0) << ","
                 << "\"unique_devices\":" << sqlite3_column_int(stmt, 1) << ","
                 << "\"first_scan\":\"" << sqlite3_column_text(stmt, 2) << "\","
                 << "\"last_scan\":\"" << sqlite3_column_text(stmt, 3) << "\"}";
        }

        sqlite3_finalize(stmt);
        res.set_content(json.str(), "application/json");
    });

    // Get device scan count
    server.Get("/device/:address/count", [db](const httplib::Request& req, httplib::Response& res) {
        std::string address = req.path_params.at("address");
        std::lock_guard<std::mutex> lock(db_mutex);

        std::string query = "SELECT COUNT(*) as count FROM ble_scans WHERE device_address = ?;";
        sqlite3_stmt* stmt;

        if (sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, nullptr) != SQLITE_OK) {
            res.status = 500;
            res.set_content("{\"error\":\"Database error\"}", "application/json");
            return;
        }

        sqlite3_bind_text(stmt, 1, address.c_str(), -1, SQLITE_TRANSIENT);

        std::stringstream json;
        if (sqlite3_step(stmt) == SQLITE_ROW) {
            json << "{\"address\":\"" << address << "\","
                 << "\"count\":" << sqlite3_column_int(stmt, 0) << "}";
        } else {
            json << "{\"address\":\"" << address << "\",\"count\":0}";
        }

        sqlite3_finalize(stmt);
        res.set_content(json.str(), "application/json");
    });

    // Get distance history for a device
    server.Get("/distance/:address", [db](const httplib::Request& req, httplib::Response& res) {
        std::string address = req.path_params.at("address");
        int limit = req.has_param("limit") ? std::stoi(req.get_param_value("limit")) : 100;

        std::lock_guard<std::mutex> lock(db_mutex);

        std::string query = "SELECT timestamp, rssi, tx_power, estimated_distance FROM device_distance_history "
                           "WHERE device_address = ? ORDER BY timestamp DESC LIMIT ?;";

        sqlite3_stmt* stmt;
        if (sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, nullptr) != SQLITE_OK) {
            res.status = 500;
            res.set_content("{\"error\":\"Database error\"}", "application/json");
            return;
        }

        sqlite3_bind_text(stmt, 1, address.c_str(), -1, SQLITE_TRANSIENT);
        sqlite3_bind_int(stmt, 2, limit);

        std::stringstream json;
        json << "{\"address\":\"" << address << "\",\"history\":[";
        bool first = true;

        while (sqlite3_step(stmt) == SQLITE_ROW) {
            if (!first) json << ",";
            first = false;

            json << "{\"timestamp\":\"" << sqlite3_column_text(stmt, 0) << "\","
                 << "\"rssi\":" << sqlite3_column_int(stmt, 1) << ","
                 << "\"tx_power\":" << sqlite3_column_int(stmt, 2) << ","
                 << "\"distance\":" << std::fixed << std::setprecision(1) << sqlite3_column_double(stmt, 3) << "}";
        }

        json << "]}";
        sqlite3_finalize(stmt);
        res.set_content(json.str(), "application/json");
    });

    // Get characteristics for a device
    server.Get("/characteristics/:address", [db](const httplib::Request& req, httplib::Response& res) {
        std::string address = req.path_params.at("address");

        std::lock_guard<std::mutex> lock(db_mutex);

        std::string query = "SELECT service_uuid, characteristic_uuid, properties, discovered_at "
                           "FROM device_characteristics WHERE device_address = ? ORDER BY discovered_at DESC;";

        sqlite3_stmt* stmt;
        if (sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, nullptr) != SQLITE_OK) {
            res.status = 500;
            res.set_content("{\"error\":\"Database error\"}", "application/json");
            return;
        }

        sqlite3_bind_text(stmt, 1, address.c_str(), -1, SQLITE_TRANSIENT);

        std::stringstream json;
        json << "{\"address\":\"" << address << "\",\"characteristics\":[";
        bool first = true;

        while (sqlite3_step(stmt) == SQLITE_ROW) {
            if (!first) json << ",";
            first = false;

            std::string service_uuid = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 0));
            std::string char_uuid = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 1));
            std::string properties = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 2));

            std::string service_name = decode_service_uuid(service_uuid);
            std::string char_name = decode_characteristic_uuid(char_uuid);
            std::string char_desc = get_characteristic_description(char_uuid);

            json << "{\"service\":\"" << service_uuid << "\","
                 << "\"service_name\":\"" << service_name << "\","
                 << "\"characteristic\":\"" << char_uuid << "\","
                 << "\"characteristic_name\":\"" << char_name << "\","
                 << "\"description\":\"" << char_desc << "\","
                 << "\"properties\":\"" << properties << "\","
                 << "\"discovered_at\":\"" << sqlite3_column_text(stmt, 3) << "\"}";
        }

        json << "]}";
        sqlite3_finalize(stmt);
        res.set_content(json.str(), "application/json");
    });

    // Read characteristic value
    server.Get("/read/:address/:service/:characteristic", [](const httplib::Request& req, httplib::Response& res) {
        std::string address = req.path_params.at("address");
        std::string service_uuid = req.path_params.at("service");
        std::string char_uuid = req.path_params.at("characteristic");

        try {
            auto adapters = SimpleBLE::Adapter::get_adapters();
            if (adapters.empty()) {
                res.status = 500;
                res.set_content("{\"error\":\"No Bluetooth adapters found\"}", "application/json");
                return;
            }

            auto adapter = adapters[0];
            auto peripherals = adapter.scan_get_results();

            SimpleBLE::Peripheral target_peripheral;
            bool found = false;

            for (auto& peripheral : peripherals) {
                if (peripheral.identifier() == address || peripheral.address() == address) {
                    target_peripheral = peripheral;
                    found = true;
                    break;
                }
            }

            if (!found) {
                res.status = 404;
                res.set_content("{\"error\":\"Device not found or not in range\"}", "application/json");
                return;
            }

            if (!target_peripheral.is_connected()) {
                std::cout << "[READ] Connecting to " << address << "..." << std::endl;
                target_peripheral.connect();
                std::this_thread::sleep_for(std::chrono::milliseconds(1000));
            }

            SimpleBLE::BluetoothUUID service(service_uuid);
            SimpleBLE::BluetoothUUID characteristic(char_uuid);

            SimpleBLE::ByteArray data = target_peripheral.read(service, characteristic);

            // Disconnect after reading
            if (target_peripheral.is_connected()) {
                target_peripheral.disconnect();
            }

            // Convert byte array to hex string and interpret based on characteristic type
            std::stringstream json;
            json << "{\"address\":\"" << address << "\","
                 << "\"service\":\"" << service_uuid << "\","
                 << "\"characteristic\":\"" << char_uuid << "\","
                 << "\"raw\":\"";

            for (uint8_t byte : data) {
                json << std::hex << std::setw(2) << std::setfill('0') << (int)byte;
            }
            json << "\",";

            // Decode specific known characteristics
            std::string upper_char = char_uuid;
            std::transform(upper_char.begin(), upper_char.end(), upper_char.begin(), ::toupper);

            if (upper_char.find("2A19") != std::string::npos && data.size() >= 1) {
                // Battery Level (0-100%)
                json << "\"value\":" << (int)data[0] << ","
                     << "\"unit\":\"%\",\"type\":\"battery\"";
            } else if (upper_char.find("2A00") != std::string::npos ||
                       upper_char.find("2A29") != std::string::npos ||
                       upper_char.find("2A24") != std::string::npos ||
                       upper_char.find("2A26") != std::string::npos) {
                // String characteristics (Device Name, Manufacturer, Model, Firmware)
                std::string text(data.begin(), data.end());
                json << "\"value\":\"" << text << "\",\"type\":\"string\"";
            } else if (upper_char.find("2A6E") != std::string::npos && data.size() >= 2) {
                // Temperature (signed 16-bit)
                int16_t temp = (data[1] << 8) | data[0];
                json << "\"value\":" << (temp / 100.0) << ","
                     << "\"unit\":\"°C\",\"type\":\"temperature\"";
            } else if (upper_char.find("2A37") != std::string::npos && data.size() >= 2) {
                // Heart Rate
                uint8_t bpm = data[1];
                json << "\"value\":" << (int)bpm << ","
                     << "\"unit\":\"bpm\",\"type\":\"heart_rate\"";
            } else {
                json << "\"value\":null,\"type\":\"unknown\"";
            }

            json << "}";
            res.set_content(json.str(), "application/json");

        } catch (const std::exception& e) {
            std::cerr << "[READ] Error: " << e.what() << std::endl;

            std::string error_msg = e.what();
            std::stringstream json;

            // Check for encryption/pairing errors
            if (error_msg.find("Encryption") != std::string::npos ||
                error_msg.find("insufficient") != std::string::npos ||
                error_msg.find("Authentication") != std::string::npos) {
                res.status = 403;
                json << "{\"error\":\"Device requires pairing/bonding\","
                     << "\"details\":\"This characteristic is encrypted and requires you to pair with the device first. "
                     << "Pair via System Settings → Bluetooth, then try again.\","
                     << "\"requires_pairing\":true}";
            } else if (error_msg.find("not in range") != std::string::npos ||
                       error_msg.find("not found") != std::string::npos) {
                res.status = 404;
                json << "{\"error\":\"Device not found\","
                     << "\"details\":\"Device is not currently in range or not responding.\"}";
            } else if (error_msg.find("timeout") != std::string::npos ||
                       error_msg.find("Timed out") != std::string::npos) {
                res.status = 504;
                json << "{\"error\":\"Connection timeout\","
                     << "\"details\":\"Device did not respond in time. It may be too far away or busy.\"}";
            } else {
                res.status = 500;
                json << "{\"error\":\"" << error_msg << "\"}";
            }

            res.set_content(json.str(), "application/json");
        }
    });

    // ESP32 sensor data ingestion endpoint
    server.Post("/esp32/scan", [db](const httplib::Request& req, httplib::Response& res) {
        std::lock_guard<std::mutex> lock(db_mutex);

        try {
            // Parse JSON from ESP32
            std::string body = req.body;
            std::cout << "[ESP32] Received data from sensor node (" << body.length() << " bytes)" << std::endl;

            // Very basic JSON parsing (production should use a proper JSON library)
            size_t device_name_pos = body.find("\"device_name\":\"");
            std::string device_name = "ESP32";
            if (device_name_pos != std::string::npos) {
                size_t start = device_name_pos + 15;
                size_t end = body.find("\"", start);
                device_name = body.substr(start, end - start);
            }

            // Extract scans array
            size_t scans_pos = body.find("\"scans\":[");
            if (scans_pos == std::string::npos) {
                res.status = 400;
                res.set_content("{\"status\":\"error\",\"message\":\"No scans array found\"}", "application/json");
                return;
            }

            // Count devices by looking for address fields
            int device_count = 0;
            size_t pos = 0;
            while ((pos = body.find("\"address\":", pos)) != std::string::npos) {
                device_count++;

                // Extract device data
                size_t addr_start = body.find("\"", pos + 10) + 1;
                size_t addr_end = body.find("\"", addr_start);
                std::string address = body.substr(addr_start, addr_end - addr_start);

                // Extract name
                size_t name_pos = body.find("\"name\":\"", pos);
                std::string name = "";
                if (name_pos != std::string::npos && name_pos < pos + 500) {
                    size_t name_start = name_pos + 8;
                    size_t name_end = body.find("\"", name_start);
                    name = body.substr(name_start, name_end - name_start);
                }

                // Extract RSSI
                size_t rssi_pos = body.find("\"rssi\":", pos);
                int rssi = 0;
                if (rssi_pos != std::string::npos && rssi_pos < pos + 500) {
                    size_t rssi_start = rssi_pos + 7;
                    size_t rssi_end = body.find_first_of(",}", rssi_start);
                    rssi = std::stoi(body.substr(rssi_start, rssi_end - rssi_start));
                }

                // Extract company_name
                size_t company_pos = body.find("\"company_name\":\"", pos);
                std::string company = "";
                if (company_pos != std::string::npos && company_pos < pos + 500) {
                    size_t company_start = company_pos + 16;
                    size_t company_end = body.find("\"", company_start);
                    company = body.substr(company_start, company_end - company_start);
                }

                // Insert into database with source indication
                const char* insert_sql = R"(
                    INSERT INTO ble_scans
                    (device_address, device_name, rssi, manufacturer_data, scan_date, scan_time, scan_hour, scan_minute, company_name)
                    VALUES (?, ?, ?, ?, date('now', 'localtime'), time('now', 'localtime'), ?, ?, ?);
                )";

                sqlite3_stmt* stmt;
                if (sqlite3_prepare_v2(db, insert_sql, -1, &stmt, nullptr) == SQLITE_OK) {
                    auto now = std::chrono::system_clock::now();
                    auto time_t_now = std::chrono::system_clock::to_time_t(now);
                    auto tm_now = std::localtime(&time_t_now);

                    std::string source_data = "ESP32:" + device_name;

                    sqlite3_bind_text(stmt, 1, address.c_str(), -1, SQLITE_TRANSIENT);
                    sqlite3_bind_text(stmt, 2, name.c_str(), -1, SQLITE_TRANSIENT);
                    sqlite3_bind_int(stmt, 3, rssi);
                    sqlite3_bind_text(stmt, 4, source_data.c_str(), -1, SQLITE_TRANSIENT);
                    sqlite3_bind_int(stmt, 5, tm_now->tm_hour);
                    sqlite3_bind_int(stmt, 6, tm_now->tm_min);
                    sqlite3_bind_text(stmt, 7, company.c_str(), -1, SQLITE_TRANSIENT);

                    sqlite3_step(stmt);
                    sqlite3_finalize(stmt);
                }

                pos = addr_end;
            }

            std::cout << "[ESP32] Stored " << device_count << " scans from " << device_name << std::endl;

            std::stringstream json;
            json << "{\"status\":\"ok\",\"received\":" << device_count << ",\"source\":\"" << device_name << "\"}";
            res.set_content(json.str(), "application/json");

        } catch (const std::exception& e) {
            std::cerr << "[ESP32] Error processing data: " << e.what() << std::endl;
            res.status = 500;
            res.set_content("{\"status\":\"error\",\"message\":\"Processing error\"}", "application/json");
        }
    });

    // Get device nickname
    server.Get("/nickname/:address", [db](const httplib::Request& req, httplib::Response& res) {
        std::string address = req.path_params.at("address");
        std::lock_guard<std::mutex> lock(db_mutex);

        std::string query = "SELECT nickname FROM device_nicknames WHERE device_address = ?;";
        sqlite3_stmt* stmt;

        if (sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, nullptr) != SQLITE_OK) {
            res.status = 500;
            res.set_content("{\"error\":\"Database error\"}", "application/json");
            return;
        }

        sqlite3_bind_text(stmt, 1, address.c_str(), -1, SQLITE_TRANSIENT);

        if (sqlite3_step(stmt) == SQLITE_ROW) {
            std::string nickname = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 0));
            std::stringstream json;
            json << "{\"address\":\"" << address << "\",\"nickname\":\"" << nickname << "\"}";
            res.set_content(json.str(), "application/json");
        } else {
            res.status = 404;
            res.set_content("{\"error\":\"No nickname found\"}", "application/json");
        }

        sqlite3_finalize(stmt);
    });

    // Set device nickname
    server.Post("/nickname/:address", [db](const httplib::Request& req, httplib::Response& res) {
        std::string address = req.path_params.at("address");
        std::string body = req.body;

        // Extract nickname from JSON body
        size_t nickname_pos = body.find("\"nickname\":\"");
        if (nickname_pos == std::string::npos) {
            res.status = 400;
            res.set_content("{\"error\":\"Missing nickname field\"}", "application/json");
            return;
        }

        size_t nickname_start = nickname_pos + 12;
        size_t nickname_end = body.find("\"", nickname_start);
        std::string nickname = body.substr(nickname_start, nickname_end - nickname_start);

        std::lock_guard<std::mutex> lock(db_mutex);

        const char* upsert_sql = R"(
            INSERT INTO device_nicknames (device_address, nickname, updated_at)
            VALUES (?, ?, datetime('now'))
            ON CONFLICT(device_address)
            DO UPDATE SET nickname = excluded.nickname, updated_at = datetime('now');
        )";

        sqlite3_stmt* stmt;
        if (sqlite3_prepare_v2(db, upsert_sql, -1, &stmt, nullptr) != SQLITE_OK) {
            res.status = 500;
            res.set_content("{\"error\":\"Database error\"}", "application/json");
            return;
        }

        sqlite3_bind_text(stmt, 1, address.c_str(), -1, SQLITE_TRANSIENT);
        sqlite3_bind_text(stmt, 2, nickname.c_str(), -1, SQLITE_TRANSIENT);

        if (sqlite3_step(stmt) == SQLITE_DONE) {
            std::stringstream json;
            json << "{\"status\":\"ok\",\"address\":\"" << address << "\",\"nickname\":\"" << nickname << "\"}";
            res.set_content(json.str(), "application/json");
        } else {
            res.status = 500;
            res.set_content("{\"error\":\"Failed to save nickname\"}", "application/json");
        }

        sqlite3_finalize(stmt);
    });

    // Delete device nickname
    server.Delete("/nickname/:address", [db](const httplib::Request& req, httplib::Response& res) {
        std::string address = req.path_params.at("address");
        std::lock_guard<std::mutex> lock(db_mutex);

        const char* delete_sql = "DELETE FROM device_nicknames WHERE device_address = ?;";
        sqlite3_stmt* stmt;

        if (sqlite3_prepare_v2(db, delete_sql, -1, &stmt, nullptr) != SQLITE_OK) {
            res.status = 500;
            res.set_content("{\"error\":\"Database error\"}", "application/json");
            return;
        }

        sqlite3_bind_text(stmt, 1, address.c_str(), -1, SQLITE_TRANSIENT);

        if (sqlite3_step(stmt) == SQLITE_DONE) {
            res.set_content("{\"status\":\"ok\"}", "application/json");
        } else {
            res.status = 500;
            res.set_content("{\"error\":\"Failed to delete nickname\"}", "application/json");
        }

        sqlite3_finalize(stmt);
    });

    // Get all nicknames
    server.Get("/nicknames", [db](const httplib::Request&, httplib::Response& res) {
        std::lock_guard<std::mutex> lock(db_mutex);

        std::string query = "SELECT device_address, nickname FROM device_nicknames;";
        sqlite3_stmt* stmt;

        if (sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, nullptr) != SQLITE_OK) {
            res.status = 500;
            res.set_content("{\"error\":\"Database error\"}", "application/json");
            return;
        }

        std::stringstream json;
        json << "{\"nicknames\":{";
        bool first = true;

        while (sqlite3_step(stmt) == SQLITE_ROW) {
            if (!first) json << ",";
            first = false;

            std::string address = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 0));
            std::string nickname = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 1));
            json << "\"" << address << "\":\"" << nickname << "\"";
        }

        json << "}}";
        sqlite3_finalize(stmt);
        res.set_content(json.str(), "application/json");
    });

    // Get security assessment for a device
    server.Get("/security/:address", [db](const httplib::Request& req, httplib::Response& res) {
        std::string address = req.path_params.at("address");
        std::lock_guard<std::mutex> lock(db_mutex);

        std::string query = "SELECT risk_level, vulnerabilities, recommendations, last_assessed "
                           "FROM security_assessments WHERE device_address = ?;";
        sqlite3_stmt* stmt;

        if (sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, nullptr) != SQLITE_OK) {
            res.status = 500;
            res.set_content("{\"error\":\"Database error\"}", "application/json");
            return;
        }

        sqlite3_bind_text(stmt, 1, address.c_str(), -1, SQLITE_TRANSIENT);

        if (sqlite3_step(stmt) == SQLITE_ROW) {
            std::string risk_level = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 0));
            std::string vulnerabilities = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 1));
            std::string recommendations = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 2));
            std::string last_assessed = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 3));

            std::stringstream json;
            json << "{\"address\":\"" << address << "\","
                 << "\"risk_level\":\"" << risk_level << "\","
                 << "\"vulnerabilities\":" << vulnerabilities << ","
                 << "\"recommendations\":" << recommendations << ","
                 << "\"last_assessed\":\"" << last_assessed << "\"}";

            res.set_content(json.str(), "application/json");
        } else {
            res.status = 404;
            res.set_content("{\"error\":\"No security assessment found\",\"message\":\"Device not yet assessed\"}", "application/json");
        }

        sqlite3_finalize(stmt);
    });

    // Get all security assessments
    server.Get("/security", [db](const httplib::Request&, httplib::Response& res) {
        std::lock_guard<std::mutex> lock(db_mutex);

        std::string query = "SELECT device_address, risk_level, last_assessed FROM security_assessments ORDER BY risk_level DESC;";
        sqlite3_stmt* stmt;

        if (sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, nullptr) != SQLITE_OK) {
            res.status = 500;
            res.set_content("{\"error\":\"Database error\"}", "application/json");
            return;
        }

        std::stringstream json;
        json << "{\"assessments\":[";
        bool first = true;

        while (sqlite3_step(stmt) == SQLITE_ROW) {
            if (!first) json << ",";
            first = false;

            std::string address = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 0));
            std::string risk_level = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 1));
            std::string last_assessed = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 2));

            json << "{\"address\":\"" << address << "\","
                 << "\"risk_level\":\"" << risk_level << "\","
                 << "\"last_assessed\":\"" << last_assessed << "\"}";
        }

        json << "]}";
        sqlite3_finalize(stmt);
        res.set_content(json.str(), "application/json");
    });

    // Get tracking data for a device
    server.Get("/tracking/:address", [db](const httplib::Request& req, httplib::Response& res) {
        std::string address = req.path_params.at("address");
        std::lock_guard<std::mutex> lock(db_mutex);

        std::string query = "SELECT * FROM device_tracking_data WHERE device_address = ?;";
        sqlite3_stmt* stmt;

        if (sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, nullptr) != SQLITE_OK) {
            res.status = 500;
            res.set_content("{\"error\":\"Database error\"}", "application/json");
            return;
        }

        sqlite3_bind_text(stmt, 1, address.c_str(), -1, SQLITE_TRANSIENT);

        if (sqlite3_step(stmt) == SQLITE_ROW) {
            std::stringstream json;
            json << "{\"address\":\"" << address << "\",";

            // Get all columns
            if (sqlite3_column_text(stmt, 1)) json << "\"device_type\":\"" << sqlite3_column_text(stmt, 1) << "\",";
            if (sqlite3_column_text(stmt, 2)) json << "\"device_model\":\"" << sqlite3_column_text(stmt, 2) << "\",";
            if (sqlite3_column_text(stmt, 3)) json << "\"manufacturer_name\":\"" << sqlite3_column_text(stmt, 3) << "\",";
            if (sqlite3_column_text(stmt, 4)) json << "\"firmware_version\":\"" << sqlite3_column_text(stmt, 4) << "\",";
            if (sqlite3_column_text(stmt, 5)) json << "\"hardware_version\":\"" << sqlite3_column_text(stmt, 5) << "\",";
            if (sqlite3_column_text(stmt, 6)) json << "\"serial_number\":\"" << sqlite3_column_text(stmt, 6) << "\",";
            if (sqlite3_column_text(stmt, 7)) json << "\"apple_continuity\":" << sqlite3_column_text(stmt, 7) << ",";
            if (sqlite3_column_text(stmt, 8)) json << "\"pairing_status\":\"" << sqlite3_column_text(stmt, 8) << "\",";
            if (sqlite3_column_text(stmt, 11)) json << "\"additional_info\":\"" << sqlite3_column_text(stmt, 11) << "\",";
            json << "\"last_updated\":\"" << sqlite3_column_text(stmt, 12) << "\"}";

            res.set_content(json.str(), "application/json");
        } else {
            res.status = 404;
            res.set_content("{\"error\":\"No tracking data found\"}", "application/json");
        }

        sqlite3_finalize(stmt);
    });
}

int main(int argc, char* argv[]) {
    std::cout << "Bluehound v1.0" << std::endl;
    std::cout << "==============\n" << std::endl;

    // Setup signal handlers
    signal(SIGINT, signal_handler);
    signal(SIGTERM, signal_handler);

    // Initialize database
    sqlite3* db;
    if (!init_database(&db)) {
        return 1;
    }

    // Start HTTP server in separate thread
    std::thread http_thread;
    httplib::Server server;

    if (config.enable_http_server) {
        setup_http_server(server, db);

        http_thread = std::thread([&server]() {
            std::cout << "Starting HTTP server on port " << config.http_port << std::endl;
            std::cout << "API Endpoints:" << std::endl;
            std::cout << "  - GET /health" << std::endl;
            std::cout << "  - GET /scans/recent?limit=N" << std::endl;
            std::cout << "  - GET /scans/date/YYYY-MM-DD" << std::endl;
            std::cout << "  - GET /scans/hour/HH" << std::endl;
            std::cout << "  - GET /stats\n" << std::endl;

            server.listen("0.0.0.0", config.http_port);
        });
    }

    // Start BLE scanning
    perform_scan(db);

    // Cleanup
    if (config.enable_http_server) {
        server.stop();
        if (http_thread.joinable()) {
            http_thread.join();
        }
    }

    sqlite3_close(db);
    std::cout << "Shutdown complete." << std::endl;

    return 0;
}
