#define NOMINMAX
#include <winsock2.h>
#include <ws2tcpip.h>
#include <windows.h>
#include <zmq.h>

#include "../XYParserApi.h"

#include <algorithm>
#include <array>
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <cwchar>
#include <cmath>
#include <iomanip>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>

namespace {

constexpr wchar_t kProgramName[] = L"XYAlgorithmUdpServer";
constexpr wchar_t kDefaultListenHost[] = L"127.0.0.1";
constexpr int kDefaultListenPort = 8100;
constexpr int kDefaultReceiveTimeoutMs = 1000;
constexpr int kDefaultSampleRate = 250;
constexpr double kDefaultHighPassHz = 0.5;
constexpr double kDefaultLowPassHz = 45.0;
constexpr double kDefaultNotchHz = 50.0;
constexpr double kDefaultNotchQ = 30.0;
constexpr double kDefaultClipUv = 5000.0;

enum class ResponseMode {
    Preprocess,
    Echo,
    Zero
};

struct ServerOptions {
    std::wstring listen_host = kDefaultListenHost;
    int listen_port = kDefaultListenPort;
    int receive_timeout_ms = kDefaultReceiveTimeoutMs;
    int sample_rate = kDefaultSampleRate;
    double high_pass_hz = kDefaultHighPassHz;
    double low_pass_hz = kDefaultLowPassHz;
    double notch_hz = kDefaultNotchHz;
    double notch_q = kDefaultNotchQ;
    double clip_uv = kDefaultClipUv;
    ResponseMode response_mode = ResponseMode::Preprocess;
};

class WinsockRuntime {
public:
    WinsockRuntime()
    {
        WSADATA wsa_data{};
        ok_ = (WSAStartup(MAKEWORD(2, 2), &wsa_data) == 0);
    }

    ~WinsockRuntime()
    {
        if (ok_) {
            WSACleanup();
        }
    }

