#include "cli_inter_actor.h"
#include "cli.h"
#include "cli_inter_preter.h"
#include <stdarg.h>
#include <stdio.h>
#include <sys/_types.h>

#define CLI_ITT_ANSI_ENABLE O

static char          cli_itt_list[CLI_ITT_LIST_NUM][CLI_ITT_LIST_LEN] = {0};
static char          cli_itt_list_hint_index = 0, cli_itt_list_his_cnt = 0;
static unsigned char cli_itt_list_index = 0;
unsigned char        g_cli_chl          = CLI_CHL_COM;

void eoch(char c)
{
    if (g_cli_chl == CLI_CHL_COM)
        CLI_PRINTF("%c", c);
}

void cli_itt_list_add(unsigned char *item)
{
    strcpy(cli_itt_list[cli_itt_list_index], (const char *)item);
    cli_itt_list_index = (cli_itt_list_index + 1) % CLI_ITT_LIST_NUM;
    cli_itt_list_his_cnt++;
    if (cli_itt_list_his_cnt >= CLI_ITT_LIST_NUM)
        cli_itt_list_his_cnt = CLI_ITT_LIST_NUM;
}

unsigned char diff_num(unsigned char a, unsigned char b)
{
    return a > b ? a - b : b - a;
}

unsigned char cli_itt_list_index_last(void)
{
    unsigned char index;
    index = (cli_itt_list_hint_index + CLI_ITT_LIST_NUM - 1) % CLI_ITT_LIST_NUM;

    if ((index != cli_itt_list_index) && (diff_num(cli_itt_list_hint_index, cli_itt_list_index) < cli_itt_list_his_cnt))
    {
        cli_itt_list_hint_index = index;
    }
    return cli_itt_list_hint_index;
}

unsigned char cli_itt_list_index_next(void)
{
    unsigned char index;
    index = (cli_itt_list_hint_index + 1) % CLI_ITT_LIST_NUM;

    if ((index != cli_itt_list_index) && (diff_num(cli_itt_list_hint_index, cli_itt_list_index) < cli_itt_list_his_cnt))
    {
        cli_itt_list_hint_index = index;
    }
    else
    {
        // cli_itt_list_hint_index = cli_itt_list_index;
    }
    return cli_itt_list_hint_index;
}

void clear_line(void)
{
    CLI_PRINTF("\r");
    for (char i = 0; i < CLI_ITT_LIST_LEN; i++)
    {
        CLI_PRINTF(" ");
    }
    CLI_PRINTF("\r");
}

void clear_line_ansi(unsigned int cursor)
{
    CLI_PRINTF("%c[%dD", '\033', cursor);
    CLI_PRINTF("%c[K", '\033');
}

void cli_printf(char *msg, ...)
{
    va_list vl;
    // char    s[10];
    if (g_cli_chl == CLI_CHL_COM)
    {
        va_start(vl, msg);
        // vsprintf(s, msg, vl);
        vprintf(msg, vl);
        va_end(vl);
    }
    else
    {
#ifdef TELNET
        va_start(vl, msg);
        telnet_esp32_vprintf(msg, vl);
        va_end(vl);
#endif
    }
}

void cli_itt_input(CLI_CHL chl, char c)
{
    // static unsigned char enter = 0;
    static unsigned char dir = 0, ch;
    static char          item[CLI_ITT_LIST_LEN];
    static unsigned char item_index = 0;
    int                  res;
    char                 hint[CLI_ITT_LIST_LEN];

    ch = (unsigned char)c;
    // CLI_PRINTF("%02x", ch);
    // return;

    switch (ch)
    {
    case '\r':
#define OS_MAC
#ifdef OS_MAC:
        item[item_index] = '\0';
        if (g_cli_chl == CLI_CHL_COM)
            CLI_PRINTF("\r\n");
        if (strlen(item) != 0)
        {
            cli_itt_list_add((unsigned char *)item);
            cli_itt_list_hint_index = cli_itt_list_index;
        }
        command_entry_match(main_table, item);
        memset(item, 0, CLI_ITT_LIST_LEN);
        // emter = 0;
        item_index = 0;
        break;
#else
        // enter = 1;
        return;
#endif
    case '\n':
        item[item_index] = '\0';
        if (g_cli_chl == CLI_CHL_COM)
            CLI_PRINTF("\r\n");
        if (strlen(item) != 0)
        {
            cli_itt_list_add((unsigned char *)item);
            cli_itt_list_hint_index = cli_itt_list_index;
        }
        command_entry_match(main_table, item);
        memset(item, 0, CLI_ITT_LIST_LEN);
        // emter = 0;
        item_index = 0;
        break;
    case '\t': // Tab
        res = command_entry_hint(main_table, item, hint);
        if (res == 0)
        {
        }
        else if (res == 1)
        {
            CLI_PRINTF("\r\n%s\r\n# %s", hint, item);
        }
        else if (res == 2)
        {
#if CLI_ITT_ANSI_ENABLE == 0
            clear_line();
#else
            clear_line_ansi(item_index);
#endif
            CLI_PRINTF("\r# %s", hint);
            strcpy(item, hint);
            item_index = strlen(item);
        }
        else if (res == 3)
        {
#if CLI_ITT_ANSI_ENABLE == 0
            clear_line();
#else
            clear_line_ansi(item_index);
#endif
            CLI_PRINTF("\r# %s", hint);
            strcpy(item, hint);
            item_index = strlen(item);
        }
        else
        {
        }
        break;
    case 0x1b: // ESC/UP-1
        dir = 1;
        break;
    case 0x5b:
        dir = 2;
        break;
    // case 0x1b: // ESC
    //     memcpy(item, 0, sizeof(item));
    //     item_index = 0;
    //     CLI_PRINTF("\r%s", item);
    //     break;
    case 8: // BackSpace
        if (item_index > 0)
        {
            item_index--;
#if CLI_ITT_ANSI_ENABLE == 1
            CLI_PRINTF("%c[1D", '\033');
            CLI_PRINTF("%c[K", '\033');
#endif
            item[item_index] = '\0';
#if CLI_ITT_ANSI_ENABLE == 0
            clear_line();
            CLI_PRINTF("\r# %s", item);
#endif
            break;
        }
    default:
        if ((ch == 0x41 || ch == 0x42) && (dir == 2))
        {
            if (ch == 0x41) // UP
            {
                strcpy(item, cli_itt_list[cli_itt_list_index_last()]);
            }
            else // DOWN
            {
                if (cli_itt_list_hint_index == cli_itt_list_index)
                {
                }
                else if (((cli_itt_list_hint_index + CLI_ITT_LIST_NUM + 1) % CLI_ITT_LIST_NUM) == cli_itt_list_index)
                {
                    cli_itt_list_hint_index = cli_itt_list_index;
                    memset(item, 0, CLI_ITT_LIST_NUM);
                }
                else
                {
                    strcpy(item, cli_itt_list[cli_itt_list_index_next()]);
                }
            }

#if CLI_ITT_ANSI_ENABLE == 1
            clear_line_ansi(item_index);
#endif
            item_index = strlen(item);
#if CLI_ITT_ANSI_ENABLE == 0
            clear_line();
#endif
            CLI_PRINTF("\r# %s", item);
            dir = 0;
            break;
        }

        if ((ch == 0x43 || ch == 0x44) && (dir == 2))
        {
            break;
        }

        eoch(c);

        if (item_index <= (CLI_ITT_LIST_LEN - 2))
        {
            item[item_index++] = c;
        }
        break;
    }
}