/**
 * Web Proxy server implementation for wssshd
 *
 * Copyright (C) 2024 Stefy Lanza <stefy@nexlab.net> and SexHack.me
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <errno.h>
#include <time.h>
#include <ctype.h>
#include <signal.h>
#include <netdb.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/select.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include "web_proxy.h"
#include "websocket.h"
#include "websocket_protocol.h"
#include "ssl.h"


// Global state for shutdown
static int server_socket = -1;
static volatile int server_running = 0;

// WSSSHT process tracking
typedef struct {
    char client_id[256];
    char hostname[256];
    pid_t pid;
    int port;
    time_t last_used;
    bool active;
} wsssht_process_t;

#define MAX_WSSSHT_PROCESSES 50
static wsssht_process_t wsssht_processes[MAX_WSSSHT_PROCESSES];
static int wsssht_processes_count = 0;
static pthread_mutex_t wsssht_mutex = PTHREAD_MUTEX_INITIALIZER;


// Active proxy connections
#define MAX_PROXY_CONNECTIONS 100
typedef struct {
    int client_fd;           // Connection from web proxy client
    void *tunnel_ws;         // WebSocket tunnel to the client
    char client_id[256];
    char hostname[256];
    bool active;
    pthread_t thread;
} proxy_connection_t;

static proxy_connection_t proxy_connections[MAX_PROXY_CONNECTIONS];
static int proxy_connections_count = 0;
static pthread_mutex_t proxy_mutex = PTHREAD_MUTEX_INITIALIZER;


// Cleanup thread
static volatile int cleanup_running = 0;
static void *cleanup_thread(void *arg) {
    (void)arg; // Unused

    cleanup_running = 1;
    while (cleanup_running) {
        sleep(60); // Check every minute

        // Clean up inactive wsssht processes
        time_t now = time(NULL);
        pthread_mutex_lock(&wsssht_mutex);
        for (int i = 0; i < wsssht_processes_count; i++) {
            wsssht_process_t *proc = &wsssht_processes[i];
            if (proc->active && (now - proc->last_used) > 300) { // 5 minutes
                printf("[WEB-PROXY] Terminating inactive wsssht process for %s (PID: %d)\n", proc->hostname, proc->pid);
                kill(proc->pid, SIGINT);
                waitpid(proc->pid, NULL, 0);
                proc->active = false;
            }
        }
        pthread_mutex_unlock(&wsssht_mutex);
    }

    return NULL;
}

// Launch wsssht daemon and get port
static int launch_wsssht_daemon(const char *service, const char *client_id, const char *domain) {
    // Check if wsssht command exists
    if (access("./wssshtools/wsssht", X_OK) != 0 && access("/usr/bin/wsssht", X_OK) != 0) {
        printf("[WEB-PROXY] wsssht command not found\n");
        return -1;
    }

    // Build target
    char target[512];
    if (domain) {
        snprintf(target, sizeof(target), "%s://%s@%s", service, client_id, domain);
    } else {
        snprintf(target, sizeof(target), "%s://%s", service, client_id);
    }

    const char *wsssht_path = "./wssshtools/wsssht";
    if (access(wsssht_path, X_OK) != 0) {
        wsssht_path = "wsssht";
    }

    // Create pipe for output
    int pipefd[2];
    if (pipe(pipefd) == -1) {
        perror("[WEB-PROXY] Failed to create pipe");
        return -1;
    }

    // Fork process
    pid_t pid = fork();
    if (pid == -1) {
        perror("[WEB-PROXY] Failed to fork");
        close(pipefd[0]);
        close(pipefd[1]);
        return -1;
    }

    if (pid == 0) {
        // Child process
        close(pipefd[0]); // Close read end
        dup2(pipefd[1], STDOUT_FILENO); // Redirect stdout to pipe
        close(pipefd[1]); // Close write end after dup

        execl(wsssht_path, "wsssht", "--daemon", target, NULL);
        perror("[WEB-PROXY] Failed to execl wsssht");
        exit(1);
    } else {
        // Parent process
        close(pipefd[1]); // Close write end

        // Read output to find port
        char line[256];
        int port = -1;
        FILE *fp = fdopen(pipefd[0], "r");
        if (fp) {
            while (fgets(line, sizeof(line), fp)) {
                printf("[WEB-PROXY] wsssht output: %s", line);
                if (strstr(line, "Listening on port")) {
                    char *port_str = strstr(line, "port");
                    if (port_str) {
                        port_str += 4; // Skip "port"
                        while (*port_str == ' ' || *port_str == '\t') port_str++;
                        port = atoi(port_str);
                        break;
                    }
                }
            }
            fclose(fp);
        } else {
            close(pipefd[0]);
        }

        if (port <= 0) {
            printf("[WEB-PROXY] Failed to parse port from wsssht output\n");
            return -1;
        }

        printf("[WEB-PROXY] wsssht daemon listening on port %d\n", port);
        return port;
    }
}

// Find or create wsssht process for hostname
static wsssht_process_t *find_or_create_wsssht_process(const char *hostname, const char *service, const char *client_id, const char *domain) {
    pthread_mutex_lock(&wsssht_mutex);

    // Find existing process
    for (int i = 0; i < wsssht_processes_count; i++) {
        wsssht_process_t *proc = &wsssht_processes[i];
        if (proc->active && strcmp(proc->hostname, hostname) == 0) {
            proc->last_used = time(NULL);
            pthread_mutex_unlock(&wsssht_mutex);
            return proc;
        }
    }

    // Create new process
    if (wsssht_processes_count >= MAX_WSSSHT_PROCESSES) {
        pthread_mutex_unlock(&wsssht_mutex);
        return NULL;
    }

    wsssht_process_t *proc = &wsssht_processes[wsssht_processes_count++];
    strncpy(proc->client_id, client_id, sizeof(proc->client_id));
    strncpy(proc->hostname, hostname, sizeof(proc->hostname));
    proc->last_used = time(NULL);
    proc->active = true;

    // Launch wsssht daemon
    proc->port = launch_wsssht_daemon(service, client_id, domain);
    if (proc->port <= 0) {
        proc->active = false;
        wsssht_processes_count--;
        pthread_mutex_unlock(&wsssht_mutex);
        return NULL;
    }

    // Fork to launch wsssht (we need to capture the PID)
    pid_t pid = fork();
    if (pid == 0) {
        // Child process - launch wsssht
        char target[512];
        if (domain) {
            snprintf(target, sizeof(target), "%s://%s@%s", service, client_id, domain);
        } else {
            snprintf(target, sizeof(target), "%s://%s", service, client_id);
        }

        const char *wsssht_path = "./wssshtools/wsssht";
        if (access(wsssht_path, X_OK) != 0) {
            wsssht_path = "wsssht";
        }

        char *argv[] = {"wsssht", "--daemon", target, NULL};
        execvp("wsssht", argv);
        exit(1); // Should not reach here
    } else if (pid > 0) {
        proc->pid = pid;
        printf("[WEB-PROXY] Launched wsssht daemon for %s (PID: %d, Port: %d)\n", hostname, pid, proc->port);
    } else {
        proc->active = false;
        wsssht_processes_count--;
        pthread_mutex_unlock(&wsssht_mutex);
        return NULL;
    }

    pthread_mutex_unlock(&wsssht_mutex);
    return proc;
}

// Thread arguments structure
typedef struct {
    const wssshd_config_t *config;
    wssshd_state_t *state;
} proxy_thread_args_t;



// Connection handler arguments
typedef struct {
    int client_fd;
    wssshd_state_t *state;
    const wssshd_config_t *config;
} connection_handler_args_t;

// Forward declaration for proxy connection handler
static void *proxy_connection_handler(void *arg);







// Parse Host header from HTTP request
static int parse_host_header(const char *request, char *hostname, size_t hostname_size) {
    if (!request || !hostname) return -1;

    const char *host_header = strstr(request, "Host:");
    if (!host_header) return -1;

    host_header += 5; // Skip "Host:"
    while (*host_header == ' ' || *host_header == '\t') host_header++;

    // Extract hostname (up to port or end of line)
    const char *end = host_header;
    while (*end && *end != '\r' && *end != '\n' && *end != ' ') {
        end++;
    }

    size_t len = end - host_header;
    if (len >= hostname_size) len = hostname_size - 1;

    strncpy(hostname, host_header, len);
    hostname[len] = '\0';

    // Remove port if present
    char *colon = strchr(hostname, ':');
    if (colon) {
        *colon = '\0';
    }

    return 0;
}





// Send HTTP error response
static void send_http_error(int client_fd, int status_code, const char *status_text) {
    const char *body_format = "<html><body><h1>%d %s</h1></body></html>";
    char body[512];
    snprintf(body, sizeof(body), body_format, status_code, status_text);

    char response[1024];
    int len = snprintf(response, sizeof(response),
        "HTTP/1.1 %d %s\r\n"
        "Content-Type: text/html\r\n"
        "Content-Length: %zu\r\n"
        "Connection: close\r\n"
        "\r\n"
        "%s",
        status_code, status_text, strlen(body), body);

    send(client_fd, response, len, 0);
}

// Proxy data between client socket and tunnel WebSocket
static void *proxy_data_forward(void *arg) __attribute__((unused));
static void *proxy_data_forward(void *arg) {
    proxy_connection_t *conn = (proxy_connection_t *)arg;
    if (!conn) return NULL;

    char buffer[8192];
    fd_set read_fds;
    int max_fd = conn->client_fd;
    struct timeval tv;

    printf("[WEB-PROXY] Started data forwarding for %s\n", conn->hostname);

    while (conn->active && server_running) {
        FD_ZERO(&read_fds);
        FD_SET(conn->client_fd, &read_fds);

        tv.tv_sec = 1;
        tv.tv_usec = 0;

        int activity = select(max_fd + 1, &read_fds, NULL, NULL, &tv);
        if (activity < 0) {
            if (errno == EINTR) continue;
            break;
        }

        if (activity == 0) {
            continue; // Timeout, check again
        }

        // Read from client socket
        if (FD_ISSET(conn->client_fd, &read_fds)) {
            ssize_t bytes_read = recv(conn->client_fd, buffer, sizeof(buffer), 0);
            if (bytes_read <= 0) {
                // Connection closed or error
                break;
            }

            // Forward to tunnel WebSocket
            if (conn->tunnel_ws) {
                ws_send_binary_frame((ws_connection_t *)conn->tunnel_ws, buffer, bytes_read, false);
            }
        }
    }

    printf("[WEB-PROXY] Stopped data forwarding for %s\n", conn->hostname);
    return NULL;
}

// Handle incoming HTTP request by proxying to wsssht daemon
static int handle_proxy_request(int client_fd, wssshd_state_t *state, const wssshd_config_t *config) {
    char request[8192];
    ssize_t bytes_read = recv(client_fd, request, sizeof(request) - 1, 0);
    if (bytes_read <= 0) {
        return -1;
    }
    request[bytes_read] = '\0';

    // Parse Host header
    char hostname[256];
    if (parse_host_header(request, hostname, sizeof(hostname)) != 0) {
        send_http_error(client_fd, 400, "Bad Request");
        return -1;
    }

    printf("[WEB-PROXY] Received request for hostname: %s\n", hostname);

    // Find client by hostname
    client_t *client = NULL;
    pthread_mutex_lock(&state->client_mutex);
    for (size_t i = 0; i < state->clients_count; i++) {
        client_t *c = &state->clients[i];
        if (!c->active) continue;

        int hostname_match = 0;
        if (strcasecmp(hostname, c->client_id) == 0) {
            hostname_match = 1;
        } else if (config && config->domain) {
            char expected_hostname[512];
            snprintf(expected_hostname, sizeof(expected_hostname), "%s.%s", c->client_id, config->domain);
            if (strcasecmp(hostname, expected_hostname) == 0) {
                hostname_match = 1;
            }
        }

        if (hostname_match) {
            client = c;
            break;
        }
    }
    pthread_mutex_unlock(&state->client_mutex);

    if (!client) {
        printf("[WEB-PROXY] No client found for hostname: %s\n", hostname);
        send_http_error(client_fd, 404, "Not Found");
        return -1;
    }

    printf("[WEB-PROXY] Found client: %s\n", client->client_id);

    // Check if client has web/http/https services
    bool has_web_service = false;
    const char *service_type = NULL;
    char *services_copy = strdup(client->services);
    if (services_copy) {
        char *service_token = strtok(services_copy, ",");
        while (service_token) {
            while (*service_token == ' ' || *service_token == '\t') service_token++;
            char *end = service_token + strlen(service_token) - 1;
            while (end > service_token && (*end == ' ' || *end == '\t')) {
                *end = '\0';
                end--;
            }

            if (strncmp(service_token, "web", 3) == 0) {
                has_web_service = true;
                service_type = "web";
                break;
            } else if (strncmp(service_token, "http", 4) == 0) {
                has_web_service = true;
                service_type = "http";
                break;
            } else if (strncmp(service_token, "https", 5) == 0) {
                has_web_service = true;
                service_type = "https";
                break;
            }

            service_token = strtok(NULL, ",");
        }
        free(services_copy);
    }

    if (!has_web_service) {
        printf("[WEB-PROXY] Client %s does not have web/http/https services\n", client->client_id);
        send_http_error(client_fd, 503, "Service Unavailable");
        return -1;
    }

    // Determine if SSL should be used
    bool use_ssl = false;
    if (strcmp(service_type, "https") == 0) {
        use_ssl = true;
        printf("[WEB-PROXY] Service type 'https', using SSL\n");
    } else if (strcmp(service_type, "web") == 0) {
        use_ssl = true; // Try HTTPS first for 'web'
        printf("[WEB-PROXY] Service type 'web', trying SSL first\n");
    } else {
        printf("[WEB-PROXY] Service type '%s', using plain TCP\n", service_type);
    }

    // Find or create wsssht process
    wsssht_process_t *proc = find_or_create_wsssht_process(hostname, service_type, client->client_id, config->domain);
    if (!proc) {
        printf("[WEB-PROXY] Failed to launch wsssht daemon for %s\n", hostname);
        send_http_error(client_fd, 502, "Bad Gateway");
        return -1;
    }

    // Connect to wsssht daemon
    int tunnel_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (tunnel_fd < 0) {
        perror("[WEB-PROXY] Failed to create socket");
        send_http_error(client_fd, 500, "Internal Server Error");
        return -1;
    }

    struct sockaddr_in addr;
    memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
    addr.sin_port = htons(proc->port);

    printf("[WEB-PROXY] Connecting to wsssht on localhost:%d\n", proc->port);
    if (connect(tunnel_fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
        perror("[WEB-PROXY] Failed to connect to wsssht");
        close(tunnel_fd);
        send_http_error(client_fd, 502, "Bad Gateway");
        return -1;
    }
    printf("[WEB-PROXY] Connected to wsssht\n");

    // SSL setup if needed
    SSL_CTX *ssl_ctx = NULL;
    SSL *tunnel_ssl = NULL;
    if (use_ssl) {
        printf("[WEB-PROXY] Setting up SSL connection\n");
        ssl_ctx = create_ssl_context();
        if (!ssl_ctx) {
            printf("[WEB-PROXY] Failed to create SSL context\n");
            if (strcmp(service_type, "web") == 0) {
                use_ssl = false; // Fallback to HTTP
                printf("[WEB-PROXY] Falling back to plain TCP\n");
            } else {
                close(tunnel_fd);
                send_http_error(client_fd, 502, "Bad Gateway");
                return -1;
            }
        } else {
            // Set socket non-blocking for SSL timeout
            int flags = fcntl(tunnel_fd, F_GETFL, 0);
            fcntl(tunnel_fd, F_SETFL, flags | O_NONBLOCK);

            tunnel_ssl = SSL_new(ssl_ctx);
            SSL_set_fd(tunnel_ssl, tunnel_fd);

            // Perform SSL connect with timeout
            int ret;
            fd_set fdset;
            struct timeval tv;
            tv.tv_sec = 5; // 5 second timeout
            tv.tv_usec = 0;

            while (1) {
                ret = SSL_connect(tunnel_ssl);
                if (ret > 0) {
                    printf("[WEB-PROXY] SSL connection established\n");
                    break;
                }
                int err = SSL_get_error(tunnel_ssl, ret);
                if (err == SSL_ERROR_WANT_READ) {
                    FD_ZERO(&fdset);
                    FD_SET(tunnel_fd, &fdset);
                    int sel = select(tunnel_fd + 1, &fdset, NULL, NULL, &tv);
                    if (sel <= 0) {
                        printf("[WEB-PROXY] SSL connection timeout on read\n");
                        ret = -1;
                        break;
                    }
                } else if (err == SSL_ERROR_WANT_WRITE) {
                    FD_ZERO(&fdset);
                    FD_SET(tunnel_fd, &fdset);
                    int sel = select(tunnel_fd + 1, NULL, &fdset, NULL, &tv);
                    if (sel <= 0) {
                        printf("[WEB-PROXY] SSL connection timeout on write\n");
                        ret = -1;
                        break;
                    }
                } else {
                    printf("[WEB-PROXY] SSL connection failed with error %d\n", err);
                    ret = -1;
                    break;
                }
            }

            if (ret <= 0) {
                SSL_free(tunnel_ssl);
                tunnel_ssl = NULL;
                SSL_CTX_free(ssl_ctx);
                ssl_ctx = NULL;
                if (strcmp(service_type, "web") == 0) {
                    use_ssl = false; // Fallback to HTTP
                    printf("[WEB-PROXY] Falling back to plain TCP\n");
                } else {
                    close(tunnel_fd);
                    send_http_error(client_fd, 502, "Bad Gateway");
                    return -1;
                }
            }

            // Set socket back to blocking
            if (tunnel_ssl) {
                fcntl(tunnel_fd, F_SETFL, flags & ~O_NONBLOCK);
            }
        }
    }

    // Send HTTP request to wsssht daemon
    int send_result;
    if (use_ssl) {
        send_result = SSL_write(tunnel_ssl, request, bytes_read);
    } else {
        send_result = send(tunnel_fd, request, bytes_read, 0);
    }
    if (send_result != bytes_read) {
        if (tunnel_ssl) {
            SSL_shutdown(tunnel_ssl);
            SSL_free(tunnel_ssl);
        }
        if (ssl_ctx) SSL_CTX_free(ssl_ctx);
        close(tunnel_fd);
        send_http_error(client_fd, 502, "Bad Gateway");
        return -1;
    }

    // Read response from wsssht daemon and forward to client
    char buffer[8192];
    ssize_t total_sent = 0;
    fd_set read_fds;
    struct timeval tv;
    while (1) {
        FD_ZERO(&read_fds);
        FD_SET(tunnel_fd, &read_fds);
        tv.tv_sec = 10; // 10 second timeout
        tv.tv_usec = 0;

        int activity = select(tunnel_fd + 1, &read_fds, NULL, NULL, &tv);
        if (activity < 0) {
            if (errno == EINTR) continue;
            break;
        }
        if (activity == 0) {
            // Timeout
            printf("[WEB-PROXY] Timeout waiting for response from wsssht\n");
            break;
        }

        ssize_t bytes_recv;
        if (use_ssl) {
            bytes_recv = SSL_read(tunnel_ssl, buffer, sizeof(buffer));
        } else {
            bytes_recv = recv(tunnel_fd, buffer, sizeof(buffer), 0);
        }
        if (bytes_recv <= 0) {
            break;
        }

        ssize_t sent = send(client_fd, buffer, bytes_recv, 0);
        if (sent != bytes_recv) {
            break;
        }
        total_sent += sent;
    }

    // Cleanup SSL
    if (tunnel_ssl) {
        SSL_shutdown(tunnel_ssl);
        SSL_free(tunnel_ssl);
    }
    if (ssl_ctx) SSL_CTX_free(ssl_ctx);
    close(tunnel_fd);

    printf("[WEB-PROXY] Request handled for %s (%zd bytes sent)\n", hostname, total_sent);
    return 0;
}

// Proxy connection handler thread
static void *proxy_connection_handler(void *arg) {
    connection_handler_args_t *args = (connection_handler_args_t *)arg;
    int client_fd = args->client_fd;
    wssshd_state_t *state = args->state;
    const wssshd_config_t *config = args->config;
    free(args);

    printf("[WEB-PROXY] New connection received\n");

    handle_proxy_request(client_fd, state, config);

    close(client_fd);
    printf("[WEB-PROXY] Connection closed\n");

    return NULL;
}

static void *http_proxy_thread(void *arg) {
    proxy_thread_args_t *args = (proxy_thread_args_t *)arg;
    const wssshd_config_t *config = args->config;
    wssshd_state_t *state = args->state;
    free(args);
    struct sockaddr_in server_addr, client_addr;
    socklen_t client_len = sizeof(client_addr);

    printf("[WEB-PROXY] Creating socket\n");
    server_socket = socket(AF_INET, SOCK_STREAM, 0);
    if (server_socket < 0) {
        perror("[WEB-PROXY] Failed to create server socket");
        return NULL;
    }
    printf("[WEB-PROXY] Socket created\n");

    // Set socket options
    int opt = 1;
    setsockopt(server_socket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));

    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);  // Listen on localhost only
    server_addr.sin_port = htons(config->web_proxy_port);
    printf("[WEB-PROXY] Binding to 127.0.0.1:%d\n", config->web_proxy_port);

    if (bind(server_socket, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
        perror("[WEB-PROXY] Failed to bind server socket");
        close(server_socket);
        return NULL;
    }
    printf("[WEB-PROXY] Bound successfully\n");

    if (listen(server_socket, 10) < 0) {
        perror("[WEB-PROXY] Failed to listen on server socket");
        close(server_socket);
        return NULL;
    }
    printf("[WEB-PROXY] Listening successfully\n");

    printf("[WEB-PROXY] Web proxy server starting on 127.0.0.1:%d\n", config->web_proxy_port);
    server_running = 1;

    // Ignore SIGPIPE to prevent crashes on broken connections
    signal(SIGPIPE, SIG_IGN);

    while (server_running) {
        int client_fd = accept(server_socket, (struct sockaddr *)&client_addr, &client_len);
        if (client_fd < 0) {
            if (server_running) perror("[WEB-PROXY] Failed to accept client connection");
            continue;
        }

        // Create a new thread to handle the connection
        connection_handler_args_t *handler_args = malloc(sizeof(connection_handler_args_t));
        if (!handler_args) {
            close(client_fd);
            continue;
        }
        handler_args->client_fd = client_fd;
        handler_args->state = state;
        handler_args->config = config;

        pthread_t thread;
        if (pthread_create(&thread, NULL, proxy_connection_handler, handler_args) != 0) {
            perror("[WEB-PROXY] Failed to create connection handler thread");
            free(handler_args);
            close(client_fd);
            continue;
        }

        pthread_detach(thread);
    }

    close(server_socket);
    server_socket = -1;
    printf("[WEB-PROXY] Web proxy server stopped\n");
    return NULL;
}

int web_proxy_start_server(const wssshd_config_t *config, wssshd_state_t *state) {
    if (!config->web_proxy_enabled || config->web_proxy_port == 0) {
        return 0; // Web proxy not enabled
    }

    // Start cleanup thread
    pthread_t cleanup_tid;
    if (pthread_create(&cleanup_tid, NULL, cleanup_thread, NULL) != 0) {
        perror("[WEB-PROXY] Failed to create cleanup thread");
        return -1;
    }
    pthread_detach(cleanup_tid);

    // Allocate thread arguments
    proxy_thread_args_t *args = malloc(sizeof(proxy_thread_args_t));
    if (!args) {
        perror("[WEB-PROXY] Failed to allocate thread arguments");
        return -1;
    }
    args->config = config;
    args->state = state;

    // Start HTTP proxy server thread
    pthread_t thread;
    if (pthread_create(&thread, NULL, http_proxy_thread, args) != 0) {
        perror("[WEB-PROXY] Failed to create HTTP proxy server thread");
        free(args);
        return -1;
    }

    pthread_detach(thread);
    return 0;
}

void web_proxy_stop_server(void) {
    server_running = 0;
    cleanup_running = 0;

    // Close server socket to unblock accept()
    if (server_socket >= 0) {
        close(server_socket);
        server_socket = -1;
    }

    // Close all active proxy connections
    pthread_mutex_lock(&proxy_mutex);
    for (int i = 0; i < proxy_connections_count; i++) {
        if (proxy_connections[i].active) {
            proxy_connections[i].active = false;
            if (proxy_connections[i].client_fd >= 0) {
                close(proxy_connections[i].client_fd);
            }
        }
    }
    proxy_connections_count = 0;
    pthread_mutex_unlock(&proxy_mutex);

    // Terminate all wsssht processes
    pthread_mutex_lock(&wsssht_mutex);
    for (int i = 0; i < wsssht_processes_count; i++) {
        wsssht_process_t *proc = &wsssht_processes[i];
        if (proc->active) {
            printf("[WEB-PROXY] Terminating wsssht process for %s (PID: %d)\n", proc->hostname, proc->pid);
            kill(proc->pid, SIGINT);
            waitpid(proc->pid, NULL, 0);
            proc->active = false;
        }
    }
    wsssht_processes_count = 0;
    pthread_mutex_unlock(&wsssht_mutex);

    printf("[WEB-PROXY] Web proxy server stopping\n");
}
