//
// Created by conntrack on 4/30/23.
//


#include "netguard.h"

struct ng_session *debug_socket;





int open_debug_socket(const struct arguments *args, int epoll_fd) {

    void *saddr;
    void *daddr;
    char source[INET6_ADDRSTRLEN + 1];
    char dest[INET6_ADDRSTRLEN + 1];

    int version = 4;
    int uid = 0;

    uint16_t mss = get_default_mss(version);
    uint8_t ws = 8;

    int send_window = ntohs(65535);
    int sequence_number = ntohs(5000);

    int sport = ntohs(40404);
    int dport = ntohs(50508);


    int packet = 2;

    struct allowed *redirect = NULL;

    log_android(ANDROID_LOG_ERROR, "%d new debug session mss %u ws %u window %u",
                packet, mss, ws, send_window << ws);

    // Register session
    struct ng_session *s = ng_malloc(sizeof(struct ng_session), "tcp session");
    s->protocol = IPPROTO_TCP;

    s->tcp.time = time(NULL);
    s->tcp.uid = uid;
    s->tcp.version = version;
    s->tcp.mss = mss;
    s->tcp.recv_scale = ws;
    s->tcp.send_scale = ws;
    s->tcp.send_window = ((uint32_t) send_window) << ws;


    s->tcp.unconfirmed = 0;
    s->tcp.remote_seq = (uint32_t) sequence_number; // probably should change hardcoded seq #
    //s->tcp.remote_seq = ntohl(tcphdr->seq); // ISN remote
    s->tcp.local_seq = (uint32_t) rand(); // ISN local
    s->tcp.remote_start = s->tcp.remote_seq;
    s->tcp.local_start = s->tcp.local_seq;
    s->tcp.acked = 0;
    s->tcp.last_keep_alive = 0;
    s->tcp.sent = 0;
    s->tcp.received = 0;

    log_android(ANDROID_LOG_ERROR, "got to change address..");

    if (version == 4) {
        inet_aton("10.1.10.1", &s->tcp.saddr.ip4);
        inet_aton("some_server_ip", &s->tcp.daddr.ip4);
    }

    saddr = &s->tcp.saddr.ip4;
    daddr = &s->tcp.daddr.ip4;

    inet_ntop(AF_INET, saddr, source, sizeof(source));
    inet_ntop(AF_INET, daddr, dest, sizeof(dest));

    log_android(ANDROID_LOG_ERROR, "new debug IP packet has source: %s, dest: %s", source, dest);

    s->tcp.source = sport; //tcphdr->source;
    s->tcp.dest = dport; // tcphdr->dest;
    s->tcp.state = TCP_LISTEN;
    s->tcp.socks5 = SOCKS5_NONE;
    s->tcp.forward = NULL;
    s->next = NULL;


    log_android(ANDROID_LOG_ERROR, "got to data with source:");

    /*
    if (datalen) {
        log_android(ANDROID_LOG_WARN, "%s SYN data", packet);
        s->tcp.forward = ng_malloc(sizeof(struct segment), "syn segment");
        s->tcp.forward->seq = s->tcp.remote_seq;
        s->tcp.forward->len = datalen;
        s->tcp.forward->sent = 0;
        s->tcp.forward->psh = tcphdr->psh;
        s->tcp.forward->data = ng_malloc(datalen, "syn segment data");
        memcpy(s->tcp.forward->data, data, datalen);
        s->tcp.forward->next = NULL;
    }
     */

    log_android(ANDROID_LOG_ERROR, "got to open socket with sport: %d, dport %d", sport, dport);
    // Open socket
    s->socket = open_tcp_socket(args, &s->tcp, redirect);
    if (s->socket < 0) {
        // Remote might retry
        ng_free(s, __FILE__, __LINE__);
        return 0;
    }



    s->tcp.recv_window = get_receive_window(s);
    log_android(ANDROID_LOG_DEBUG, "TCP socket %d lport %d",
                s->socket, get_local_port(s->socket));




    // Monitor events
    memset(&s->ev, 0, sizeof(struct epoll_event));
    s->ev.events = EPOLLOUT | EPOLLERR;
    s->ev.data.ptr = s;



    log_android(ANDROID_LOG_ERROR, "DEBUG adding epoll monitor events: %d", epoll_fd);
    if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, s->socket, &s->ev))
        log_android(ANDROID_LOG_ERROR, "epoll add tcp error %d: %s",
                    errno, strerror(errno));


    s->next = args->ctx->ng_session;
    //args->ctx->ng_session->next = s;
    debug_socket = s;


    return 1;

}





void debug_socket_init(const struct arguments *args, int epoll_fd) {
    // TODO: Init the socket. Initialize this socket kind of like what happens
    // in tcp.c for open_tcp_socket.
    // debug_socket = open()

    log_android(ANDROID_LOG_ERROR, "initalizing debug socket");
    open_debug_socket(args, epoll_fd);




}
void read_debug_socket() {
    // TODO: Figure out what needs to be passed as parameters to this function
    return ;
}

void write_debug_socket(const struct arguments *args, const uint8_t *buffer, size_t length) {
    // TODO: This function is modelled after write_pcap_ret so I made
    // parameters for this function the same since we basically want to do the same thing.

    //struct tcp_session *cur = &debug_socket->tcp;

    // test write to the debug socket
    //write_data(args, cur, buffer, length);


    // Forward to tun
    if (write_data(args, &debug_socket->tcp, buffer, length) >= 0) {

        log_android(ANDROID_LOG_ERROR, "Writing to debug socket with length: %d", length);
        debug_socket->tcp.local_seq += length;
        debug_socket->tcp.unconfirmed++;
    }



}




