#include "print.h"
#include "keydriver.h"
#include "stdint.h"
#include "stdopt.h"
#include "strings.h"
#include "io.h"
#include "vga.h"
#include "idt.h"
#include "memory.h"
#include "window.h"
#include "fs.h"
#include "fat12.h"
#include "basic.h"

#define COMMAND_BUFFER_SIZE 256 // Increase buffer size to handle longer commands
#define BACKSPACE_KEY 8
#define HISTORY_SIZE 10
#define COMMAND_BUFFER_SIZE 256
#define BUFFER_SIZE 4096

extern void kpanic(int error_code);

void shutdown_system()
{
    __asm__(
        "movl $1, %eax\n" // syscall number for sys_reboot (1 in this case)
        "movl $0, %ebx\n" // reboot flags
        "movl $0, %ecx\n" // no additional arguments
        "movl $0, %edx\n" // no additional arguments
        "int $0x80\n"     // interrupt to invoke syscall
    );
}

char commandHistory[HISTORY_SIZE][COMMAND_BUFFER_SIZE];
int currentHistoryIndex = 0;
int historyCount = 0;

void add_to_history(const char *command)
{
    if (historyCount < HISTORY_SIZE)
    {
        historyCount++;
    }
    else
    {
        for (int i = 1; i < HISTORY_SIZE; i++)
        {
            strcpy(commandHistory[i - 1], commandHistory[i]);
        }
    }
    strcpy(commandHistory[historyCount - 1], command);
    currentHistoryIndex = historyCount;
}

const char *get_previous_command()
{
    if (currentHistoryIndex > 0)
    {
        currentHistoryIndex--;
        return commandHistory[currentHistoryIndex];
    }
    return NULL;
}

const char *get_next_command()
{
    if (currentHistoryIndex < historyCount - 1)
    {
        currentHistoryIndex++;
        return commandHistory[currentHistoryIndex];
    }
    return NULL;
}

const void clear()
{
    print_set_color(PRINT_COLOR_WHITE, PRINT_COLOR_BLACK); // Set text color

    move_print_cursor(0, 0);
    move_cursor(0, 0);
    print_clear();
    print_setup_prompt();
}

void halt()
{
    print_str("[ WARN ] HALT\n");
    while (1)
    {
    }
}

void commandHandler(char *command)
{
    printf("\n");

    if (strcmp(command, "cls") == 0)
    {
        clear();
    }
    else if (strcmp(command, "knp") == 0)
    {
        kpanic(1);
    }
    else if (int_strncmp(command, "echo ", 5) == 0)
    {
        char *message = command + 5; // Skip the "echo " part
        print_str("\n");
        print_str(message);
        print_str("\n");
    }
    else if (int_strncmp(command, "cwin", 4) == 0)
    {
        // Define window properties
        Window myWindow;
        int x = 8;                                  // X position of the window
        int y = 4;                                  // Y position of the window
        int width = 30;                             // Width of the window
        int height = 10;                            // Height of the window
        uint8_t borderColor = PRINT_COLOR_RED;      // Border color
        uint8_t backgroundColor = PRINT_COLOR_BLUE; // Background color

        // Create and display the window
        create_window(&myWindow, x, y, width, height, borderColor, backgroundColor, "Main Window");

        // Print text inside the window
        print_set_color(PRINT_COLOR_WHITE, PRINT_COLOR_BLUE); // Set text color
        print_text_in_window(&myWindow, 2, 2, "Window Manager is a ");
        print_text_in_window(&myWindow, 2, 3, "Work in progress, Sorry :("); // Print text inside the window
        print_text_in_window(&myWindow, 2, 4, "do [ cls ] to clear");        // Print text inside the window
    }
    else if (int_strncmp(command, "exit", 4) == 0)
    {
        printf("Driver Call [ shutdown_system(); ] \n");
        shutdown_system();
    }
    else if (int_strncmp(command, "panic_test", 10) == 0)
    {
        int _y = 1 / 0;
        printf("Output %d\n", _y);
    }
    else if (int_strncmp(command, "test", 4) == 0)
    {

        //// Test custom malloc and free
        // void* block1 = malloc(32);
        // void* block2 = malloc(64);
        // void* block3 = malloc(128);
        //
        //// List used blocks
        // list_used_blocks();
        //
        //// Free a block and check again
        // free(block2);
        // printf("\nAfter freeing block2:\n");
        // list_used_blocks();
        //
        // void* block4 = malloc(64);
        //
        // list_used_blocks();

        create_game();
    }
    else if (int_strncmp(command, "split", 5) == 0)
    {
        printf("Kernel Call [ split_string(); ]\n");

        // Check the length of the command string and use it properly
        char **new_command = split_string(command, ",", strlen(command));

        // char** new_command = {{NULL, NULL, NULL, NULL}};

        if (new_command)
        {
            // Add a loop to print all the elements in the new_command array for debugging
            for (int i = 0; new_command[i] != NULL; i++)
            {
                printf("new_command[%d]: %s\n", i, new_command[i]);
            }

            // halt();  // Debug halt

            // Ensure that new_command[1] exists before accessing it
            if (new_command[1] != NULL)
            {
                printf("%s\n", new_command[1]);
            }
            else
            {
                printf("Error: new_command[1] is NULL\n");
            }
        }
        else
        {
            printf("Error: split_string returned NULL\n");
        }
    }
    else
    {
        printf("Unknown command: %s\n", command);
    }
}