    bool ok() const { return ok_; }

private:
    bool ok_ = false;
};

bool ParseInt(const wchar_t* text, int& value)
{
    if (text == nullptr || text[0] == L'\0') {
        return false;
    }

    wchar_t* end = nullptr;
    const long parsed = std::wcstol(text, &end, 10);
    if (end == text || *end != L'\0') {
        return false;
    }

    value = static_cast<int>(parsed);
    return true;
}

bool ParseDouble(const wchar_t* text, double& value)
{
    if (text == nullptr || text[0] == L'\0') {
        return false;
    }

    wchar_t* end = nullptr;
    value = std::wcstod(text, &end);
    return end != text && *end == L'\0';
}

bool EqualsIgnoreCase(const std::wstring& left, const wchar_t* right)
{
    return _wcsicmp(left.c_str(), right) == 0;
}

bool ParseResponseMode(const wchar_t* text, ResponseMode& mode)
{
    if (text == nullptr) {
        return false;
    }

    const std::wstring value(text);
    if (EqualsIgnoreCase(value, L"preprocess")) {
        mode = ResponseMode::Preprocess;
        return true;
    }
    if (EqualsIgnoreCase(value, L"echo")) {
        mode = ResponseMode::Echo;
        return true;
    }
    if (EqualsIgnoreCase(value, L"zero")) {
        mode = ResponseMode::Zero;
        return true;
    }
    return false;
}

std::string Narrow(const std::wstring& value)
{
    if (value.empty()) {
        return std::string();
    }

    const int size = WideCharToMultiByte(CP_UTF8, 0, value.c_str(), -1, nullptr, 0, nullptr, nullptr);
    if (size <= 0) {
        return std::string();
    }

    std::string converted(static_cast<std::size_t>(size - 1), '\0');
    WideCharToMultiByte(CP_UTF8, 0, value.c_str(), -1, converted.data(), size, nullptr, nullptr);
    return converted;
}

std::string BuildZmqTcpEndpoint(const std::wstring& host, int port)
{
    return "tcp://" + Narrow(host) + ':' + std::to_string(port);
}

void PrintUsage()
{
    std::wcout << L"Usage: " << kProgramName << L" [options]\n"
               << L"  --listen-host 127.0.0.1\n"
               << L"  --listen-port 8100\n"
               << L"  --receive-timeout-ms 1000\n"
               << L"  --sample-rate 250\n"
               << L"  --high-pass-hz 0.5\n"
               << L"  --low-pass-hz 45\n"
               << L"  --notch-hz 50\n"
               << L"  --notch-q 30\n"
               << L"  --clip-uv 5000\n"
               << L"  --mode preprocess|echo|zero\n";
}

bool ParseArguments(int argc, wchar_t* argv[], ServerOptions& options)
{
    for (int i = 1; i < argc; ++i) {
        const std::wstring arg(argv[i]);
        if (arg == L"--listen-host" && i + 1 < argc) {
            options.listen_host = argv[++i];
        } else if (arg == L"--listen-port" && i + 1 < argc) {
            if (!ParseInt(argv[++i], options.listen_port)) {
                return false;
            }
        } else if (arg == L"--receive-timeout-ms" && i + 1 < argc) {
            if (!ParseInt(argv[++i], options.receive_timeout_ms)) {
                return false;
            }
        } else if (arg == L"--sample-rate" && i + 1 < argc) {
            if (!ParseInt(argv[++i], options.sample_rate)) {
                return false;
            }
        } else if (arg == L"--high-pass-hz" && i + 1 < argc) {
            if (!ParseDouble(argv[++i], options.high_pass_hz)) {
                return false;
            }
        } else if (arg == L"--low-pass-hz" && i + 1 < argc) {
            if (!ParseDouble(argv[++i], options.low_pass_hz)) {
                return false;
            }
        } else if (arg == L"--notch-hz" && i + 1 < argc) {
            if (!ParseDouble(argv[++i], options.notch_hz)) {
                return false;
            }
        } else if (arg == L"--notch-q" && i + 1 < argc) {
            if (!ParseDouble(argv[++i], options.notch_q)) {
                return false;
            }
        } else if (arg == L"--clip-uv" && i + 1 < argc) {
            if (!ParseDouble(argv[++i], options.clip_uv)) {
                return false;
            }
        } else if (arg == L"--mode" && i + 1 < argc) {
            if (!ParseResponseMode(argv[++i], options.response_mode)) {
                return false;
            }
        } else if (arg == L"--help" || arg == L"-h") {
            return false;
        } else {
            return false;
        }
    }

    return options.listen_port > 0 &&
           options.receive_timeout_ms >= 0 &&
           options.sample_rate > 0 &&
           options.high_pass_hz >= 0.0 &&
           options.low_pass_hz > 0.0 &&
           options.notch_hz >= 0.0 &&
           options.notch_q > 0.0 &&
           options.clip_uv > 0.0 &&
           options.high_pass_hz < options.low_pass_hz &&
           options.low_pass_hz < (static_cast<double>(options.sample_rate) * 0.5);
}

class DcBlocker {
public:
    void Configure(double sample_rate_hz, double high_pass_hz)
    {
        if (high_pass_hz <= 0.0 || sample_rate_hz <= 0.0) {
            enabled_ = false;
            x_prev_ = 0.0;
            y_prev_ = 0.0;
            return;
        }

        const double normalized = 2.0 * 3.14159265358979323846 * high_pass_hz / sample_rate_hz;
        feedback_ = std::exp(-normalized);
        enabled_ = true;
        x_prev_ = 0.0;
        y_prev_ = 0.0;
    }

    double Process(double value)
    {
        if (!enabled_) {
            return value;
        }

        const double output = value - x_prev_ + feedback_ * y_prev_;
        x_prev_ = value;
        y_prev_ = output;
        return output;
    }

private:
    bool enabled_ = false;
    double feedback_ = 0.0;
    double x_prev_ = 0.0;
    double y_prev_ = 0.0;
};

class OnePoleLowPass {
public:
    void Configure(double sample_rate_hz, double cutoff_hz)
    {
        if (cutoff_hz <= 0.0 || sample_rate_hz <= 0.0) {
            enabled_ = false;
            y_prev_ = 0.0;
            return;
        }

        const double dt = 1.0 / sample_rate_hz;
        const double rc = 1.0 / (2.0 * 3.14159265358979323846 * cutoff_hz);
        alpha_ = dt / (rc + dt);
        enabled_ = true;
        initialized_ = false;
        y_prev_ = 0.0;
    }

