use std::io::{self, Write};
use std::fs;
use serde_json;

use crate::lexer::{LexerInfo, LexResult, lexical_analysis};
use crate::print_version;
use crate::interpreter::{InterpreterState, StackValue};

static REPL_FILE_NAME: &str = "<STDIN>";

fn print_top_of_stack(state: &InterpreterState) {
    let Some(item) = state.stack_top() else {
        println!("#0: <STACK IS EMPTY>");
        return;
    };

    match &item {
        StackValue::Identifier(id) => {
            println!("#0: ::{}", id.name);
        }
        StackValue::I64(v) => println!("#0: {}", v),
        StackValue::I32(v) => println!("#0: {}:i32", v),
        StackValue::I16(v) => println!("#0: {}:i16", v),
        StackValue::I8(v)  => println!("#0: {}:i8", v),

        StackValue::U64(v) => println!("#0: {}:u64", v),
        StackValue::U32(v) => println!("#0: {}:u32", v),
        StackValue::U16(v) => println!("#0: {}:u16", v),
        StackValue::U8(v)  => println!("#0: {}:u8", v),

        StackValue::F32(v) => println!("#0: {}:f32", v),
        StackValue::F64(v) => println!("#0: {}", v),

        StackValue::Character(ch) => println!("#0: {}", ch),
        StackValue::Boolean(b) => println!("#0: {}", if *b { "TRUE" } else { "FALSE" }),

        StackValue::TokenString(_) => println!("#0: <TOKEN STRING>"),
        StackValue::Callable(_)    => println!("#0: <CALLABLE>"),
    };
}

pub fn repl() -> i32 {
    print_version();
    println!("===== YREA SLS REPL =====");
    println!("Type `#exit` to exit.");
    io::stdout().flush().unwrap();

    let mut interpreter = InterpreterState::new();
    if !interpreter.init() {
        return 1;
    }

    let stdin = io::stdin();
    let mut buf = String::new();

    loop {
        buf.clear();

        if stdin.read_line(&mut buf).is_err() {
            return 1;
        }

        if buf.trim_end() == "#exit" {
            return 0;
        }

        if let Some(file) = buf.trim_end().strip_prefix("#save ") {
            match serde_json::to_string(&interpreter) {
                Ok(json) => {
                    if let Err(err) = fs::write(file, json) {
                        eprintln!("Failed to save state: {}", err);
                    } else {
                        println!("State saved to {}", file);
                    }
                }
                Err(err) => eprintln!("Serialization error: {}", err),
            }
            continue;
        }

        if let Some(file) = buf.trim_end().strip_prefix("#load ") {
            match fs::read_to_string(file) {
                Ok(json) => match serde_json::from_str(&json) {
                    Ok(state) => {
                        interpreter = state;
                        println!("State restored from {}", file);
                    }
                    Err(err) => eprintln!("Deserialization error: {}", err),
                },
                Err(err) => eprintln!("Failed to read file: {}", err),
            }
            continue;
        }

        let code = buf.clone();
        let mut lexer_info = LexerInfo::new(REPL_FILE_NAME, code.clone());
        let result = lexical_analysis(&mut lexer_info);

        match result {
            LexResult::Ok(tokens) => {
                for token in tokens {
                    if !interpreter.execute(&token) {
                        eprintln!("A runtime error occured!");
                        break;
                    }
                }

                print_top_of_stack(&interpreter);
            }

            LexResult::Err(err) => {
                dbg!(err);
            }
        }
    }
}
