// SPDX-License-Identifier: GPL-3.0-or-later

#include "stream.h"

static struct {
    STREAM_HANDSHAKE err;
    const char *str;
    int response_code;
} handshake_errors[] = {
    {STREAM_HANDSHAKE_OK_V3, "CONNECTED", 200},
    {STREAM_HANDSHAKE_OK_V2, "CONNECTED", 200},
    {STREAM_HANDSHAKE_OK_V1, "CONNECTED", 200},
    {STREAM_HANDSHAKE_NEVER, "NEVER CONNECTED", 204}, // No Content
    {STREAM_HANDSHAKE_CONNECT_HANDSHAKE_FAILED, "BAD HANDSHAKE", 400}, // Bad Request
    {STREAM_HANDSHAKE_PARENT_IS_LOCALHOST, "LOCALHOST", 101}, // Switching Protocols
    {STREAM_HANDSHAKE_PARENT_NODE_ALREADY_CONNECTED, "ALREADY CONNECTED", 409}, // Conflict
    {STREAM_HANDSHAKE_PARENT_DENIED_ACCESS, "DENIED", 403}, // Forbidden
    {STREAM_HANDSHAKE_CONNECT_SEND_TIMEOUT, "SEND TIMEOUT", 408}, // Request Timeout
    {STREAM_HANDSHAKE_CONNECT_RECEIVE_TIMEOUT, "RECEIVE TIMEOUT", 504}, // Gateway Timeout
    {STREAM_HANDSHAKE_CONNECT_INVALID_CERTIFICATE, "INVALID CERTIFICATE", 495}, // Custom: SSL Certificate Error
    {STREAM_HANDSHAKE_CONNECT_SSL_ERROR, "SSL ERROR", 525}, // SSL Handshake Failure
    {STREAM_HANDSHAKE_CONNECTION_FAILED, "CANT CONNECT", 502}, // Bad Gateway
    {STREAM_HANDSHAKE_PARENT_BUSY_TRY_LATER, "BUSY TRY LATER", 503}, // Service Unavailable
    {STREAM_HANDSHAKE_PARENT_INTERNAL_ERROR, "INTERNAL ERROR", 500}, // Internal Server Error
    {STREAM_HANDSHAKE_PARENT_IS_INITIALIZING, "REMOTE IS INITIALIZING", 102}, // Processing (WebDAV)

    // receiver-only codes
    {STREAM_HANDSHAKE_RCV_DISCONNECT_PARSER_FAILED, "DISCONNECTED PARSE ERROR", 400}, // Bad Request
    {STREAM_HANDSHAKE_RCV_DISCONNECT_STALE_RECEIVER, "DISCONNECTED STALE RECEIVER", 410}, // Gone
    {STREAM_HANDSHAKE_RCV_DECOMPRESSION_FAILED, "DISCONNECTED DECOMPRESSION FAILED", 415}, // Unsupported Media Type

    // sender-only codes
    {STREAM_HANDSHAKE_SND_DISCONNECT_HOST_CLEANUP, "DISCONNECTED HOST CLEANUP", 202}, // Accepted
    {STREAM_HANDSHAKE_SND_DISCONNECT_COMPRESSION_FAILED, "DISCONNECTED SND COMPRESSION FAILED", 415}, // Unsupported Media Type
    {STREAM_HANDSHAKE_SND_DISCONNECT_HTTP_UPGRADE_FAILED, "HTTP UPGRADE ERROR", 426}, // Upgrade Required
    {STREAM_HANDSHAKE_SND_DISCONNECT_RECEIVER_LEFT, "RECEIVER LEFT", 498},

    // receiver and sender codes
    {STREAM_HANDSHAKE_DISCONNECT_SIGNALED_TO_STOP, "DISCONNECTED SIGNALED TO STOP", 499}, // Client Closed Request
    {STREAM_HANDSHAKE_DISCONNECT_SHUTDOWN, "DISCONNECTED SHUTDOWN REQUESTED", 503}, // Service Unavailable
    {STREAM_HANDSHAKE_DISCONNECT_SOCKET_READ_FAILED, "DISCONNECTED SOCKET READ FAILED", 502}, // Bad Gateway
    {STREAM_HANDSHAKE_DISCONNECT_SOCKET_WRITE_FAILED, "DISCONNECTED SOCKET WRITE FAILED", 502}, // Bad Gateway
    {STREAM_HANDSHAKE_DISCONNECT_SOCKET_ERROR, "DISCONNECT SOCKET ERROR", 500}, // Internal Server Error
    {STREAM_HANDSHAKE_DISCONNECT_TIMEOUT, "DISCONNECTED TIMEOUT", 504}, // Gateway Timeout
    {STREAM_HANDSHAKE_DISCONNECT_SOCKET_CLOSED_BY_REMOTE, "DISCONNECTED SOCKET CLOSED BY REMOTE END", 499}, // Client Closed Request
    {STREAM_HANDSHAKE_DISCONNECT_BUFFER_OVERFLOW, "DISCONNECTED NOT SUFFICIENT SEND BUFFER", 413}, // Payload Too Large
    {STREAM_HANDSHAKE_DISCONNECT_REPLICATION_STALLED, "REPLICATION STALLED", 507}, // Insufficient Storage

    // sender (stream parents - SP) failures to connect
    {STREAM_HANDSHAKE_SP_PREPARING, "PREPARING", 102}, // Processing (WebDAV)
    {STREAM_HANDSHAKE_SP_NO_HOST_IN_DESTINATION, "NO HOST IN DESTINATION - CONFIG ERROR", 404}, // Not Found
    {STREAM_HANDSHAKE_SP_CONNECT_TIMEOUT, "CONNECT TIMEOUT", 408}, // Request Timeout
    {STREAM_HANDSHAKE_SP_CONNECTION_REFUSED, "CONNECTION REFUSED", 403}, // Forbidden
    {STREAM_HANDSHAKE_SP_CANT_RESOLVE_HOSTNAME, "CANT RESOLVE HOSTNAME", 400}, // Bad Request
    {STREAM_HANDSHAKE_SP_CONNECTING, "CONNECTING", 102}, // Processing (WebDAV)
    {STREAM_HANDSHAKE_SP_CONNECTED, "SOCKET CONNECTED", 200}, // OK
    {STREAM_HANDSHAKE_SP_NO_STREAM_INFO, "NO STREAM INFO", 404}, // Not Found
    {STREAM_HANDSHAKE_SP_NO_DESTINATION, "NO PARENT TO SEND TO", 502}, // Bad Gateway

    { 0, NULL, 0 },
};

const char *stream_handshake_error_to_string(STREAM_HANDSHAKE reason) {
    if(reason >= STREAM_HANDSHAKE_OK_V1)
        // handshake_error is the whole version / capabilities number
        return "CONNECTED";

    for(size_t i = 0; handshake_errors[i].str ; i++) {
        if(reason == handshake_errors[i].err)
            return handshake_errors[i].str;
    }

    return "UNKNOWN";
}

int stream_handshake_error_to_response_code(STREAM_HANDSHAKE reason) {
    if(reason >= STREAM_HANDSHAKE_OK_V1)
        // handshake_error is the whole version / capabilities number
        return 200;

    for(size_t i = 0; handshake_errors[i].str ; i++) {
        if(reason == handshake_errors[i].err)
            return handshake_errors[i].response_code;
    }

    return 404;
}