    double Process(double value)
    {
        if (!enabled_) {
            return value;
        }

        if (!initialized_) {
            y_prev_ = value;
            initialized_ = true;
            return value;
        }

        y_prev_ += alpha_ * (value - y_prev_);
        return y_prev_;
    }

private:
    bool enabled_ = false;
    bool initialized_ = false;
    double alpha_ = 0.0;
    double y_prev_ = 0.0;
};

class NotchBiquad {
public:
    void Configure(double sample_rate_hz, double notch_hz, double q)
    {
        if (sample_rate_hz <= 0.0 || notch_hz <= 0.0 || q <= 0.0 ||
            notch_hz >= (sample_rate_hz * 0.5)) {
            enabled_ = false;
            ResetState();
            return;
        }

        const double omega = 2.0 * 3.14159265358979323846 * notch_hz / sample_rate_hz;
        const double alpha = std::sin(omega) / (2.0 * q);
        const double cos_omega = std::cos(omega);
        const double a0 = 1.0 + alpha;

        b0_ = 1.0 / a0;
        b1_ = (-2.0 * cos_omega) / a0;
        b2_ = 1.0 / a0;
        a1_ = (-2.0 * cos_omega) / a0;
        a2_ = (1.0 - alpha) / a0;
        enabled_ = true;
        ResetState();
    }

    double Process(double value)
    {
        if (!enabled_) {
            return value;
        }

        const double output = b0_ * value + b1_ * x1_ + b2_ * x2_ - a1_ * y1_ - a2_ * y2_;
        x2_ = x1_;
        x1_ = value;
        y2_ = y1_;
        y1_ = output;
        return output;
    }

private:
    void ResetState()
    {
        x1_ = 0.0;
        x2_ = 0.0;
        y1_ = 0.0;
        y2_ = 0.0;
    }

    bool enabled_ = false;
    double b0_ = 1.0;
    double b1_ = 0.0;
    double b2_ = 0.0;
    double a1_ = 0.0;
    double a2_ = 0.0;
    double x1_ = 0.0;
    double x2_ = 0.0;
    double y1_ = 0.0;
    double y2_ = 0.0;
};

class ChannelPreprocessor {
public:
    void Configure(const ServerOptions& options)
    {
        const double sample_rate = static_cast<double>(options.sample_rate);
        dc_blocker_.Configure(sample_rate, options.high_pass_hz);
        low_pass_.Configure(sample_rate, options.low_pass_hz);
        notch_.Configure(sample_rate, options.notch_hz, options.notch_q);
        clip_uv_ = options.clip_uv;
    }

    double Process(double value)
    {
        double processed = dc_blocker_.Process(value);
        processed = notch_.Process(processed);
        processed = low_pass_.Process(processed);
        return std::clamp(processed, -clip_uv_, clip_uv_);
    }

private:
    DcBlocker dc_blocker_;
    OnePoleLowPass low_pass_;
    NotchBiquad notch_;
    double clip_uv_ = kDefaultClipUv;
};

class AlgorithmProcessor {
public:
    void Configure(const ServerOptions& options)
    {
        for (auto& channel : channels_) {
            channel.Configure(options);
        }
    }

