#include "myCmd.h"
#include "myBase.h"
#include <vector>
#include <cstring>
#include <cstdio>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <termios.h>
#include <ctype.h>
#include <errno.h>
#include <signal.h>  // 加这个

// 修复 write 警告
#define SAFE_WRITE(fd, buf, sz) do { (void)write(fd, buf, sz); } while(0)

// 静态 vector：所有命令自动存在这里
static std::vector<stru_cmd>& get_cmd_list()
{
    static std::vector<stru_cmd> s_cmd_list;
    return s_cmd_list;
}

void cmd_manager_add_command(const char *name, void (*func)(int argc, char *argv[]), const char *desc)
{
    if(NULL == name || NULL == func || NULL == desc)
    {
        return;
    }

    auto& s_cmd_list = get_cmd_list();
    s_cmd_list.push_back({
        .name = name,
        .func = func,
        .desc = desc,
    });
}

// 获取最终命令表
stru_cmd *cmd_manager_get_commands(unsigned int *out_count)
{
    auto& s_cmd_list = get_cmd_list();

    if (out_count)
        *out_count = s_cmd_list.size();

    if (s_cmd_list.empty())
    {
        return NULL;
    }

    return s_cmd_list.data();
}

static char *linenoiseHistory[100];
static int linenoiseHistoryLen = 0;
static void (*completionCallback)(const char *, char ***, int *) = NULL;

static struct termios orig_termios;
static int rawModeEnabled = 0;

static void disableRawMode();

// Ctrl+C 信号处理
static void handleSigInt(int sig)
{
    if (rawModeEnabled) {
        disableRawMode();
        rawModeEnabled = 0;
    }
    printf("\n");
    exit(0);
}

static void disableRawMode() {
    if (!rawModeEnabled) return;
    tcsetattr(STDIN_FILENO, TCSAFLUSH, &orig_termios);
    rawModeEnabled = 0;
}

static int enableRawMode() {
    signal(SIGINT, handleSigInt);  // 绑定 Ctrl+C

    tcgetattr(STDIN_FILENO, &orig_termios);
    atexit(disableRawMode);
    struct termios raw = orig_termios;
    raw.c_lflag &= ~(ECHO | ICANON);
    // 这里不再关闭 ISIG → Ctrl+C 有效
    raw.c_cc[VMIN] = 1;
    raw.c_cc[VTIME] = 0;

    int ret = tcsetattr(STDIN_FILENO, TCSAFLUSH, &raw);
    if (ret == 0) rawModeEnabled = 1;
    return ret;
}

