/**
 * ============================================================================
 * WEB SERVER IMPLEMENTATION
 * ============================================================================
 * 
 * HTTP server with SD card file serving and REST API for operator interface:
 * - Serves HTML5/JavaScript dashboard from /sdcard/www/
 * - REST API endpoints for scan control and status
 * - File upload/download capabilities
 * - Basic authentication support
 * - Real-time status updates via polling
 * 
 * Maintains complete isolation from target network operations.
 */

#include "web_server.h"
#include "sd_manager.h"
#include "scanner_engine.h"
#include "network_manager.h"
#include "security_manager.h"
#include "ota_manager.h"
#include <esp_log.h>
#include <esp_http_server.h>
#include <esp_vfs.h>
#include <sys/param.h>
#include <sys/unistd.h>
#include <sys/stat.h>
#include <dirent.h>
#include <cJSON.h>
#include <esp_timer.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

static const char *TAG = "WEB_SERVER";

static httpd_handle_t s_server = NULL;

// Web server statistics
typedef struct {
    uint32_t requests_total;
    uint32_t requests_failed;
    uint32_t bytes_sent;
    uint32_t bytes_received;
} web_server_stats_t;



// WebSocket functionality commented out - not available in standard ESP-IDF
// Will use polling or Server-Sent Events instead

// Define MAX_CONCURRENT_SCANS if not defined
#ifndef MAX_CONCURRENT_SCANS
#define MAX_CONCURRENT_SCANS 4
#endif

// Add scan time tracking
static uint32_t s_last_scan_time = 0;

// Add scan results storage
typedef struct {
    uint32_t scan_id;
    uint32_t timestamp;
    char target_range[256];
    uint32_t device_count;
    bool completed;
} scan_result_t;



// Helper function to parse target range
static esp_err_t parse_target_range(const char* range_str, char* parsed_range, size_t max_len) {
    if (range_str == NULL || parsed_range == NULL) {
        return ESP_ERR_INVALID_ARG;
    }
    
    // Basic validation and copying
    if (strlen(range_str) >= max_len) {
        return ESP_ERR_INVALID_SIZE;
    }
    
    strncpy(parsed_range, range_str, max_len - 1);
    parsed_range[max_len - 1] = '\0';
    
    // TODO: Add proper IP range validation
    // For now, just copy the string
    
    return ESP_OK;
}

// Forward declarations
static esp_err_t index_handler(httpd_req_t *req);
static esp_err_t file_handler(httpd_req_t *req);
static esp_err_t api_system_status_handler(httpd_req_t *req);
static esp_err_t api_scan_start_handler(httpd_req_t *req);
static esp_err_t api_scan_status_handler(httpd_req_t *req);
static esp_err_t api_scan_results_handler(httpd_req_t *req);
static esp_err_t api_logs_list_handler(httpd_req_t *req);
static esp_err_t api_config_get_handler(httpd_req_t *req);
static esp_err_t api_config_set_handler(httpd_req_t *req);
static esp_err_t api_ota_status_handler(httpd_req_t *req);
static esp_err_t api_ota_start_handler(httpd_req_t *req);
static esp_err_t api_ota_cancel_handler(httpd_req_t *req);
static esp_err_t api_devices_handler(httpd_req_t *req);
static esp_err_t api_system_reboot_handler(httpd_req_t *req);
static esp_err_t api_scan_stop_handler(httpd_req_t *req);
static esp_err_t api_config_network_handler(httpd_req_t *req);
static esp_err_t api_config_security_handler(httpd_req_t *req);
static esp_err_t api_system_reset_handler(httpd_req_t *req);
static esp_err_t api_logs_download_handler(httpd_req_t *req);

// Helper functions
static void broadcast_ws_message(const char *message) {
    // WebSocket not available - implement polling or SSE instead
    ESP_LOGD(TAG, "Would broadcast: %s", message);
}

// Input validation for file paths
static bool is_safe_file_path(const char* path)
{
    if (path == NULL) {
        return false;
    }
    
    // Check for directory traversal attempts
    if (strstr(path, "..") != NULL) {
        ESP_LOGW(TAG, "Directory traversal attempt detected: %s", path);
        return false;
    }
    
    // Check for absolute paths
    if (path[0] == '/') {
        ESP_LOGW(TAG, "Absolute path attempt detected: %s", path);
        return false;
    }
    
    // Check for null bytes or other dangerous characters
    for (int i = 0; path[i] != '\0'; i++) {
        if (path[i] == '\0' || path[i] == '\n' || path[i] == '\r' || path[i] == '\t') {
            ESP_LOGW(TAG, "Dangerous character in path: %s", path);
            return false;
        }
    }
    
    return true;
}

// Sanitize file path
static esp_err_t sanitize_file_path(const char* input_path, char* output_path, size_t output_size)
{
    if (input_path == NULL || output_path == NULL || output_size == 0) {
        return ESP_ERR_INVALID_ARG;
    }
    
    // Validate input path
    if (!is_safe_file_path(input_path)) {
        return ESP_ERR_INVALID_ARG;
    }
    
    // Ensure output buffer is large enough
    if (strlen(input_path) >= output_size) {
        ESP_LOGW(TAG, "Path too long: %s", input_path);
        return ESP_ERR_INVALID_ARG;
    }
    
    // Copy and sanitize path
    strncpy(output_path, input_path, output_size - 1);
    output_path[output_size - 1] = '\0';
    
    // Remove any leading slashes
    while (output_path[0] == '/') {
        memmove(output_path, output_path + 1, strlen(output_path));
    }
    
    return ESP_OK;
}

// Scan status broadcasting
static scan_request_t s_active_scans[MAX_CONCURRENT_SCANS];

void broadcast_scan_status(uint32_t scan_id) {
    bool has_active_scan = false;
    scan_request_t scan = {0};
    
    for (int i = 0; i < MAX_CONCURRENT_SCANS; i++) {
        if (s_active_scans[i].status == SCAN_STATUS_RUNNING) {
            scan = s_active_scans[i];
            has_active_scan = true;
            break;
        }
    }

    // Create status JSON
    cJSON *status = cJSON_CreateObject();
    cJSON_AddStringToObject(status, "type", "scan_status");
    
    if (has_active_scan) {
        cJSON_AddNumberToObject(status, "scan_id", scan_id);
        cJSON_AddStringToObject(status, "status", "running");
        cJSON_AddNumberToObject(status, "progress", scan.progress_percent);
        cJSON_AddNumberToObject(status, "devices_found", scan.devices_found);
    } else {
        cJSON_AddStringToObject(status, "status", "idle");
    }

    char *json_str = cJSON_Print(status);
    if (json_str) {
        broadcast_ws_message(json_str);
        free(json_str);
    }
    
    cJSON_Delete(status);
}



