#include <uv.h>
#include <iostream>
#include <vector>
#include <cstdlib>
#include <cstring>
#include <thread>
#include <mutex>
#include <chrono>
#include <iomanip>
#include <sstream>

#define container_of(ptr, type, member) \
    ((type *)((char *)(ptr) - offsetof(type, member)))

const int MAX_CONNECTIONS = 300;
const int MAX_MESSAGE_SIZE = 1024 * 1024; // 1MB

struct Client {
    uv_tcp_t handle;
    uv_connect_t connect_req;
    uv_write_t write_req;
    std::string server_ip;
    int server_port;
    bool connected;
    std::mutex mutex;
};

std::vector<Client*> clients;
uv_loop_t* loop;

void on_write(uv_write_t* req, int status) {
    Client* client = container_of(req, Client, write_req);
    if (status < 0) {
        std::cerr << "Write error: " << uv_strerror(status) << std::endl;
        uv_close((uv_handle_t*)&client->handle, nullptr);
    }
}

void on_read(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) {
    Client* client = container_of(stream, Client, handle);
    if (nread < 0) {
        std::cerr << "Read error: " << uv_strerror(nread) << std::endl;
        uv_close((uv_handle_t*)&client->handle, nullptr);
        free(buf->base);
        return;
    }

    if (nread > 0) {
        std::cout << "Received " << nread << " bytes from server" << std::endl;
    }

    free(buf->base);
}

void on_connect(uv_connect_t* req, int status) {
    Client* client = container_of(req, Client, connect_req);
    if (status < 0) {
        std::cerr << "Connect error: " << uv_strerror(status) << std::endl;
        uv_close((uv_handle_t*)&client->handle, nullptr);
        return;
    }

    client->connected = true;
    std::cout << "Connected to server: " << client->server_ip << ":" << client->server_port << std::endl;

    // Get the client's IP and port
    struct sockaddr_in addr;
    int addr_len = sizeof(addr);
    uv_tcp_getpeername(&client->handle, (struct sockaddr*)&addr, &addr_len);

    char client_ip[INET_ADDRSTRLEN];
    uv_ip4_name((const struct sockaddr_in*)&addr, client_ip, INET_ADDRSTRLEN);
    int client_port = ntohs(addr.sin_port);

    // Prepare message with client's IP and port
    std::stringstream ss;
    ss << "Client IP: " << client_ip << ", Port: " << client_port;
    std::string message = ss.str();

    // Send the message
    uv_buf_t buf_list = uv_buf_init(const_cast<char*>(message.c_str()), message.size());
    uv_write(&client->write_req, (uv_stream_t*)&client->handle, &buf_list, 1, on_write);

    uv_read_start((uv_stream_t*)&client->handle, [](uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf) {
        buf->base = (char*)malloc(suggested_size);
        buf->len = suggested_size;
    }, on_read);
}

void start_client(Client* client) {
    struct sockaddr_in addr;
    uv_ip4_addr(client->server_ip.c_str(), client->server_port, &addr);

    uv_tcp_init(loop, &client->handle);
    uv_tcp_connect(&client->connect_req, &client->handle, (const struct sockaddr*)&addr, on_connect);
}

void run_client_thread(Client* client) {
    start_client(client);
    uv_run(loop, UV_RUN_DEFAULT);
}

int main2() {
    loop = uv_default_loop();

    // Create and start 300 clients
    for (int i = 0; i < MAX_CONNECTIONS; ++i) {
        Client* client = new Client;
        client->server_ip = "172.22.128.1"; // Replace with your server IP
        client->server_port = 8098;       // Replace with your server port
        client->connected = false;

        std::thread client_thread(run_client_thread, client);
        client_thread.detach();

        clients.push_back(client);
    }

    // Handle shutdown or other logic here
    while (true) {
        // You can add logic to handle client connections, messages, etc.
        // For example, sending data periodically or handling disconnects.
        uv_run(loop, UV_RUN_ONCE);
    }

    return 0;
}