    std::size_t BuildResponsePayload(const std::uint8_t* request,
                                     std::size_t request_size,
                                     ResponseMode mode,
                                     std::vector<std::uint8_t>& response)
    {
        if ((request_size % sizeof(double)) != 0) {
            response.clear();
            return 0;
        }

        const std::size_t value_count = request_size / sizeof(double);
        if ((value_count % static_cast<std::size_t>(XYPARSER_FRAME_DATA_COLUMN_COUNT)) != 0) {
            response.clear();
            return 0;
        }
        const std::size_t sample_count =
            value_count / static_cast<std::size_t>(XYPARSER_FRAME_DATA_COLUMN_COUNT);
        const std::size_t response_value_count =
            sample_count * static_cast<std::size_t>(XYPARSER_MAX_CHANNELS);
        const std::size_t response_size = response_value_count * sizeof(double);
        response.resize(response_size);

        const auto* input_values = reinterpret_cast<const double*>(request);
        auto* output_values = reinterpret_cast<double*>(response.data());

        if (mode == ResponseMode::Zero) {
            std::fill(response.begin(), response.end(), 0);
            return response_size;
        }

        for (std::size_t sample_index = 0; sample_index < sample_count; ++sample_index) {
            const std::size_t input_sample_offset =
                sample_index * static_cast<std::size_t>(XYPARSER_FRAME_DATA_COLUMN_COUNT);
            const std::size_t output_sample_offset =
                sample_index * static_cast<std::size_t>(XYPARSER_MAX_CHANNELS);
            for (std::size_t channel_index = 0; channel_index < XYPARSER_MAX_CHANNELS; ++channel_index) {
                const std::size_t input_value_index = input_sample_offset + channel_index;
                const std::size_t output_value_index = output_sample_offset + channel_index;
                if (input_value_index >= value_count || output_value_index >= response_value_count) {
                response.clear();
                return 0;
            }
                output_values[output_value_index] =
                    (mode == ResponseMode::Echo)
                        ? input_values[input_value_index]
                        : channels_[channel_index].Process(input_values[input_value_index]);
            }
        }

        return response_size;
    }

private:
    std::array<ChannelPreprocessor, XYPARSER_MAX_CHANNELS> channels_{};
};

const char* DescribeTriggerType(int trigger_type)
{
    switch (trigger_type) {
    case XYPARSER_TRIGGER_NONE:
        return "NONE";
    case XYPARSER_TRIGGER_TRAIN_0:
        return "TRAIN_0";
    case XYPARSER_TRIGGER_TRAIN_1:
        return "TRAIN_1";
    default:
        return "UNKNOWN";
    }
}

const char* GetLeadName(std::size_t channel_index)
{
    static constexpr const char* kLeadNames[XYPARSER_MAX_CHANNELS] = {
        "FP1", "FP2", "PO6", "POZ", "F3",  "F4",  "FPZ", "AF4",
        "FC3", "PO8", "CP2", "CP1", "FCZ", "PO5", "FC2", "FC1",
        "C3",  "C4",  "FC4", "CP4", "P3",  "P4",  "F5",  "C5",
        "F6",  "PO4", "CP6", "CP5", "PO3", "CP3", "FC6", "FC5",
        "CB1", "CB2", "P5",  "AF7", "A1",  "T7",  "FT7", "TP7",
        "FT8", "AF8", "F8",  "F7",  "P6",  "C6",  "O2",  "O1",
        "T8",  "P7",  "CZ",  "PZ",  "P8",  "FZ",  "OZ",  "PO7",
        "TP8", "AF3", "C2",  "C1",  "P2",  "P1",  "F2",  "F1"
    };
    if (channel_index >= std::size(kLeadNames)) {
        return "lead?";
    }
    return kLeadNames[channel_index];
}

void PrintActiveChannelSamples(const double* values,
                               std::size_t value_count,
                               const std::string& remote_endpoint,
                               std::uint64_t packet_count)
{
    for (std::size_t sample_index = 0; sample_index < XYPARSER_SAMPLES_PER_FRAME; ++sample_index) {
        const std::size_t sample_offset =
            sample_index * static_cast<std::size_t>(XYPARSER_FRAME_DATA_COLUMN_COUNT);
        const std::size_t trigger_type_index = sample_offset + XYPARSER_FRAME_DATA_TRIGGER_TYPE_INDEX;
        const std::size_t trigger_index_index = sample_offset + XYPARSER_FRAME_DATA_TRIGGER_INDEX_INDEX;
        if (trigger_index_index >= value_count) {
            return;
        }

        std::ostringstream channel_stream;
        int active_channel_count = 0;
        for (std::size_t channel_index = 0; channel_index < XYPARSER_MAX_CHANNELS; ++channel_index) {
            const std::size_t value_index = sample_offset + channel_index;
            if (value_index >= value_count) {
                return;
            }

            const double value_uv = values[value_index];
            if (value_uv == 0.0) {
                continue;
            }

            if (active_channel_count > 0) {
                channel_stream << " | ";
            }
            channel_stream << GetLeadName(channel_index)
                           << '=' << value_uv << "uV";
            ++active_channel_count;
        }

        if (active_channel_count == 0) {
            continue;
        }

        const int trigger_type = static_cast<int>(std::llround(values[trigger_type_index]));
        const int trigger_index = static_cast<int>(std::llround(values[trigger_index_index]));
        std::cout << "[AlgorithmZmqServer][ActiveSample]"
                  << " packet=" << packet_count
                  << " sample=" << sample_index
                  << " remote=" << remote_endpoint
                  << " trigger=" << trigger_type
                  << '(' << DescribeTriggerType(trigger_type) << ')'
                  << " triggerIndex=" << trigger_index
                  << " channels=" << channel_stream.str()
                  << std::endl;
    }
}

class TriggerChangeLogger {
public:
    void ObservePayload(const double* values,
                        std::size_t value_count,
                        const std::string& remote_endpoint,
                        std::uint64_t packet_count)
    {
        for (std::size_t sample_index = 0; sample_index < XYPARSER_SAMPLES_PER_FRAME; ++sample_index) {
            const std::size_t sample_offset =
                sample_index * static_cast<std::size_t>(XYPARSER_FRAME_DATA_COLUMN_COUNT);
            const std::size_t trigger_type_index = sample_offset + XYPARSER_FRAME_DATA_TRIGGER_TYPE_INDEX;
            const std::size_t trigger_index_index = sample_offset + XYPARSER_FRAME_DATA_TRIGGER_INDEX_INDEX;
            if (trigger_index_index >= value_count) {
                return;
            }

            const int trigger_type = static_cast<int>(std::llround(values[trigger_type_index]));
            const int trigger_index = static_cast<int>(std::llround(values[trigger_index_index]));
            if (!has_last_trigger_ ||
                trigger_type != last_trigger_type_ ||
                trigger_index != last_trigger_index_) {
                has_last_trigger_ = true;
                last_trigger_type_ = trigger_type;
                last_trigger_index_ = trigger_index;
                std::cout << "[AlgorithmZmqServer][Trigger] packet=" << packet_count
                          << " sample=" << sample_index
                          << " remote=" << remote_endpoint
                          << " type=" << trigger_type
                          << '(' << DescribeTriggerType(trigger_type) << ')'
                          << " index=" << trigger_index
                          << std::endl;
            }
        }
    }

private:
    bool has_last_trigger_ = false;
    int last_trigger_type_ = 0;
    int last_trigger_index_ = 0;
};

class ZmqAlgorithmServer {
public:
    ~ZmqAlgorithmServer() { Close(); }