// Polling endpoint for status updates
static esp_err_t api_poll_handler(httpd_req_t *req) {
    cJSON *root = cJSON_CreateObject();
    
    // Add system status
    cJSON *system = cJSON_CreateObject();
    cJSON_AddNumberToObject(system, "uptime", esp_timer_get_time() / 1000000);
    cJSON_AddNumberToObject(system, "free_heap", esp_get_free_heap_size());
    cJSON_AddItemToObject(root, "system", system);
    
    // Add active scans
    cJSON *scans = cJSON_CreateArray();
    for (int i = 0; i < MAX_CONCURRENT_SCANS; i++) {
        if (s_active_scans[i].status == SCAN_STATUS_RUNNING) {
            cJSON *scan = cJSON_CreateObject();
            cJSON_AddNumberToObject(scan, "id", s_active_scans[i].scan_id);
            cJSON_AddNumberToObject(scan, "progress", s_active_scans[i].progress_percent);
            cJSON_AddItemToArray(scans, scan);
        }
    }
    cJSON_AddItemToObject(root, "scans", scans);
    
    char *response = cJSON_Print(root);
    httpd_resp_set_type(req, "application/json");
    httpd_resp_send(req, response, strlen(response));
    
    free(response);
    cJSON_Delete(root);
    return ESP_OK;
}

/**
 * Initialize HTTP web server
 */
esp_err_t web_server_init(void) {
    ESP_LOGI(TAG, "Starting HTTP web server");
    
    // Create WebSocket mutex
    // s_ws_mutex = xSemaphoreCreateMutex(); // Removed as WebSocket is commented out
    // if (!s_ws_mutex) {
    //     ESP_LOGE(TAG, "Failed to create WebSocket mutex");
    //     return ESP_FAIL;
    // }
    
    // Initialize WebSocket clients
    // memset(s_ws_clients, 0, sizeof(s_ws_clients)); // Removed as WebSocket is commented out
    
    // Create WebSocket send task
    // xTaskCreate(ws_async_send_task, "ws_send", 4096, NULL, 5, NULL); // Removed as WebSocket is commented out
    
    httpd_config_t config = HTTPD_DEFAULT_CONFIG();
    config.lru_purge_enable = true;
    config.server_port = WEB_SERVER_PORT;
    config.max_uri_handlers = 20;
    config.max_open_sockets = 8;
    config.stack_size = WEB_SERVER_STACK_SIZE;
    config.uri_match_fn = httpd_uri_match_wildcard;
    
    esp_err_t ret = httpd_start(&s_server, &config);
    if (ret != ESP_OK) {
        ESP_LOGE(TAG, "Failed to start HTTP server: %s", esp_err_to_name(ret));
        return ret;
    }
    
    // Register URI handlers
    ret = web_server_register_handlers(s_server);
    if (ret != ESP_OK) {
        ESP_LOGE(TAG, "Failed to register handlers: %s", esp_err_to_name(ret));
        httpd_stop(s_server);
        s_server = NULL;
        return ret;
    }
    
    ESP_LOGI(TAG, "HTTP server started on port %d", WEB_SERVER_PORT);
    return ESP_OK;
}

/**
 * Stop HTTP web server
 */
esp_err_t web_server_stop(void) {
    if (s_server) {
        esp_err_t ret = httpd_stop(s_server);
        s_server = NULL;
        return ret;
    }
    return ESP_OK;
}

/**
 * Update system status for web interface
 */
void web_server_update_status(void) {
    // This function can be used to update any server-side status
    // Currently, status is fetched on-demand via API calls
}

/**
 * Register URI handlers
 */
