/**
 * Tunnel object management 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 <time.h>
#include "tunnel.h"

tunnel_t *tunnel_create(const char *request_id, const char *client_id) {
    tunnel_t *tunnel = calloc(1, sizeof(tunnel_t));
    if (!tunnel) {
        return NULL;
    }

    // Initialize with provided values
    if (request_id) {
        strncpy(tunnel->request_id, request_id, sizeof(tunnel->request_id) - 1);
    }
    if (client_id) {
        strncpy(tunnel->client_id, client_id, sizeof(tunnel->client_id) - 1);
    }

    // Set defaults
    tunnel->status = TUNNEL_STATUS_CREATING;
    tunnel->created_at = time(NULL);
    tunnel->updated_at = time(NULL);

    strcpy(tunnel->protocol, "ssh");
    strcpy(tunnel->tunnel, "any");
    strcpy(tunnel->tunnel_control, "any");
    strcpy(tunnel->service, "ssh");

    // Initialize keep-alive timestamps
    tunnel->last_keepalive_from_client = time(NULL);
    tunnel->last_keepalive_from_tool = time(NULL);

    return tunnel;
}

void tunnel_free(tunnel_t *tunnel) {
    if (tunnel) {
        free(tunnel);
    }
}

void tunnel_update_status(tunnel_t *tunnel, tunnel_status_t status, const char *error_message) {
    if (!tunnel) return;

    tunnel->status = status;
    tunnel->updated_at = time(NULL);

    if (error_message) {
        strncpy(tunnel->error_message, error_message, sizeof(tunnel->error_message) - 1);
    } else {
        tunnel->error_message[0] = '\0';
    }
}

void tunnel_set_websockets(tunnel_t *tunnel, void *client_ws, void *wsssh_ws) {
    if (!tunnel) return;

    tunnel->client_ws = client_ws;
    tunnel->wsssh_ws = wsssh_ws;
    tunnel->updated_at = time(NULL);
}

void tunnel_set_destination_info(tunnel_t *tunnel, const char *public_ip, const char *private_ip) {
    if (!tunnel) return;

    if (public_ip) {
        strncpy(tunnel->wssshc_public_ip, public_ip, sizeof(tunnel->wssshc_public_ip) - 1);
    }
    if (private_ip) {
        strncpy(tunnel->wssshc_private_ip, private_ip, sizeof(tunnel->wssshc_private_ip) - 1);
    }
    tunnel->updated_at = time(NULL);
}

void tunnel_set_source_info(tunnel_t *tunnel, const char *private_ip) {
    if (!tunnel) return;

    if (private_ip) {
        strncpy(tunnel->tool_private_ip, private_ip, sizeof(tunnel->tool_private_ip) - 1);
    }
    tunnel->updated_at = time(NULL);
}

const char *tunnel_status_string(tunnel_status_t status) {
    switch (status) {
        case TUNNEL_STATUS_CREATING: return "creating";
        case TUNNEL_STATUS_ACTIVE: return "active";
        case TUNNEL_STATUS_CLOSING: return "closing";
        case TUNNEL_STATUS_CLOSED: return "closed";
        case TUNNEL_STATUS_ERROR: return "error";
        default: return "unknown";
    }
}

void tunnel_print(const tunnel_t *tunnel) {
    if (!tunnel) return;

    printf("Tunnel(id=%s, client=%s, status=%s",
           tunnel->request_id, tunnel->client_id, tunnel_status_string(tunnel->status));

    if (tunnel->error_message[0]) {
        printf(", error='%s'", tunnel->error_message);
    }
    printf(")");
}