    bool Open(const ServerOptions& options)
    {
        Close();
        last_error_text_.clear();
        last_client_identity_.clear();
        local_endpoint_ = BuildZmqTcpEndpoint(options.listen_host, options.listen_port);

        context_ = zmq_ctx_new();
        if (context_ == nullptr) {
            last_error_text_ = zmq_strerror(zmq_errno());
            return false;
        }

        socket_ = zmq_socket(context_, ZMQ_ROUTER);
        if (socket_ == nullptr) {
            last_error_text_ = zmq_strerror(zmq_errno());
            Close();
            return false;
        }

        const int linger_ms = 0;
        zmq_setsockopt(socket_, ZMQ_LINGER, &linger_ms, sizeof(linger_ms));
        zmq_setsockopt(socket_, ZMQ_RCVTIMEO, &options.receive_timeout_ms, sizeof(options.receive_timeout_ms));
        zmq_setsockopt(socket_, ZMQ_SNDTIMEO, &options.receive_timeout_ms, sizeof(options.receive_timeout_ms));

        if (zmq_bind(socket_, local_endpoint_.c_str()) != 0) {
            last_error_text_ = zmq_strerror(zmq_errno());
            Close();
            return false;
        }

        return true;
    }

    int Receive(std::uint8_t* buffer, int capacity, std::vector<std::uint8_t>& client_identity, bool& timed_out)
    {
        timed_out = false;
        client_identity.clear();
        if (socket_ == nullptr) {
            last_error_text_ = "socket not open";
            return -1;
        }

        std::vector<std::uint8_t> identity_frame;
        bool has_more = false;
        if (!ReceiveFrame(identity_frame, has_more)) {
            timed_out = (last_error_text_ == "Resource temporarily unavailable");
            return timed_out ? 0 : -1;
        }
        if (!has_more) {
            last_error_text_ = "missing payload frame";
            return -1;
        }

        std::vector<std::uint8_t> second_frame;
        if (!ReceiveFrame(second_frame, has_more)) {
            timed_out = (last_error_text_ == "Resource temporarily unavailable");
            return timed_out ? 0 : -1;
        }

        std::vector<std::uint8_t> payload_frame;
        if (!has_more) {
            payload_frame = std::move(second_frame);
        } else if (second_frame.empty()) {
            if (!ReceiveFrame(payload_frame, has_more)) {
                timed_out = (last_error_text_ == "Resource temporarily unavailable");
                return timed_out ? 0 : -1;
            }
            if (has_more) {
                last_error_text_ = "unexpected multipart payload";
                return -1;
            }
        } else {
            std::vector<std::uint8_t> third_frame;
            if (!ReceiveFrame(third_frame, has_more)) {
                timed_out = (last_error_text_ == "Resource temporarily unavailable");
                return timed_out ? 0 : -1;
            }
            if (!has_more) {
                payload_frame = std::move(third_frame);
            } else {
                if (!third_frame.empty()) {
                    last_error_text_ = "unexpected non-empty delimiter frame";
                    return -1;
                }
                if (!ReceiveFrame(payload_frame, has_more)) {
                    timed_out = (last_error_text_ == "Resource temporarily unavailable");
                    return timed_out ? 0 : -1;
                }
                if (has_more) {
                    last_error_text_ = "unexpected multipart payload";
                    return -1;
                }
            }
        }
        if (payload_frame.size() > static_cast<std::size_t>(capacity)) {
            last_error_text_ = "payload too large";
            return -1;
        }

        std::memcpy(buffer, payload_frame.data(), payload_frame.size());
        client_identity = std::move(identity_frame);
        last_client_identity_ = DescribeClientIdentity(client_identity);
        last_error_text_.clear();
        return static_cast<int>(payload_frame.size());
    }