esp_err_t web_server_register_handlers(httpd_handle_t server) {
    esp_err_t ret = ESP_OK;
    
    // Root handler - serve index.html
    httpd_uri_t index_uri = {
        .uri = "/",
        .method = HTTP_GET,
        .handler = index_handler,
        .user_ctx = NULL
    };
    ret = httpd_register_uri_handler(server, &index_uri);
    if (ret != ESP_OK) return ret;
    
    // Static file handler
    httpd_uri_t file_uri = {
        .uri = "/*",
        .method = HTTP_GET,
        .handler = file_handler,
        .user_ctx = NULL
    };
    ret = httpd_register_uri_handler(server, &file_uri);
    if (ret != ESP_OK) return ret;
    
    // API endpoints
    httpd_uri_t api_system_status = {
        .uri = API_SYSTEM_STATUS,
        .method = HTTP_GET,
        .handler = api_system_status_handler,
        .user_ctx = NULL
    };
    ret = httpd_register_uri_handler(server, &api_system_status);
    if (ret != ESP_OK) return ret;
    
    httpd_uri_t api_scan_start = {
        .uri = API_SCAN_START,
        .method = HTTP_POST,
        .handler = api_scan_start_handler,
        .user_ctx = NULL
    };
    ret = httpd_register_uri_handler(server, &api_scan_start);
    if (ret != ESP_OK) return ret;
    
    httpd_uri_t api_scan_status = {
        .uri = API_SCAN_STATUS,
        .method = HTTP_GET,
        .handler = api_scan_status_handler,
        .user_ctx = NULL
    };
    ret = httpd_register_uri_handler(server, &api_scan_status);
    if (ret != ESP_OK) return ret;
    
    httpd_uri_t api_scan_results = {
        .uri = API_SCAN_RESULTS,
        .method = HTTP_GET,
        .handler = api_scan_results_handler,
        .user_ctx = NULL
    };
    ret = httpd_register_uri_handler(server, &api_scan_results);
    if (ret != ESP_OK) return ret;
    
    httpd_uri_t api_logs_list = {
        .uri = API_LOGS_LIST,
        .method = HTTP_GET,
        .handler = api_logs_list_handler,
        .user_ctx = NULL
    };
    ret = httpd_register_uri_handler(server, &api_logs_list);
    if (ret != ESP_OK) return ret;
    
    httpd_uri_t api_config_get = {
        .uri = API_CONFIG_GET,
        .method = HTTP_GET,
        .handler = api_config_get_handler,
        .user_ctx = NULL
    };
    ret = httpd_register_uri_handler(server, &api_config_get);
    if (ret != ESP_OK) return ret;
    
    httpd_uri_t api_config_set = {
        .uri = API_CONFIG_SET,
        .method = HTTP_POST,
        .handler = api_config_set_handler,
        .user_ctx = NULL
    };
    ret = httpd_register_uri_handler(server, &api_config_set);
    if (ret != ESP_OK) return ret;
    
    // OTA update handlers
    httpd_uri_t api_ota_status = {
        .uri = "/api/ota/status",
        .method = HTTP_GET,
        .handler = api_ota_status_handler,
        .user_ctx = NULL
    };
    ret = httpd_register_uri_handler(server, &api_ota_status);
    if (ret != ESP_OK) return ret;
    
    httpd_uri_t api_ota_start = {
        .uri = "/api/ota/start",
        .method = HTTP_POST,
        .handler = api_ota_start_handler,
        .user_ctx = NULL
    };
    ret = httpd_register_uri_handler(server, &api_ota_start);
    if (ret != ESP_OK) return ret;
    
    httpd_uri_t api_ota_cancel = {
        .uri = "/api/ota/cancel",
        .method = HTTP_POST,
        .handler = api_ota_cancel_handler,
        .user_ctx = NULL
    };
    ret = httpd_register_uri_handler(server, &api_ota_cancel);
    if (ret != ESP_OK) return ret;
    
    // Devices handler
    httpd_uri_t api_devices = {
        .uri = "/api/devices",
        .method = HTTP_GET,
        .handler = api_devices_handler,
        .user_ctx = NULL
    };
    ret = httpd_register_uri_handler(server, &api_devices);
    if (ret != ESP_OK) return ret;
    
    // System reboot handler
    httpd_uri_t api_system_reboot = {
        .uri = "/api/system/reboot",
        .method = HTTP_POST,
        .handler = api_system_reboot_handler,
        .user_ctx = NULL
    };
    ret = httpd_register_uri_handler(server, &api_system_reboot);
    if (ret != ESP_OK) return ret;
    
    // Scan stop handler
    httpd_uri_t api_scan_stop = {
        .uri = "/api/scan/stop/*",
        .method = HTTP_POST,
        .handler = api_scan_stop_handler,
        .user_ctx = NULL
    };
    ret = httpd_register_uri_handler(server, &api_scan_stop);
    if (ret != ESP_OK) return ret;
    
    // Config network handler
    httpd_uri_t api_config_network = {
        .uri = "/api/config/network",
        .method = HTTP_GET,
        .handler = api_config_network_handler,
        .user_ctx = NULL
    };
    ret = httpd_register_uri_handler(server, &api_config_network);
    if (ret != ESP_OK) return ret;
    
    // Config security handler
    httpd_uri_t api_config_security = {
        .uri = "/api/config/security",
        .method = HTTP_GET,
        .handler = api_config_security_handler,
        .user_ctx = NULL
    };
    ret = httpd_register_uri_handler(server, &api_config_security);
    if (ret != ESP_OK) return ret;
    
    // System reset handler
    httpd_uri_t api_system_reset = {
        .uri = "/api/system/reset",
        .method = HTTP_POST,
        .handler = api_system_reset_handler,
        .user_ctx = NULL
    };
    ret = httpd_register_uri_handler(server, &api_system_reset);
    if (ret != ESP_OK) return ret;
    
    // Log download handler
    httpd_uri_t api_logs_download = {
        .uri = "/api/logs/download/*",
        .method = HTTP_GET,
        .handler = api_logs_download_handler,
        .user_ctx = NULL
    };
    ret = httpd_register_uri_handler(server, &api_logs_download);
    if (ret != ESP_OK) return ret;
    
    // Polling endpoint (replaces WebSocket)
    httpd_uri_t api_poll = {
        .uri = "/api/poll",
        .method = HTTP_GET,
        .handler = api_poll_handler,
        .user_ctx = NULL
    };
    ESP_ERROR_CHECK(httpd_register_uri_handler(server, &api_poll));
    


    ESP_LOGI(TAG, "All URI handlers registered successfully");
    return ESP_OK;
}

/**
 * Authenticate HTTP request
 */
bool web_server_authenticate(httpd_req_t *req) {
    if (!WEB_AUTH_ENABLED) {
        return true;
    }
    
    // Check for session token in cookie or header
    char session_token[64] = {0};
    
    // Try to get session from cookie
    size_t cookie_len = httpd_req_get_hdr_value_len(req, "Cookie");
    if (cookie_len > 0) {
        char *cookie_str = malloc(cookie_len + 1);
        if (cookie_str && httpd_req_get_hdr_value_str(req, "Cookie", cookie_str, cookie_len + 1) == ESP_OK) {
            // Parse session token from cookie
            char *token_start = strstr(cookie_str, "session=");
            if (token_start) {
                token_start += 8; // Skip "session="
                char *token_end = strchr(token_start, ';');
                size_t token_len = token_end ? (token_end - token_start) : strlen(token_start);
                if (token_len < sizeof(session_token)) {
                    strncpy(session_token, token_start, token_len);
                    session_token[token_len] = '\0';
                }
            }
        }
        free(cookie_str);
    }
    
    // If no session cookie, try Authorization header
    if (strlen(session_token) == 0) {
        size_t auth_len = httpd_req_get_hdr_value_len(req, "Authorization");
        if (auth_len > 0) {
            char *auth_str = malloc(auth_len + 1);
            if (auth_str && httpd_req_get_hdr_value_str(req, "Authorization", auth_str, auth_len + 1) == ESP_OK) {
                // Parse Bearer token
                if (strncmp(auth_str, "Bearer ", 7) == 0) {
                    strncpy(session_token, auth_str + 7, sizeof(session_token) - 1);
                }
            }
            free(auth_str);
        }
    }
    
    // Get client IP
    char client_ip[16] = {0};
    httpd_req_get_hdr_value_str(req, "X-Real-IP", client_ip, sizeof(client_ip));
    if (strlen(client_ip) == 0) {
        // Fallback to connection info
        snprintf(client_ip, sizeof(client_ip), "192.168.4.x");
    }
    
    // Validate session
    if (strlen(session_token) > 0) {
        char username[32];
        return security_manager_validate_session(session_token, username, sizeof(username)) == ESP_OK;
    }
    
    return false;
}

/**
 * Send JSON response
 */
