/* protocol.c - Implementasi parser protokol */
#include "protocol.h"

#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <time.h>

static int eq_ci(const char *a, const char *b) {
    while (*a != '\0' && *b != '\0') {
        if (toupper((unsigned char)*a) != toupper((unsigned char)*b)) {
            return 0;
        }
        a++;
        b++;
    }
    return *a == '\0' && *b == '\0';
}

const char *proto_command_name(proto_command cmd) {
    switch (cmd) {
        case PROTO_CMD_PING:    return "PING";
        case PROTO_CMD_ECHO:    return "ECHO";
        case PROTO_CMD_UPPER:   return "UPPER";
        case PROTO_CMD_LOWER:   return "LOWER";
        case PROTO_CMD_TIME:    return "TIME";
        case PROTO_CMD_STATS:   return "STATS";
        case PROTO_CMD_QUIT:    return "QUIT";
        case PROTO_CMD_UNKNOWN:
        default:                return "UNKNOWN";
    }
}

int proto_parse_line(const char *line, proto_message *msg) {
    if (line == NULL || msg == NULL) {
        return -1;
    }
    /* Lewati whitespace di awal. */
    while (*line == ' ' || *line == '\t') {
        line++;
    }
    if (*line == '\0' || *line == '\n' || *line == '\r') {
        return -1;
    }
    /* Ekstrak command word pertama. */
    char cmd_buf[PROTO_COMMAND_MAX];
    int consumed = 0;
    if (sscanf(line, "%15s%n", cmd_buf, &consumed) != 1) {
        return -1;
    }
    if (eq_ci(cmd_buf, "PING")) {
        msg->command = PROTO_CMD_PING;
    } else if (eq_ci(cmd_buf, "ECHO")) {
        msg->command = PROTO_CMD_ECHO;
    } else if (eq_ci(cmd_buf, "UPPER")) {
        msg->command = PROTO_CMD_UPPER;
    } else if (eq_ci(cmd_buf, "LOWER")) {
        msg->command = PROTO_CMD_LOWER;
    } else if (eq_ci(cmd_buf, "TIME")) {
        msg->command = PROTO_CMD_TIME;
    } else if (eq_ci(cmd_buf, "STATS")) {
        msg->command = PROTO_CMD_STATS;
    } else if (eq_ci(cmd_buf, "QUIT") || eq_ci(cmd_buf, "EXIT")) {
        msg->command = PROTO_CMD_QUIT;
    } else {
        msg->command = PROTO_CMD_UNKNOWN;
    }
    /* Salin sisa argumen, lewati satu spasi setelah command word. */
    const char *args_start = line + consumed;
    while (*args_start == ' ' || *args_start == '\t') {
        args_start++;
    }
    strncpy(msg->args, args_start, PROTO_LINE_MAX - 1);
    msg->args[PROTO_LINE_MAX - 1] = '\0';
    /* Hapus newline di akhir. */
    size_t len = strlen(msg->args);
    while (len > 0 && (msg->args[len - 1] == '\n' ||
                       msg->args[len - 1] == '\r')) {
        msg->args[--len] = '\0';
    }
    msg->args_len = len;
    return 0;
}

int proto_build_reply(char *out, size_t out_cap,
                      proto_reply code, const char *text) {
    if (out == NULL || out_cap < 8) {
        return -1;
    }
    const char *body = (text != NULL) ? text : "";
    int n = snprintf(out, out_cap, "%d %s\n", (int)code, body);
    if (n < 0 || (size_t)n >= out_cap) {
        return -1;
    }
    return n;
}