void print_setup_prompt()
{
    move_cursor(0, 0);
    print_set_color(PRINT_COLOR_LIGHT_RED, PRINT_COLOR_BLACK);
    print_str("-------------------- ");
    print_set_color(PRINT_COLOR_GREEN, PRINT_COLOR_BLACK);
    print_str("EYOS");
    print_set_color(PRINT_COLOR_LIGHT_RED, PRINT_COLOR_BLACK);
    print_str(" --------------------\n");
    print_set_color(PRINT_COLOR_WHITE, PRINT_COLOR_BLACK);
    print_str("V 1.5.01\n");
}

int test_basic()
{
    InterpreterState state;
    init_state(&state);

    const char *program[] = {
        "LET A = 10",
        "LET B = 20",
        "PRINT A + B",
        "LET A = \"Hello\"",
        "LET B = \" World\"",
        "PRINT A + B",
        "END",

    };

    for (size_t i = 0; i < sizeof(program) / sizeof(program[0]); i++)
    {
        execute_line(&state, program[i]);
        if (!state.running)
            break;
    }

    return 0;
}

void kernel_main()
{

    init_keyboard_driver();

    idt_install();

    print_str("[ WARN ] Skipping File System Initialization...\n[ INFO ] Do [ fsinit ] to initalize the filesystem\n");

    if (fat12_init() == 0)
    {
        printf("Filesystem mounted\n");

        fat12_read_root_directory();

        fat12_dir_entry_t entry;
        if (fat12_find_file("HELLOTXT", &entry))
        {
            printf("File found: HELLO.TXT\n");
        }
    }
    clear();

    test_basic();

    print_setup_prompt();

    print_str(" > ");

    // Main loop
    char key;
    bool keydown = false;
    char commandBuffer[COMMAND_BUFFER_SIZE];
    size_t commandLength = 0; // To track the length of the current command

    while (1)
    {
        key = read_key();

        if (key != 0)
        {
            if (!keydown)
            {
                CursorPosition pos = get_print_cursor_pos();
                move_cursor(pos.x, pos.y);
                if (key == 10)
                {                                        // Enter key
                    commandBuffer[commandLength] = '\0'; // Null-terminate the command
                    commandHandler(commandBuffer);

                    // Reset command buffer for the next input
                    commandLength = 0;
                    print_str(" > ");
                }
                else if (key == BACKSPACE_KEY)
                { // Backspace key
                    if (commandLength > 0)
                    {
                        // Remove the last character from the buffer
                        commandLength--;
                        commandBuffer[commandLength] = '0'; // Null-terminate after removal

                        // Clear the character from the screen (overwrite with space)
                        // Move cursor back one position
                        offset_print_cursor(-1, 0);
                        print_char(' ');            // Overwrite the character
                        offset_print_cursor(-1, 0); // Move cursor back one position(because its moved left one by the rpintf)
                    }
                }
                else
                {
                    if (key >= 32 && key <= 126)
                    { // Check if the key is a printable character
                        if (commandLength < COMMAND_BUFFER_SIZE - 1)
                        {
                            commandBuffer[commandLength++] = key; // Append character to buffer
                            commandBuffer[commandLength] = '\0';  // Null-terminate the buffer
                            print_char(key);                      // Print key to the screen
                        }
                    }
                }
                keydown = true;
            }
        }
        else
        {
            keydown = false;
        }

        // int x = 100/0;
    }

    kpanic(2);
}