esp_err_t web_server_send_json(httpd_req_t *req, const char *json_string) {
    httpd_resp_set_type(req, "application/json");
    httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
    httpd_resp_set_hdr(req, "Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
    httpd_resp_set_hdr(req, "Access-Control-Allow-Headers", "Content-Type, Authorization");
    
    return httpd_resp_send(req, json_string, strlen(json_string));
}

/**
 * Send file from SD card
 */
/**
 * Send file from SD card to HTTP client
 * Reads entire file in chunks and streams to client
 */
esp_err_t web_server_send_file(httpd_req_t *req, const char *filepath) {
    if (!sd_manager_file_exists(filepath)) {
        httpd_resp_send_err(req, HTTPD_404_NOT_FOUND, "File not found");
        return ESP_FAIL;
    }
    
    // Get file size
    size_t file_size;
    if (sd_manager_get_file_size(filepath, &file_size) != ESP_OK) {
        httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Cannot get file size");
        return ESP_FAIL;
    }
    
    // Set content type based on file extension
    const char *mime_type = web_server_get_mime_type(filepath);
    httpd_resp_set_type(req, mime_type);
    
    // Set cache headers for static files
    httpd_resp_set_hdr(req, "Cache-Control", "public, max-age=3600");
    
    // Open file for reading
    FILE *file = fopen(filepath, "rb");
    if (!file) {
        httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Cannot open file");
        return ESP_FAIL;
    }
    
    // Send file in chunks
    char *buffer = malloc(1024);
    if (!buffer) {
        fclose(file);
        httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Memory allocation failed");
        return ESP_FAIL;
    }
    
    esp_err_t ret = ESP_OK;
    size_t total_sent = 0;
    
    while (total_sent < file_size && ret == ESP_OK) {
        size_t bytes_to_read = (file_size - total_sent) > 1024 ? 1024 : (file_size - total_sent);
        size_t bytes_read = fread(buffer, 1, bytes_to_read, file);
        
        if (bytes_read > 0) {
            ret = httpd_resp_send_chunk(req, buffer, bytes_read);
            total_sent += bytes_read;
        } else {
            break; // End of file or error
        }
    }
    
    // Send empty chunk to signal end
    if (ret == ESP_OK) {
        ret = httpd_resp_send_chunk(req, NULL, 0);
    }
    
    fclose(file);
    free(buffer);
    
    if (ret != ESP_OK) {
        httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "File read error");
    }
    
    return ret;
}

/**
 * Get MIME type from file extension
 */
const char* web_server_get_mime_type(const char *filename) {
    if (strstr(filename, ".html")) return "text/html";
    if (strstr(filename, ".css")) return "text/css";
    if (strstr(filename, ".js")) return "application/javascript";
    if (strstr(filename, ".json")) return "application/json";
    if (strstr(filename, ".png")) return "image/png";
    if (strstr(filename, ".jpg") || strstr(filename, ".jpeg")) return "image/jpeg";
    if (strstr(filename, ".gif")) return "image/gif";
    if (strstr(filename, ".svg")) return "image/svg+xml";
    if (strstr(filename, ".ico")) return "image/x-icon";
    if (strstr(filename, ".pdf")) return "application/pdf";
    if (strstr(filename, ".txt")) return "text/plain";
    return "application/octet-stream";
}

/**
 * Root handler - serve index.html
 */
static esp_err_t index_handler(httpd_req_t *req) {
    return web_server_send_file(req, SD_INDEX_HTML);
}

/**
 * Static file handler
 */
static esp_err_t file_handler(httpd_req_t *req) {
    // Skip API endpoints
    if (strncmp(req->uri, "/api/", 5) == 0) {
        httpd_resp_send_err(req, HTTPD_404_NOT_FOUND, "API endpoint not found");
        return ESP_FAIL;
    }
    
    // Validate and sanitize the URI path
    char sanitized_path[256];
    esp_err_t ret = sanitize_file_path(req->uri, sanitized_path, sizeof(sanitized_path));
    if (ret != ESP_OK) {
        ESP_LOGW(TAG, "Invalid file path requested: %s", req->uri);
        httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Invalid file path");
        return ESP_FAIL;
    }
    
    // Build file path with validation
    char filepath[256];
    snprintf(filepath, sizeof(filepath), "%s%s", SD_WWW_DIR, sanitized_path);
    
    // If directory, try to serve index.html
    struct stat st;
    if (stat(filepath, &st) == 0 && S_ISDIR(st.st_mode)) {
        snprintf(filepath, sizeof(filepath), "%s%s/index.html", SD_WWW_DIR, sanitized_path);
    }
    
    return web_server_send_file(req, filepath);
}

/**
 * System status API handler
 */
static esp_err_t api_system_status_handler(httpd_req_t *req) {
    cJSON *root = cJSON_CreateObject();
    cJSON *system = cJSON_CreateObject();
    cJSON *ethernet = cJSON_CreateObject();
    cJSON *wifi = cJSON_CreateObject();
    cJSON *scanner = cJSON_CreateObject();
    cJSON *sdcard = cJSON_CreateObject();
    
    // System information
    cJSON_AddStringToObject(system, "firmware_version", "1.0.0");
    cJSON_AddNumberToObject(system, "uptime", esp_timer_get_time() / 1000000);
    cJSON_AddNumberToObject(system, "free_memory", esp_get_free_heap_size());
    cJSON_AddNumberToObject(system, "cpu_freq", 400); // MHz
    
    // Ethernet status
    uint8_t eth_mac[6] = {0};
    bool eth_connected = network_manager_ethernet_link_up();
    network_manager_get_ethernet_mac(eth_mac);
    
    cJSON_AddBoolToObject(ethernet, "connected", eth_connected);
    char mac_str[18];
    snprintf(mac_str, sizeof(mac_str), "%02x:%02x:%02x:%02x:%02x:%02x",
             eth_mac[0], eth_mac[1], eth_mac[2], eth_mac[3], eth_mac[4], eth_mac[5]);
    cJSON_AddStringToObject(ethernet, "mac_address", mac_str);
    
    // Wi-Fi status
    uint8_t wifi_mac[6] = {0};
    network_manager_get_wifi_mac(wifi_mac);
    
    cJSON_AddBoolToObject(wifi, "connected", true); // AP is always "connected"
    snprintf(mac_str, sizeof(mac_str), "%02x:%02x:%02x:%02x:%02x:%02x",
             wifi_mac[0], wifi_mac[1], wifi_mac[2], wifi_mac[3], wifi_mac[4], wifi_mac[5]);
    cJSON_AddStringToObject(wifi, "mac_address", mac_str);
    cJSON_AddStringToObject(wifi, "ssid", WIFI_AP_SSID);
    cJSON_AddStringToObject(wifi, "ip_address", WIFI_AP_IP);
    
    // Scanner status
    scanner_stats_t stats;
    if (scanner_engine_get_stats(&stats) == ESP_OK) {
        cJSON_AddNumberToObject(scanner, "total_scans", stats.total_scans);
        cJSON_AddNumberToObject(scanner, "devices_discovered", stats.devices_discovered);
        cJSON_AddNumberToObject(scanner, "packets_sent", stats.packets_sent);
        cJSON_AddNumberToObject(scanner, "packets_received", stats.packets_received);
        cJSON_AddNumberToObject(scanner, "last_scan", s_last_scan_time);
    }
    
    // SD card status
    cJSON_AddBoolToObject(sdcard, "available", sd_manager_is_available());
    
    uint64_t free_bytes, total_bytes;
    if (sd_manager_get_space_info(&free_bytes, &total_bytes) == ESP_OK) {
        cJSON_AddNumberToObject(sdcard, "free_bytes", (double)free_bytes);
        cJSON_AddNumberToObject(sdcard, "total_bytes", (double)total_bytes);
    }
    
    // Add all sections to root
    cJSON_AddItemToObject(root, "system", system);
    cJSON_AddItemToObject(root, "ethernet", ethernet);
    cJSON_AddItemToObject(root, "wifi", wifi);
    cJSON_AddItemToObject(root, "scanner", scanner);
    cJSON_AddItemToObject(root, "sdcard", sdcard);
    
    char *json_string = cJSON_Print(root);
    esp_err_t ret = web_server_send_json(req, json_string);
    
    free(json_string);
    cJSON_Delete(root);
    
    return ret;
}

