#include <iostream>
#include <string>
#include <cassert>
#include <cstring>
#include <memory>
#include <thread>
#include <chrono>

#include "connection.h"
#include "eventapi.h"
#include "exception.h"

using namespace netplus;

// Minimal test server implementing eventapi
class MyServer : public event {
  public:
    MyServer(std::vector<netplus::socket*> serversockets, int timeout=1000)
          : event(serversockets, timeout) {
    }

    void RequestEvent(con &curcon, const int tid, ULONG_PTR args) override {
        const std::string body = "Hello world\n";
        std::string resp;
        resp += "HTTP/1.1 200 OK\r\n";
        resp += "Content-Type: text/plain\r\n";
        resp += "Content-Length: " + std::to_string(body.size()) + "\r\n";
        resp += "Connection: close\r\n";
        resp += "\r\n";
        resp += body;

        curcon.SendData.append(resp.data(), resp.size());
    }

    void ResponseEvent(con &curcon, const int tid, ULONG_PTR args) override {
    }

    void ConnectEvent(con &curcon, const int tid, ULONG_PTR args) override {
    }

    void DisconnectEvent(con &curcon, const int tid, ULONG_PTR args) override {
    }

    void CreateConnection(std::shared_ptr<con> &res) override {
        res = std::make_shared<con>(this);
    }
};

int main() {
    // Reset global state in case a previous run left it dirty
    event::Running = true;

    tcp MySocket("127.0.0.1", 8080, 1024, -1);

    MyServer srv({&MySocket});

    // Run the server in a background thread
    std::thread serverThread([&srv]() {
        srv.runEventloop();
    });

    // Give the server time to start the event loop
    std::this_thread::sleep_for(std::chrono::milliseconds(500));

    int result = 1; // default = failure

    try {
        // Connect a client
        tcp client;
        client.connect("127.0.0.1", 8080);
        client.setTimeout(5000);

        // Send an HTTP request
        const std::string request =
            "GET / HTTP/1.1\r\n"
            "Host: 127.0.0.1\r\n"
            "Connection: close\r\n"
            "\r\n";

        buffer sendbuf(request.data(), request.size());
        client.sendData(sendbuf);

        // Read the response (with timeout protection)
        std::string response;
        for (;;) {
            buffer recvbuf(4096);
            size_t n = 0;
            try {
                n = client.recvData(recvbuf);
            } catch (...) {
                break;
            }
            if (n == 0) break;
            response.append(recvbuf.data.buf, n);

            // Check if we received complete HTTP response (headers + body)
            auto hdr_end = response.find("\r\n\r\n");
            if (hdr_end != std::string::npos) {
                // Parse Content-Length
                size_t body_start = hdr_end + 4;
                auto cl_pos = response.find("Content-Length: ");
                if (cl_pos != std::string::npos) {
                    size_t cl_val = std::stoul(response.substr(cl_pos + 16));
                    if (response.size() >= body_start + cl_val)
                        break; // got entire response
                }
            }
        }

        client.close();

        // Verify the response
        if (response.find("HTTP/1.1 200 OK") != std::string::npos &&
            response.find("Hello world") != std::string::npos) {
            std::cout << "HTTP test PASSED" << std::endl;
            result = 0;
        } else {
            std::cerr << "HTTP test FAILED: unexpected response:\n"
                      << response << std::endl;
        }
    } catch (const std::exception &e) {
        std::cerr << "HTTP test FAILED with exception: " << e.what() << std::endl;
    } catch (...) {
        std::cerr << "HTTP test FAILED with unknown exception" << std::endl;
    }

    // Stop the server
    event::Running = false;

    if (serverThread.joinable())
        serverThread.join();

    return result;
}