    bool Send(const std::uint8_t* data, int size, const std::vector<std::uint8_t>& client_identity)
    {
        if (socket_ == nullptr) {
            last_error_text_ = "socket not open";
            return false;
        }

        const int sent_identity = zmq_send(socket_,
                                           client_identity.data(),
                                           client_identity.size(),
                                           ZMQ_SNDMORE);
        if (sent_identity != static_cast<int>(client_identity.size())) {
            last_error_text_ = zmq_strerror(zmq_errno());
            return false;
        }

        const int sent_empty = zmq_send(socket_, nullptr, 0, ZMQ_SNDMORE);
        if (sent_empty != 0) {
            last_error_text_ = zmq_strerror(zmq_errno());
            return false;
        }

        const int sent_payload = zmq_send(socket_, data, size, 0);
        if (sent_payload != size) {
            last_error_text_ = zmq_strerror(zmq_errno());
            return false;
        }

        last_error_text_.clear();
        return true;
    }

    const std::string& last_error() const { return last_error_text_; }
    const std::string& local_endpoint() const { return local_endpoint_; }
    const std::string& last_client_identity() const { return last_client_identity_; }

private:
    bool ReceiveFrame(std::vector<std::uint8_t>& frame, bool& has_more)
    {
        zmq_msg_t message;
        zmq_msg_init(&message);
        const int received = zmq_msg_recv(&message, socket_, 0);
        if (received < 0) {
            last_error_text_ = zmq_strerror(zmq_errno());
            zmq_msg_close(&message);
            return false;
        }

        const auto* data = static_cast<const std::uint8_t*>(zmq_msg_data(&message));
        const std::size_t size = zmq_msg_size(&message);
        frame.assign(data, data + size);

        int more = 0;
        size_t more_size = sizeof(more);
        zmq_getsockopt(socket_, ZMQ_RCVMORE, &more, &more_size);
        has_more = (more != 0);
        zmq_msg_close(&message);
        return true;
    }

    std::string DescribeClientIdentity(const std::vector<std::uint8_t>& client_identity) const
    {
        return std::string(reinterpret_cast<const char*>(client_identity.data()), client_identity.size());
    }

    void Close()
    {
        if (socket_ != nullptr) {
            zmq_close(socket_);
            socket_ = nullptr;
        }
        if (context_ != nullptr) {
            zmq_ctx_term(context_);
            context_ = nullptr;
        }
        last_client_identity_.clear();
    }

