use super::{TreeCursor, VarType, expressions, types};

mod function;
mod map;
mod reference;
mod set;
mod vec;

pub fn parse(cursor: &mut TreeCursor, code: &str) -> VarType {
    cursor.goto_first_child();

    let type_name = cursor.node().kind();
    let var_type = match type_name {
        "void" => VarType::Void,
        "int" => VarType::Int,
        "str" => VarType::Str,
        "float" => VarType::Float,
        "bool" => VarType::Bool,
        "reference_type" => reference::parse(cursor, code),
        "function_type" => function::parse(cursor, code),
        "struct_identifier" => VarType::Struct(code[cursor.node().byte_range()].to_string()),
        "vec_type" => vec::parse(cursor, code),
        "set_type" => set::parse(cursor, code),
        "map_type" => map::parse(cursor, code),
        _ => todo!("{type_name}"),
    };

    cursor.goto_parent();
    var_type
}

pub fn transpile(var_type: &VarType) -> String {
    let s = match &var_type {
        VarType::Void => "()",
        VarType::Int => "i32",
        VarType::Float => "f32",
        // could be a mistake
        VarType::Str => "&'static str",
        VarType::Bool => "bool",
        VarType::Reference(ref_type) => &format!("&mut {}", transpile(ref_type)),
        VarType::Struct(struct_name) => struct_name,
        VarType::Function {
            return_type,
            param_types,
        } => &format!(
            "fn({}) -> {}",
            expressions::transpile_list(&param_types.iter().map(transpile).collect()),
            transpile(return_type),
        ),
        VarType::Vec(inner_type) => &vec::transpile(inner_type),
        VarType::Set(inner_type) => &set::transpile(inner_type),
        VarType::Map(map_types) => &map::transpile(map_types),
        _ => todo!("{var_type:?}"),
    };
    s.to_string()
}