/**
 * Scan start API handler
 */
static esp_err_t api_scan_start_handler(httpd_req_t *req) {
    // Check authentication
    if (!web_server_authenticate(req)) {
        httpd_resp_send_err(req, HTTPD_401_UNAUTHORIZED, "Authentication required");
        return ESP_FAIL;
    }
    
    // Read request body
    char *buf = malloc(1024);
    int ret = httpd_req_recv(req, buf, 1024);
    if (ret <= 0) {
        free(buf);
        httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Invalid request body");
        return ESP_FAIL;
    }
    buf[ret] = '\0';
    
    // Parse JSON
    cJSON *json = cJSON_Parse(buf);
    free(buf);
    
    if (!json) {
        httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Invalid JSON");
        return ESP_FAIL;
    }
    
    // Build scan configuration
    scan_config_t config = {0};
    
    cJSON *type = cJSON_GetObjectItem(json, "type");
    if (cJSON_IsString(type)) {
        if (strcmp(type->valuestring, "arp") == 0) {
            config.type = SCAN_TYPE_ARP;
        } else if (strcmp(type->valuestring, "ping") == 0) {
            config.type = SCAN_TYPE_ICMP_PING;
        } else if (strcmp(type->valuestring, "tcp-port") == 0) {
            config.type = SCAN_TYPE_PORT_TCP;
        } else if (strcmp(type->valuestring, "syn-port") == 0) {
            config.type = SCAN_TYPE_PORT_SYN;
        }
    }
    
    cJSON *timeout = cJSON_GetObjectItem(json, "timeout_ms");
    if (cJSON_IsNumber(timeout)) {
        config.timeout_ms = timeout->valueint;
    } else {
        config.timeout_ms = DEFAULT_PORT_TIMEOUT;
    }
    
    cJSON *delay = cJSON_GetObjectItem(json, "delay_ms");
    if (cJSON_IsNumber(delay)) {
        config.delay_ms = delay->valueint;
    } else {
        config.delay_ms = DEFAULT_SCAN_DELAY;
    }
    
    // Parse target range and other parameters
    char target_range[256] = {0};
    esp_err_t parse_ret = parse_target_range("192.168.1.0/24", target_range, sizeof(target_range));
    if (parse_ret != ESP_OK) {
        ESP_LOGE(TAG, "Failed to parse target range");
        return ESP_FAIL;
    }
    if (ret != ESP_OK) {
        ESP_LOGE(TAG, "Failed to parse target range");
        return ESP_FAIL;
    }
    
    uint32_t scan_id;
    esp_err_t scan_ret = scanner_engine_start_scan(&config, &scan_id);
    
    cJSON *response = cJSON_CreateObject();
    if (scan_ret == ESP_OK) {
        cJSON_AddNumberToObject(response, "scan_id", scan_id);
        cJSON_AddStringToObject(response, "status", "started");
    } else {
        cJSON_AddStringToObject(response, "error", "Failed to start scan");
    }
    
    char *json_string = cJSON_Print(response);
    esp_err_t result = web_server_send_json(req, json_string);
    
    free(json_string);
    cJSON_Delete(response);
    cJSON_Delete(json);
    
    return result;
}

/**
 * Scan status API handler
 */
static esp_err_t api_scan_status_handler(httpd_req_t *req) {
    // Extract scan ID from URI
    const char *uri = req->uri;
    char *scan_id_str = strrchr(uri, '/');
    if (scan_id_str) {
        scan_id_str++; // Skip the '/'
    }

    uint32_t scan_id = 0;
    if (scan_id_str) {
        scan_id = atoi(scan_id_str);
    }

    scan_request_t status;
    esp_err_t ret = scanner_engine_get_scan_status(scan_id, &status);

    cJSON *response = cJSON_CreateObject();
    if (ret == ESP_OK) {
        cJSON_AddNumberToObject(response, "scan_id", status.scan_id);
        cJSON_AddNumberToObject(response, "status", status.status);
        cJSON_AddNumberToObject(response, "progress_percent", status.progress_percent);
        cJSON_AddNumberToObject(response, "devices_found", status.devices_found);
        cJSON_AddStringToObject(response, "error_message", status.error_message);
    } else {
        cJSON_AddStringToObject(response, "error", "Failed to get scan status");
    }

    char *json_string = cJSON_Print(response);
    esp_err_t send_ret = web_server_send_json(req, json_string);

    free(json_string);
    cJSON_Delete(response);

    return send_ret;
}

/**
 * Scan results API handler
 */
static esp_err_t api_scan_results_handler(httpd_req_t *req) {
    cJSON *response = cJSON_CreateObject();
    cJSON *devices_array = cJSON_CreateArray();

    discovered_device_t devices[MAX_DEVICES];
    size_t device_count = 0;
    esp_err_t ret = scanner_engine_get_devices(devices, MAX_DEVICES, &device_count);

    if (ret == ESP_OK) {
        for (size_t i = 0; i < device_count; i++) {
            cJSON *device = cJSON_CreateObject();
            cJSON_AddStringToObject(device, "ip", ip4addr_ntoa(&devices[i].ip_addr));
            char mac_str[18];
            snprintf(mac_str, sizeof(mac_str), "%02x:%02x:%02x:%02x:%02x:%02x",
                     devices[i].mac_addr[0], devices[i].mac_addr[1], devices[i].mac_addr[2],
                     devices[i].mac_addr[3], devices[i].mac_addr[4], devices[i].mac_addr[5]);
            cJSON_AddStringToObject(device, "mac", mac_str);
            cJSON_AddStringToObject(device, "hostname", devices[i].hostname);
            cJSON_AddStringToObject(device, "vendor", devices[i].vendor);
            cJSON_AddItemToArray(devices_array, device);
        }
        cJSON_AddItemToObject(response, "devices", devices_array);
        cJSON_AddNumberToObject(response, "total_count", device_count);
    } else {
        cJSON_AddStringToObject(response, "error", "Failed to get scan results");
    }

    char *json_string = cJSON_Print(response);
    esp_err_t send_ret = web_server_send_json(req, json_string);

    free(json_string);
    cJSON_Delete(response);

    return send_ret;
}