    void* context_ = nullptr;
    void* socket_ = nullptr;
    std::string last_error_text_;
    std::string local_endpoint_;
    std::string last_client_identity_;
};

int RunServer(const ServerOptions& options)
{
    ZmqAlgorithmServer server;
    if (!server.Open(options)) {
        std::cerr << "Open algorithm ZMQ server failed"
                  << " endpoint=" << BuildZmqTcpEndpoint(options.listen_host, options.listen_port)
                  << " zmqError=" << server.last_error()
                  << std::endl;
        return 1;
    }

    constexpr std::size_t expected_payload_bytes =
        XYPARSER_FRAME_ALGORITHM_VALUE_COUNT * sizeof(double);
    std::array<std::uint8_t, expected_payload_bytes> request_buffer{};
    std::vector<std::uint8_t> response_buffer;
    AlgorithmProcessor processor;
    TriggerChangeLogger trigger_logger;
    processor.Configure(options);
    std::uint64_t packet_count = 0;
    std::uint64_t invalid_payload_count = 0;

    std::cout << "Algorithm ZMQ server listening"
              << " local=" << server.local_endpoint()
              << " payloadBytes=" << expected_payload_bytes
              << " payloadDoubles=" << XYPARSER_FRAME_ALGORITHM_VALUE_COUNT
              << " mode="
              << (options.response_mode == ResponseMode::Preprocess
                      ? "preprocess"
                      : (options.response_mode == ResponseMode::Echo ? "echo" : "zero"))
              << " sampleRate=" << options.sample_rate
              << " highPassHz=" << options.high_pass_hz
              << " lowPassHz=" << options.low_pass_hz
              << " notchHz=" << options.notch_hz
              << " notchQ=" << options.notch_q
              << " clipUv=" << options.clip_uv
              << std::endl;

    while (true) {
        std::vector<std::uint8_t> client_identity;
        bool timed_out = false;
        const int received = server.Receive(request_buffer.data(),
                                            static_cast<int>(request_buffer.size()),
                                            client_identity,
                                            timed_out);
        if (timed_out) {
            continue;
        }
        if (received < 0) {
            std::cerr << "Receive algorithm ZMQ payload failed"
                      << " zmqError=" << server.last_error()
                      << std::endl;
            continue;
        }

        ++packet_count;
        const std::string remote_endpoint = server.last_client_identity();
        if (static_cast<std::size_t>(received) != expected_payload_bytes) {
            ++invalid_payload_count;
            std::cerr << "Unexpected algorithm ZMQ payload size"
                      << " remote=" << remote_endpoint
                      << " actualBytes=" << received
                      << " expectedBytes=" << expected_payload_bytes
                      << " invalidPayloads=" << invalid_payload_count
                      << std::endl;
            continue;
        }

        PrintActiveChannelSamples(reinterpret_cast<const double*>(request_buffer.data()),
                                  static_cast<std::size_t>(received) / sizeof(double),
                                  remote_endpoint,
                                  packet_count);
        trigger_logger.ObservePayload(reinterpret_cast<const double*>(request_buffer.data()),
                                      static_cast<std::size_t>(received) / sizeof(double),
                                      remote_endpoint,
                                      packet_count);

        const std::size_t response_size = processor.BuildResponsePayload(request_buffer.data(),
                                                                         static_cast<std::size_t>(received),
                                                                         options.response_mode,
                                                                         response_buffer);
        if (response_size == 0) {
            ++invalid_payload_count;
            std::cerr << "Build algorithm ZMQ response failed"
                      << " remote=" << remote_endpoint
                      << " actualBytes=" << received
                      << " invalidPayloads=" << invalid_payload_count
                      << std::endl;
            continue;
        }
        if (!server.Send(response_buffer.data(), static_cast<int>(response_size), client_identity)) {
            std::cerr << "Send algorithm ZMQ payload failed"
                      << " remote=" << remote_endpoint
                      << " zmqError=" << server.last_error()
                      << std::endl;
            continue;
        }

        if (packet_count <= 3 || (packet_count % 100) == 0) {
            std::cout << "[AlgorithmZmqServer] packets=" << packet_count
                      << " remote=" << remote_endpoint
                      << " bytes=" << received
                      << std::endl;
        }
    }
}

} // namespace

int wmain(int argc, wchar_t* argv[])
{
    ServerOptions options{};
    if (!ParseArguments(argc, argv, options)) {
        PrintUsage();
        return 1;
    }

    return RunServer(options);
}