static int linenoiseEdit(char *buf, int bufsize, const char *prompt) {
    int pos = 0, len = 0;
    char c;
    memset(buf, 0, bufsize);
    SAFE_WRITE(STDOUT_FILENO, prompt, strlen(prompt));

    int history_idx = linenoiseHistoryLen;

    while (1) {
        if (read(STDIN_FILENO, &c, 1) == -1) return -1;

        if (c == '\n' || c == '\r') {
            buf[len] = 0;
            SAFE_WRITE(STDOUT_FILENO, "\n", 1);
            return len;
        }

        if (c == 127 || c == '\b') {
            if (len > 0) {
                len--; pos--;
                buf[len] = 0;
                SAFE_WRITE(STDOUT_FILENO, "\b \b", 3);
                history_idx = linenoiseHistoryLen;
            }
            continue;
        }

        if (c == 27) {
            char seq[2];
            if (read(STDIN_FILENO, &seq[0], 1) == -1) break;
            if (read(STDIN_FILENO, &seq[1], 1) == -1) break;

            if (seq[0] == '[') {
                if (seq[1] == 'A') {
                    if (linenoiseHistoryLen == 0) continue;
                    history_idx--;
                    if (history_idx < 0) history_idx = 0;
                    const char *hist = linenoiseHistory[history_idx];
                    strncpy(buf, hist, bufsize - 1);
                    len = pos = strlen(buf);
                    SAFE_WRITE(STDOUT_FILENO, "\r\033[K", 4);
                    SAFE_WRITE(STDOUT_FILENO, prompt, strlen(prompt));
                    SAFE_WRITE(STDOUT_FILENO, buf, len);
                } else if (seq[1] == 'B') {
                    if (linenoiseHistoryLen == 0) continue;
                    history_idx++;
                    if (history_idx >= linenoiseHistoryLen) {
                        history_idx = linenoiseHistoryLen;
                        memset(buf, 0, bufsize);
                        len = pos = 0;
                    } else {
                        const char *hist = linenoiseHistory[history_idx];
                        strncpy(buf, hist, bufsize - 1);
                        len = pos = strlen(buf);
                    }
                    SAFE_WRITE(STDOUT_FILENO, "\r\033[K", 4);
                    SAFE_WRITE(STDOUT_FILENO, prompt, strlen(prompt));
                    SAFE_WRITE(STDOUT_FILENO, buf, len);
                }
            }
            continue;
        }

        if (c == 9) {
            char **completions = NULL;
            int ncomp = 0;
            if (completionCallback) {
                completionCallback(buf, &completions, &ncomp);
                if (ncomp > 0) {
                    strncpy(buf, completions[0], bufsize - 1);
                    len = pos = strlen(buf);
                    SAFE_WRITE(STDOUT_FILENO, "\r\033[K", 4);
                    SAFE_WRITE(STDOUT_FILENO, prompt, strlen(prompt));
                    SAFE_WRITE(STDOUT_FILENO, buf, len);
                    for (int j = 0; j < ncomp; j++) free(completions[j]);
                    free(completions);
                }
            }
            history_idx = linenoiseHistoryLen;
            continue;
        }

        if (len < bufsize - 1) {
            buf[len++] = c;
            pos++;
            SAFE_WRITE(STDOUT_FILENO, &c, 1);
            history_idx = linenoiseHistoryLen;
        }
    }
    return 0;
}

char *linenoise(const char *prompt) {
    char buf[1024];
    enableRawMode();
    int n = linenoiseEdit(buf, sizeof(buf), prompt);
    disableRawMode();
    if (n <= 0) return NULL;
    char *copy = (char *)malloc(strlen(buf) + 1);
    strcpy(copy, buf);
    return copy;
}

void linenoiseFree(void *ptr) {
    free(ptr);
}

int linenoiseHistoryAdd(const char *line) {
    if (linenoiseHistoryLen >= 100) return 0;
    linenoiseHistory[linenoiseHistoryLen] = (char *)malloc(strlen(line) + 1);
    strcpy(linenoiseHistory[linenoiseHistoryLen], line);
    linenoiseHistoryLen++;
    return 1;
}

void linenoiseHistoryFree(void) {
    for (int j = 0; j < linenoiseHistoryLen; j++)
        free(linenoiseHistory[j]);
}

void lineniseSetCompletionCallback(void (*cb)(const char *, char ***, int *)) {
    completionCallback = cb;
}

stru_cmd *cmd_find(const char *name)
{
    auto& s_cmd_list = get_cmd_list();

    for(auto &cmd : s_cmd_list)
    {
        if(0 == strcmp(cmd.name, name))
        {
            return &cmd;
        }
    }

    return NULL;
}

void cmd_complete(const char *buf, char ***completions, int *ncomp)
{
    int cnt = 0;
    char **c = NULL;
    auto& s_cmd_list = get_cmd_list();

    for(auto &cmd : s_cmd_list)
    {
        if(!strncmp(cmd.name, buf, strlen(buf)))
        {
            if(NULL == c)
            {
                c = (char **)malloc(sizeof(char *) * (s_cmd_list.size() + 1));
            }
            c[cnt] = (char *)malloc(strlen(cmd.name) + 1);
            strcpy(c[cnt], cmd.name);
            cnt++;
        }
    }

    if(NULL == c)
    {
        *ncomp = 0;
        *completions = NULL;
    }
    else
    {
        *ncomp = cnt;
        *completions = c;
    }
}

void cmd_help(int argc, char *argv[])
{
    auto& s_cmd_list = get_cmd_list();

    for(auto &cmd : s_cmd_list)
    {
        printf("%s [%s]\n", cmd.name, cmd.desc);
    }
}

CMD_REGISTER("help", cmd_help, "显示所有命令");