/*
    Test:
        curl -X POST http://localhost:3000 \
        -H "Content-Type: application/json" \
        -d '{"x":123}'
*/

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <string.h>


#define PORT 3000
#define BUFFER_SIZE 4096

static const char ok_header[] =
"HTTP/1.1 200 OK\r\n"
"Content-Type: application/json\r\n"
"Connection: close\r\n"
"\r\n";

static const char bad_request[] =
"HTTP/1.1 400 Bad Request\r\n"
"Content-Type: application/json\r\n"
"Connection: close\r\n"
"\r\n"
"{\"ok\":false}";


static char request_buffer[BUFFER_SIZE];
static char response_buffer[BUFFER_SIZE];


static void append(char *dst, const char *src) {
    while (*dst) dst++;

    while (*src){
        *dst = *src;
        dst++;
        src++;
    }

    *dst = 0;
}

int main(void){
    int server_fd;
    int client_fd;
    int received;

    struct sockaddr_in addr;

    server_fd = socket(AF_INET, SOCK_STREAM, 0);

    if (server_fd < 0) return 1;

    memset(&addr, 0, sizeof(addr));

    addr.sin_family = AF_INET;
    addr.sin_port = htons(PORT);
    addr.sin_addr.s_addr = htonl(INADDR_ANY);

    if (bind(server_fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) return 1;

    if (listen(server_fd, 4) < 0) return 1;

    for (;;){
        client_fd = accept(server_fd, 0, 0);

        if (client_fd < 0) continue;

        memset(request_buffer, 0, BUFFER_SIZE);

        received = read(client_fd, request_buffer, BUFFER_SIZE - 1);

        if (received <= 0){
            close(client_fd);
            continue;
        }

        char *body = NULL;
        char *ptr = request_buffer;

        while (*ptr) {
            if (ptr[0] == '\r' && ptr[1] == '\n' &&
                ptr[2] == '\r' && ptr[3] == '\n') {
                body = ptr + 4;
                break;
            }
            ptr++;
        }

        if (body){
            memset(response_buffer, 0, BUFFER_SIZE);

            append(response_buffer, ok_header);
            append(response_buffer, "{\"ok\":true,\"data\":");
            append(response_buffer, body);
            append(response_buffer, "}");

            write(client_fd, response_buffer, strlen(response_buffer));
        }
        else write(client_fd, bad_request, sizeof(bad_request) - 1);
        close(client_fd);
    }

    return 0;
}