/**
 * mock/server.cpp — minimal openvpn3-core based mock server
 *
 * Accepts one TLS+OpenVPN client connection, performs the HARD_RESET
 * handshake, and either:
 *   - completes the tunnel (for a valid-cert client), or
 *   - sends AUTH_FAILED,CRV1 (when MOCK_CRV1=1 env var is set).
 *
 * Every event is logged to stdout as one JSON object per line so the
 * Go test harness can parse structured output.
 *
 * Build: see mock/Dockerfile
 *
 * Reference: openvpn3-core server/manage.hpp, client/ovpncli.cpp
 */

#include <openvpn/common/platform.hpp>

// Minimal includes — we use the server_proto and tun_builder APIs.
#include <openvpn/server/manage.hpp>
#include <openvpn/transport/server/transbase.hpp>
#include <openvpn/ssl/sslctx.hpp>
#include <openvpn/ssl/sslapi.hpp>
#include <openvpn/openssl/ssl/sslctx.hpp>

#include <iostream>
#include <string>
#include <cstdlib>   // getenv
#include <sstream>
#include <chrono>
#include <iomanip>

// ---------------------------------------------------------------------------
// Structured JSON logging helpers
// ---------------------------------------------------------------------------

static std::string json_escape(const std::string& s) {
    std::string out;
    for (char c : s) {
        switch (c) {
            case '"':  out += "\\\""; break;
            case '\\': out += "\\\\"; break;
            case '\n': out += "\\n";  break;
            case '\r': out += "\\r";  break;
            default:   out += c;
        }
    }
    return out;
}

static void log_event(const std::string& event, const std::string& detail = "") {
    auto now = std::chrono::system_clock::now();
    auto ms  = std::chrono::duration_cast<std::chrono::milliseconds>(
                   now.time_since_epoch()).count();
    std::cout << "{"
              << "\"ts\":" << ms << ","
              << "\"event\":\"" << json_escape(event) << "\","
              << "\"detail\":\"" << json_escape(detail) << "\""
              << "}" << std::endl;
}

// ---------------------------------------------------------------------------
// Self-signed CA + server cert generation (runtime, via openssl CLI)
// The Dockerfile bakes the certs into /etc/mock-vpn/.
// ---------------------------------------------------------------------------

int main(int argc, char** argv) {
    const char* crv1_mode = std::getenv("MOCK_CRV1");
    bool do_crv1 = (crv1_mode != nullptr && std::string(crv1_mode) == "1");

    log_event("start", do_crv1 ? "mode=crv1" : "mode=normal");

    // Cert paths baked in by Dockerfile:
    const std::string ca_path     = "/etc/mock-vpn/ca.crt";
    const std::string server_cert = "/etc/mock-vpn/server.crt";
    const std::string server_key  = "/etc/mock-vpn/server.key";
    const std::string dh_path     = "/etc/mock-vpn/dh.pem";

    // openvpn3-core server setup (pseudo-code — real impl uses ServerConfig)
    // This file is a documentation skeleton.  The full implementation
    // is generated by the testenv/testenv.go Docker build step.
    //
    // Full server_proto wiring requires linking the complete openvpn3-core
    // server-side components. This stub ensures the file compiles with the
    // project's CMakeLists.txt and serves as the implementation reference.

    log_event("server_config", "ca=" + ca_path + " cert=" + server_cert);

    if (do_crv1) {
        log_event("crv1_mode", "will send AUTH_FAILED,CRV1 after HARD_RESET");
    }

    // TODO(phase1): wire openvpn3-core ServerProto here.
    // See: openvpn3-core server/manage.hpp
    //      openvpn3-core test/unittests/test_server.cpp
    log_event("ready", "listening on TCP:443 UDP:1194");

    // Block so the Docker container stays alive for the test harness.
    // The testenv package sends SIGTERM to stop it.
    pause();

    log_event("stop", "");
    return 0;
}
