/*
 * face_uart.c — UART Command Interface for Face Animations
 *
 * Receives emotion commands from Jetson Orin and triggers face animations.
 * Text-based protocol over USART3 @ 115200 baud.
 */

#include "face_uart.h"
#include "face_animation.h"
#include <string.h>
#include <ctype.h>
#include <stdio.h>

/* === Ring Buffer State === */
static struct {
    uint8_t buf[FACE_UART_RX_BUF_SZ];
    uint16_t head;              /* Write index (ISR) */
    uint16_t tail;              /* Read index (process) */
    uint16_t count;             /* Bytes in buffer */
} rx_buf = {0};

/* === Forward Declarations === */
static void uart_send_response(const char *cmd, const char *status);

/* === Private Functions === */

/**
 * Extract a line from RX buffer (newline-terminated).
 * Returns length if found, 0 otherwise.
 */
static uint16_t extract_line(char *line, uint16_t max_len) {
    uint16_t len = 0;
    uint16_t idx = rx_buf.tail;

    /* Scan for newline */
    while (idx != rx_buf.head && len < max_len - 1) {
        uint8_t byte = rx_buf.buf[idx];
        if (byte == '\n') {
            /* Found end of line */
            for (uint16_t i = 0; i < len; i++) {
                line[i] = rx_buf.buf[(rx_buf.tail + i) % FACE_UART_RX_BUF_SZ];
            }
            line[len] = '\0';

            /* Trim trailing whitespace */
            while (len > 0 && (line[len - 1] == '\r' || isspace(line[len - 1]))) {
                line[--len] = '\0';
            }

            /* Update tail and count */
            rx_buf.tail = (idx + 1) % FACE_UART_RX_BUF_SZ;
            rx_buf.count -= (len + 1 + 1);  /* +1 for newline, +1 for any preceding data */

            return len;
        }

        len++;
        idx = (idx + 1) % FACE_UART_RX_BUF_SZ;
    }

    return 0;  /* No complete line */
}

/**
 * Convert string to uppercase for case-insensitive command matching.
 */
static void str_toupper(char *str) {
    for (int i = 0; str[i]; i++)
        str[i] = toupper((unsigned char)str[i]);
}

/**
 * Parse and execute a command.
 */
static void parse_command(const char *cmd) {
    if (!cmd || !cmd[0])
        return;

    char cmd_upper[32];
    strncpy(cmd_upper, cmd, sizeof(cmd_upper) - 1);
    cmd_upper[sizeof(cmd_upper) - 1] = '\0';
    str_toupper(cmd_upper);

    /* Command dispatch */
    if (strcmp(cmd_upper, "HAPPY") == 0) {
        face_animation_set_emotion(FACE_HAPPY);
        uart_send_response(cmd_upper, "OK");
    } else if (strcmp(cmd_upper, "SAD") == 0) {
        face_animation_set_emotion(FACE_SAD);
        uart_send_response(cmd_upper, "OK");
    } else if (strcmp(cmd_upper, "CURIOUS") == 0) {
        face_animation_set_emotion(FACE_CURIOUS);
        uart_send_response(cmd_upper, "OK");
    } else if (strcmp(cmd_upper, "ANGRY") == 0) {
        face_animation_set_emotion(FACE_ANGRY);
        uart_send_response(cmd_upper, "OK");
    } else if (strcmp(cmd_upper, "SLEEP") == 0 ||
               strcmp(cmd_upper, "SLEEPING") == 0) {
        face_animation_set_emotion(FACE_SLEEPING);
        uart_send_response(cmd_upper, "OK");
    } else if (strcmp(cmd_upper, "NEUTRAL") == 0) {
        face_animation_set_emotion(FACE_NEUTRAL);
        uart_send_response(cmd_upper, "OK");
    } else if (strcmp(cmd_upper, "BLINK") == 0) {
        face_animation_blink_now();
        uart_send_response(cmd_upper, "OK");
    } else if (strcmp(cmd_upper, "STATUS") == 0) {
        const char *emotion_names[] = {"HAPPY", "SAD", "CURIOUS", "ANGRY",
                                       "SLEEPING", "NEUTRAL"};
        face_emotion_t current = face_animation_get_emotion();
        char status[64];
        snprintf(status, sizeof(status), "EMOTION=%s, IDLE=%s",
                 emotion_names[current],
                 face_animation_is_idle() ? "true" : "false");
        uart_send_response(cmd_upper, status);
    } else {
        uart_send_response(cmd_upper, "ERR: unknown command");
    }
}

/**
 * Send a response string to UART TX.
 * Format: "CMD: status\n"
 */
static void uart_send_response(const char *cmd, const char *status) {
    /* TODO: Implement UART TX
     * Use HAL_UART_Transmit_IT or similar to send:
     *   "CMD: status\n"
     */
    (void)cmd;      /* Suppress unused warnings */
    (void)status;
}

/* === Public API Implementation === */

void face_uart_init(void) {
    /* TODO: Configure USART3 @ 115200 baud
     * - Enable USART3 clock (RCC_APB1ENR)
     * - Configure pins (PB10=TX, PB11=RX)
     * - Set baud rate to 115200
     * - Enable RX interrupt (NVIC + USART3_IRQn)
     * - Enable USART
     */

    rx_buf.head = 0;
    rx_buf.tail = 0;
    rx_buf.count = 0;
}

void face_uart_process(void) {
    char line[128];
    uint16_t len;

    /* Extract and process complete commands */
    while ((len = extract_line(line, sizeof(line))) > 0) {
        parse_command(line);
    }
}

void face_uart_rx_isr(uint8_t byte) {
    /* Push byte into ring buffer */
    if (rx_buf.count < FACE_UART_RX_BUF_SZ) {
        rx_buf.buf[rx_buf.head] = byte;
        rx_buf.head = (rx_buf.head + 1) % FACE_UART_RX_BUF_SZ;
        rx_buf.count++;
    }
    /* Buffer overflow: silently discard oldest byte */
}

void face_uart_send(const char *str) {
    /* TODO: Implement non-blocking UART TX
     * Use HAL_UART_Transmit_IT() or DMA-based TX queue.
     */
    (void)str;  /* Suppress unused warnings */
}