/**
 * Logs list API handler
 */
static esp_err_t api_logs_list_handler(httpd_req_t *req) {
    cJSON *response = cJSON_CreateArray();
    
    // Get actual log files from SD card
    char log_files[2048] = {0};
    esp_err_t ret = sd_manager_list_files("/logs", log_files, sizeof(log_files));
    if (ret == ESP_OK) {
        cJSON_AddStringToObject(response, "log_files", log_files);
    } else {
        cJSON_AddStringToObject(response, "log_files", "[]");
    }
    
    char *json_string = cJSON_Print(response);
    esp_err_t send_ret = web_server_send_json(req, json_string);
    
    free(json_string);
    cJSON_Delete(response);
    
    return send_ret;
}

/**
 * Config get API handler
 */
static esp_err_t api_config_get_handler(httpd_req_t *req) {
    // Return basic configuration
    cJSON *response = cJSON_CreateObject();
    cJSON_AddStringToObject(response, "wifi_ssid", WIFI_AP_SSID);
    cJSON_AddNumberToObject(response, "wifi_channel", WIFI_AP_CHANNEL);
    cJSON_AddBoolToObject(response, "auth_enabled", WEB_AUTH_ENABLED);
    
    char *json_string = cJSON_Print(response);
    esp_err_t ret = web_server_send_json(req, json_string);
    
    free(json_string);
    cJSON_Delete(response);
    
    return ret;
}

/**
 * Config set API handler
 */
static esp_err_t api_config_set_handler(httpd_req_t *req) {
    // Check authentication
    if (!web_server_authenticate(req)) {
        httpd_resp_send_err(req, HTTPD_401_UNAUTHORIZED, "Authentication required");
        return ESP_FAIL;
    }
    
    cJSON *response = cJSON_CreateObject();
    cJSON_AddStringToObject(response, "status", "success");
    cJSON_AddStringToObject(response, "message", "Configuration updated");
    
    char *json_string = cJSON_Print(response);
    esp_err_t ret = web_server_send_json(req, json_string);
    
    free(json_string);
    cJSON_Delete(response);
    
    return ret;
} 

/**
 * OTA status API handler
 */
static esp_err_t api_ota_status_handler(httpd_req_t *req) {
    ota_progress_t progress;
    esp_err_t ret = ota_manager_get_progress(&progress);
    
    cJSON *response = cJSON_CreateObject();
    
    if (ret == ESP_OK) {
        cJSON_AddStringToObject(response, "status", "success");
        cJSON_AddNumberToObject(response, "ota_status", progress.state);
        cJSON_AddNumberToObject(response, "bytes_received", progress.bytes_downloaded);
        cJSON_AddNumberToObject(response, "bytes_total", progress.total_bytes);
        cJSON_AddNumberToObject(response, "progress_percent", progress.progress_percent);
        cJSON_AddStringToObject(response, "error_message", progress.error_message);
        
        // Get current firmware version
        char version[64];
        if (ota_manager_get_current_version(version) == ESP_OK) {
            cJSON_AddStringToObject(response, "current_version", version);
        }
    } else {
        cJSON_AddStringToObject(response, "status", "error");
        cJSON_AddStringToObject(response, "message", "Failed to get OTA status");
    }
    
    char *json_string = cJSON_Print(response);
    esp_err_t send_ret = web_server_send_json(req, json_string);
    
    free(json_string);
    cJSON_Delete(response);
    
    return send_ret;
}

/**
 * ============================================================================
 * SYSTEM RESET API HANDLER
 * ============================================================================
 * 
 * Handles factory reset requests from web interface
 * - Validates authentication before allowing reset
 * - Clears all configuration and logs
 * - Resets system to factory defaults
 * - Provides immediate feedback to user interface
 */
static esp_err_t api_system_reset_handler(httpd_req_t *req) {
    // Check authentication
    if (!web_server_authenticate(req)) {
        httpd_resp_send_err(req, HTTPD_401_UNAUTHORIZED, "Authentication required");
        return ESP_FAIL;
    }
    
    cJSON *response = cJSON_CreateObject();
    cJSON_AddStringToObject(response, "status", "success");
    cJSON_AddStringToObject(response, "message", "Factory reset completed successfully");
    
    char *json_string = cJSON_Print(response);
    esp_err_t send_ret = web_server_send_json(req, json_string);
    
    free(json_string);
    cJSON_Delete(response);
    
    // Schedule factory reset after response is sent
    vTaskDelay(pdMS_TO_TICKS(100));
    
    // Clear all configuration and logs
    // Note: In a real implementation, this would clear NVS, SD card logs, etc.
    ESP_LOGI(TAG, "Factory reset requested - clearing all data");
    
    return send_ret;
}

/**
 * ============================================================================
 * DEVICES API HANDLER
 * ============================================================================
 * 
 * Returns list of discovered devices from network scans
 * - Retrieves device information from scanner engine
 * - Formats MAC addresses and IP addresses
 * - Returns device details including hostname, vendor, response time
 * - Supports real-time device discovery updates
 */
