// Kyler Olsen
// YREA SLS
// REPL
// November 2025

#include <stddef.h>
#include <stdio.h>
#include <string.h>

#include "sls/repl.h"
#include "sls/meta.h"
#include "sls/errors.h"
#include "sls/lexer.h"
#include "sls/string.h"
#include "sls/interpreter.h"

static const SlsStr REPL_FILE_NAME = SLS_STR_CONST("<STDIN>");

void print_top_of_stack(InterpreterState *interpreter_state) {
    if (interpreter_state->stack == NULL) {
        printf("#0: <STACK IS EMPTY>\n");
        return;
    }
    switch (interpreter_state->stack->type) {
    case STACK_IDENTIFIER:
        printf("#0: ::%s\n", interpreter_state->stack->identifier.name.str);
        break;
    case STACK_I64:
        printf("#0: %ld\n", interpreter_state->stack->i64);
        break;
    case STACK_I32:
        printf("#0: %d:i32\n", interpreter_state->stack->i32);
        break;
    case STACK_I16:
        printf("#0: %d:i16\n", interpreter_state->stack->i16);
        break;
    case STACK_I8:
        printf("#0: %d:8\n", interpreter_state->stack->i8);
        break;
    case STACK_U64:
        printf("#0: %lu:u64\n", interpreter_state->stack->u64);
        break;
    case STACK_U32:
        printf("#0: %u:32\n", interpreter_state->stack->u32);
        break;
    case STACK_U16:
        printf("#0: %u:16\n", interpreter_state->stack->u16);
        break;
    case STACK_U8:
        printf("#0: %u:8\n", interpreter_state->stack->u8);
        break;
    case STACK_FLOAT:
        printf("#0: %f:f32\n", interpreter_state->stack->f32);
        break;
    case STACK_DOUBLE:
        printf("#0: %f\n", interpreter_state->stack->f64);
        break;
    case STACK_CHARACTER:
        printf("#0: %c\n", interpreter_state->stack->character);
        break;
    case STACK_BOOLEAN:
        if (interpreter_state->stack->boolean) printf("#0: TRUE\n");
        else printf("#0: FALSE\n");
        break;
    case STACK_TOKEN_STRING:
        printf("#0: <TOKEN STRING>\n");
        break;
    case STACK_CALLABLE:
        printf("#0: <CALLABLE>\n");
        break;
    }
}

int repl() {
    print_version();
    printf("===== YREA SLS REPL =====\n");
    printf("Type `#exit` to exit.\n");
    fflush(stdout);

    LexerInfo lexer_info;
    InterpreterState *interpreter_state = interpreter_create();
    if (interpreter_state == NULL) return 1;
    char buf[256];
    while (fgets(buf, sizeof(buf), stdin)) {
        size_t len = strlen(buf);
        if (len && buf[len - 1] == '\n') buf[len - 1] = '\0';
        if (strncmp(buf, "#exit", 5) == 0) {
            interpreter_delete(interpreter_state);
            return 0;
        }

        SlsStr code = sls_str_malloc(buf, sizeof(buf));
        init_lexer(&lexer_info, REPL_FILE_NAME, code);
        LexerResult result = lexical_analysis(&lexer_info);
        if (result.type == SLS_ERROR) {
            printf("%s\n", result.error.message.str);
            sls_str_free(&result.error.message);
        } else {
            LexerTokenResult *head = result.result;
            while (head) {
                if (head->type == SLS_ERROR) {
                    printf("%s\n", head->error.message.str);
                    break;
                } else if (!execute(interpreter_state, head)) {
                    printf("A runtime error occurred!\n");
                    break;
                }
                head = head->next;
            }
            clean_token_result(result.result);
            print_top_of_stack(interpreter_state);
        }
        sls_str_free(&code);
    }

    interpreter_delete(interpreter_state);
    return 1;
}
