#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdbool.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/wait.h>
#include "dshlib.h"

/* Function to execute built-in commands */
Built_In_Cmds exec_built_in_cmd(cmd_buff_t *cmd) {
    if (strcmp(cmd->argv[0], "exit") == 0) {
        exit(0);
    } 
    else if (strcmp(cmd->argv[0], "cd") == 0) {
        if (cmd->argc == 1) { 
            // If no argument, change to home directory
            const char *home = getenv("HOME");
            if (home) {
                if (chdir(home) != 0) {
                    perror("cd");
                }
            }
        } 
        else {
            if (chdir(cmd->argv[1]) != 0) {
                perror("cd");
            }
        }
        return BI_EXECUTED;
    }
    else if (strcmp(cmd->argv[0], "echo") == 0) {
        for (int i = 1; i < cmd->argc; i++) {
            // Remove surrounding quotes if present
            char *arg = cmd->argv[i];
            if (arg[0] == '"' && arg[strlen(arg) - 1] == '"') {
                arg[strlen(arg) - 1] = '\0'; // Remove trailing quote
                printf("%s", arg + 1); // Print without leading quote
            } else {
                printf("%s", arg);
            }
            if (i < cmd->argc - 1) printf(" ");
        }
        printf("\n");
        return BI_EXECUTED;
    }
    
    return BI_NOT_BI;
}

/* Function to execute external commands */
int exec_cmd(cmd_buff_t *cmd) {
    pid_t pid = fork();
    
    if (pid < 0) {
        perror("Fork failed");
        return ERR_EXEC_CMD;
    } 
    else if (pid == 0) {
        if (execvp(cmd->argv[0], cmd->argv) == -1) {
            perror("Command execution failed");
            exit(EXIT_FAILURE);
        }
    } 
    else { 
        int status;
        waitpid(pid, &status, 0);
    }
    return OK;
}

/* Function to parse user input into cmd_buff_t */
int build_cmd_buff(char *cmd_line, cmd_buff_t *cmd) {
    cmd->argc = 0;
    cmd->_cmd_buffer = strdup(cmd_line);
    
    if (!cmd->_cmd_buffer) {
        return ERR_MEMORY;
    }

    char *token = strtok(cmd->_cmd_buffer, " ");
    while (token != NULL) {
        cmd->argv[cmd->argc++] = token;
        token = strtok(NULL, " ");
    }
    cmd->argv[cmd->argc] = NULL; // Null-terminate the argument list

    return OK;
}

/* Main shell loop */
int exec_local_cmd_loop() {
    char input_buffer[SH_CMD_MAX];
    cmd_buff_t cmd;

    while (1) {
        printf("%s", SH_PROMPT);
        if (fgets(input_buffer, sizeof(input_buffer), stdin) == NULL) {
            printf("\n");
            break;
        }

        // Remove trailing newline
        input_buffer[strcspn(input_buffer, "\n")] = '\0';

        // Ignore empty input
        if (strlen(input_buffer) == 0) {
            continue;
        }

        if (build_cmd_buff(input_buffer, &cmd) != OK) {
            fprintf(stderr, "Error: command buffer allocation failed\n");
            continue;
        }

        // Check if built-in command
        if (exec_built_in_cmd(&cmd) == BI_NOT_BI) {
            exec_cmd(&cmd);
        }

        free(cmd._cmd_buffer); // Free allocated memory
    }
    return OK;
}