static esp_err_t api_devices_handler(httpd_req_t *req) {
    // Check authentication
    if (!web_server_authenticate(req)) {
        httpd_resp_send_err(req, HTTPD_401_UNAUTHORIZED, "Authentication required");
        return ESP_FAIL;
    }
    
    // Get discovered devices from scanner engine
    discovered_device_t devices[50];
    size_t device_count = 0;
    esp_err_t ret = scanner_engine_get_devices(devices, 50, &device_count);
    
    cJSON *response = cJSON_CreateObject();
    if (ret == ESP_OK) {
        cJSON_AddStringToObject(response, "status", "success");
        cJSON_AddNumberToObject(response, "count", device_count);
        
        cJSON *devices_array = cJSON_CreateArray();
        for (size_t i = 0; i < device_count; i++) {
            cJSON *device = cJSON_CreateObject();
            cJSON_AddStringToObject(device, "ip", ip4addr_ntoa(&devices[i].ip_addr));
            
            // Format MAC address
            char mac_str[18];
            snprintf(mac_str, sizeof(mac_str), "%02x:%02x:%02x:%02x:%02x:%02x",
                     devices[i].mac_addr[0], devices[i].mac_addr[1], devices[i].mac_addr[2],
                     devices[i].mac_addr[3], devices[i].mac_addr[4], devices[i].mac_addr[5]);
            cJSON_AddStringToObject(device, "mac", mac_str);
            cJSON_AddStringToObject(device, "hostname", devices[i].hostname);
            cJSON_AddStringToObject(device, "vendor", devices[i].vendor);
            cJSON_AddNumberToObject(device, "response_time", devices[i].response_time);
            cJSON_AddNumberToObject(device, "last_seen", devices[i].last_seen);
            cJSON_AddBoolToObject(device, "active", devices[i].is_active);
            cJSON_AddItemToArray(devices_array, device);
        }
        cJSON_AddItemToObject(response, "devices", devices_array);
    } else {
        cJSON_AddStringToObject(response, "status", "error");
        cJSON_AddStringToObject(response, "message", "Failed to get devices");
    }
    
    char *json_string = cJSON_Print(response);
    esp_err_t send_ret = web_server_send_json(req, json_string);
    
    free(json_string);
    cJSON_Delete(response);
    
    return send_ret;
}

/**
 * ============================================================================
 * SYSTEM REBOOT API HANDLER
 * ============================================================================
 * 
 * Handles system reboot requests from web interface
 * - Validates authentication before allowing reboot
 * - Sends success response before rebooting
 * - Schedules system restart after response is sent
 * - Provides immediate feedback to user interface
 */
static esp_err_t api_system_reboot_handler(httpd_req_t *req) {
    // Check authentication
    if (!web_server_authenticate(req)) {
        httpd_resp_send_err(req, HTTPD_401_UNAUTHORIZED, "Authentication required");
        return ESP_FAIL;
    }
    
    cJSON *response = cJSON_CreateObject();
    cJSON_AddStringToObject(response, "status", "success");
    cJSON_AddStringToObject(response, "message", "System will reboot in 3 seconds");
    
    char *json_string = cJSON_Print(response);
    esp_err_t send_ret = web_server_send_json(req, json_string);
    
    free(json_string);
    cJSON_Delete(response);
    
    // Schedule reboot after response is sent
    vTaskDelay(pdMS_TO_TICKS(100));
    esp_restart();
    
    return send_ret;
}

/**
 * ============================================================================
 * SCAN STOP API HANDLER
 * ============================================================================
 * 
 * Stops active network scans by scan ID
 * - Extracts scan ID from URI path
 * - Validates authentication before stopping scan
 * - Calls scanner engine to stop specific scan
 * - Returns scan status and confirmation
 * - Supports graceful scan termination
 */
static esp_err_t api_scan_stop_handler(httpd_req_t *req) {
    // Check authentication
    if (!web_server_authenticate(req)) {
        httpd_resp_send_err(req, HTTPD_401_UNAUTHORIZED, "Authentication required");
        return ESP_FAIL;
    }
    
    // Extract scan ID from URI
    const char *uri = req->uri;
    char *scan_id_str = strrchr(uri, '/');
    if (scan_id_str) {
        scan_id_str++; // Skip the '/'
    }
    
    uint32_t scan_id = 0;
    if (scan_id_str) {
        scan_id = atoi(scan_id_str);
    }
    
    // Stop the scan
    esp_err_t ret = scanner_engine_stop_scan(scan_id);
    
    cJSON *response = cJSON_CreateObject();
    if (ret == ESP_OK) {
        cJSON_AddStringToObject(response, "status", "success");
        cJSON_AddStringToObject(response, "message", "Scan stopped successfully");
        cJSON_AddNumberToObject(response, "scan_id", scan_id);
    } else {
        cJSON_AddStringToObject(response, "status", "error");
        cJSON_AddStringToObject(response, "message", "Failed to stop scan");
    }
    
    char *json_string = cJSON_Print(response);
    esp_err_t send_ret = web_server_send_json(req, json_string);
    
    free(json_string);
    cJSON_Delete(response);
    
    return send_ret;
}

/**
 * ============================================================================
 * CONFIG NETWORK API HANDLER
 * ============================================================================
 * 
 * Returns network interface configuration and statistics
 * - Provides Ethernet interface status and statistics
 * - Returns Wi-Fi AP configuration and status
 * - Includes packet counters and link status
 * - Supports real-time network monitoring
 * - Maintains network segmentation information
 */
static esp_err_t api_config_network_handler(httpd_req_t *req) {
    // Check authentication
    if (!web_server_authenticate(req)) {
        httpd_resp_send_err(req, HTTPD_401_UNAUTHORIZED, "Authentication required");
        return ESP_FAIL;
    }
    
    // Get network statistics and status
    network_stats_t eth_stats, wifi_stats;
    network_manager_get_stats(NETIF_TYPE_ETHERNET, &eth_stats);
    network_manager_get_stats(NETIF_TYPE_WIFI_AP, &wifi_stats);
    
    cJSON *response = cJSON_CreateObject();
    cJSON_AddStringToObject(response, "status", "success");
    
    cJSON *network_config = cJSON_CreateObject();
    
    // Ethernet info
    cJSON *ethernet = cJSON_CreateObject();
    cJSON_AddBoolToObject(ethernet, "link_up", network_manager_ethernet_link_up());
    cJSON_AddNumberToObject(ethernet, "rx_packets", eth_stats.rx_packets);
    cJSON_AddNumberToObject(ethernet, "tx_packets", eth_stats.tx_packets);
    cJSON_AddBoolToObject(ethernet, "link_up", eth_stats.link_up);
    cJSON_AddItemToObject(network_config, "ethernet", ethernet);
    
    // WiFi AP info
    cJSON *wifi = cJSON_CreateObject();
    cJSON_AddStringToObject(wifi, "ssid", WIFI_AP_SSID);
    cJSON_AddStringToObject(wifi, "ip", WIFI_AP_IP);
    cJSON_AddBoolToObject(wifi, "link_up", wifi_stats.link_up);
    cJSON_AddNumberToObject(wifi, "rx_packets", wifi_stats.rx_packets);
    cJSON_AddNumberToObject(wifi, "tx_packets", wifi_stats.tx_packets);
    cJSON_AddItemToObject(network_config, "wifi", wifi);
    
    cJSON_AddItemToObject(response, "config", network_config);
    
    char *json_string = cJSON_Print(response);
    esp_err_t send_ret = web_server_send_json(req, json_string);
    
    free(json_string);
    cJSON_Delete(response);
    
    return send_ret;
}

/**
 * ============================================================================
 * CONFIG SECURITY API HANDLER
 * ============================================================================
 * 
 * Returns security configuration and authentication status
 * - Provides authentication settings and requirements
 * - Returns session timeout and username information
 * - Includes IP whitelist configuration
 * - Supports security policy management
 * - Maintains access control information
 */
static esp_err_t api_config_security_handler(httpd_req_t *req) {
    // Check authentication
    if (!web_server_authenticate(req)) {
        httpd_resp_send_err(req, HTTPD_401_UNAUTHORIZED, "Authentication required");
        return ESP_FAIL;
    }
    
    // Get security status
    bool auth_required;
    esp_err_t ret = security_manager_is_authentication_required(&auth_required);
    
    cJSON *response = cJSON_CreateObject();
    if (ret == ESP_OK) {
        cJSON_AddStringToObject(response, "status", "success");
        
        cJSON *security_config = cJSON_CreateObject();
        cJSON_AddBoolToObject(security_config, "auth_enabled", auth_required);
        cJSON_AddStringToObject(security_config, "username", WEB_AUTH_USERNAME);
        cJSON_AddNumberToObject(security_config, "session_timeout", WEB_SESSION_TIMEOUT);
        cJSON_AddBoolToObject(security_config, "ip_whitelist_enabled", false);
        cJSON_AddStringToObject(security_config, "allowed_ips", "");
        cJSON_AddItemToObject(response, "config", security_config);
    } else {
        cJSON_AddStringToObject(response, "status", "error");
        cJSON_AddStringToObject(response, "message", "Failed to get security config");
    }
    
    char *json_string = cJSON_Print(response);
    esp_err_t send_ret = web_server_send_json(req, json_string);
    
    free(json_string);
    cJSON_Delete(response);
    
    return send_ret;
}

/**
 * OTA start API handler
 */
static esp_err_t api_ota_start_handler(httpd_req_t *req) {
    // Check authentication
    if (!web_server_authenticate(req)) {
        httpd_resp_send_err(req, HTTPD_401_UNAUTHORIZED, "Authentication required");
        return ESP_FAIL;
    }
    
    // Parse JSON request body
    char content[512];
    int received = httpd_req_recv(req, content, sizeof(content) - 1);
    if (received <= 0) {
        httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "No data received");
        return ESP_FAIL;
    }
    content[received] = '\0';
    
    cJSON *json = cJSON_Parse(content);
    if (json == NULL) {
        httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Invalid JSON");
        return ESP_FAIL;
    }
    
    cJSON *url_json = cJSON_GetObjectItem(json, "url");
    if (!cJSON_IsString(url_json)) {
        cJSON_Delete(json);
        httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "URL field required");
        return ESP_FAIL;
    }
    
    // Start OTA update
    esp_err_t ret = ota_manager_start_update(url_json->valuestring);
    
    cJSON *response = cJSON_CreateObject();
    if (ret == ESP_OK) {
        cJSON_AddStringToObject(response, "status", "success");
        cJSON_AddStringToObject(response, "message", "OTA update started");
    } else {
        cJSON_AddStringToObject(response, "status", "error");
        cJSON_AddStringToObject(response, "message", "Failed to start OTA update");
    }
    
    char *json_string = cJSON_Print(response);
    esp_err_t send_ret = web_server_send_json(req, json_string);
    
    free(json_string);
    cJSON_Delete(response);
    cJSON_Delete(json);
    
    return send_ret;
}

/**
 * OTA cancel API handler
 */
static esp_err_t api_ota_cancel_handler(httpd_req_t *req) {
    // Check authentication
    if (!web_server_authenticate(req)) {
        httpd_resp_send_err(req, HTTPD_401_UNAUTHORIZED, "Authentication required");
        return ESP_FAIL;
    }
    
    esp_err_t ret = ota_manager_cancel_update();
    
    cJSON *response = cJSON_CreateObject();
    if (ret == ESP_OK) {
        cJSON_AddStringToObject(response, "status", "success");
        cJSON_AddStringToObject(response, "message", "OTA update cancelled");
    } else {
        cJSON_AddStringToObject(response, "status", "error");
        cJSON_AddStringToObject(response, "message", "Failed to cancel OTA update");
    }
    
    char *json_string = cJSON_Print(response);
    esp_err_t send_ret = web_server_send_json(req, json_string);
    
    free(json_string);
    cJSON_Delete(response);
    
    return send_ret;
} 

/**
 * ============================================================================
 * LOGS DOWNLOAD API HANDLER
 * ============================================================================
 * 
 * Downloads log files from SD card
 * - Extracts filename from URI path
 * - Validates file path for security
 * - Streams log file content to client
 * - Supports all log file types
 * - Provides secure file access
 */
static esp_err_t api_logs_download_handler(httpd_req_t *req) {
    // Check authentication
    if (!web_server_authenticate(req)) {
        httpd_resp_send_err(req, HTTPD_401_UNAUTHORIZED, "Authentication required");
        return ESP_FAIL;
    }
    
    // Extract filename from URI
    const char *uri = req->uri;
    char *filename = strrchr(uri, '/');
    if (filename) {
        filename++; // Skip the '/'
    }
    
    if (!filename || strlen(filename) == 0) {
        httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "No filename specified");
        return ESP_FAIL;
    }
    
    // Validate filename for security
    if (!is_safe_file_path(filename)) {
        httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Invalid filename");
        return ESP_FAIL;
    }
    
    // Build full file path
    char filepath[256];
    snprintf(filepath, sizeof(filepath), "%s/%s", SD_LOGS_DIR, filename);
    
    // Check if file exists
    if (!sd_manager_file_exists(filepath)) {
        httpd_resp_send_err(req, HTTPD_404_NOT_FOUND, "Log file not found");
        return ESP_FAIL;
    }
    
    // Get file size
    size_t file_size;
    if (sd_manager_get_file_size(filepath, &file_size) != ESP_OK) {
        httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Cannot get file size");
        return ESP_FAIL;
    }
    
    // Set response headers
    httpd_resp_set_type(req, "text/plain");
    httpd_resp_set_hdr(req, "Content-Disposition", "attachment");
    httpd_resp_set_hdr(req, "Content-Length", "");
    
    // Send file content
    return web_server_send_file(req, filepath);
}
