use crate::util::input;

pub fn tool_libcreate() {
    let mut ptype: String;
    loop {
        ptype = input("Enter project type (bin|lib)");
        if ptype == "bin" || ptype == "lib" {
            break;
        }
    }

    let project_name = input("Enter project name");
    let project_path = input("Enter Directory to create project in");

    println!("[ Creating new {ptype} project {project_name} in {project_path} ]");

    let template = match ptype.as_str() {
        "bin" => generate_bin_template(&project_name),
        "lib" => generate_lib_template(&project_name),
        _ => panic!("Invalid project type"),
    };

    let path = format!("{project_path}/{project_name}.dsa");
    std::fs::write(path, template).expect("Unable to write file");
}

fn generate_lib_template(module_name: &str) -> String {
    format!(
        r#"// {module_name}.dsa
// usage:
//
// include {module_name} "<relative path>"
//
// usage for {module_name}_main:
// push (arg1)
// push (arg0)
// call {module_name}::{module_name}_main
// pop (arg0)
// pop (arg1)

// Example data declarations
// dw example_data: 0x0000

// Main function template
{module_name}_main:
    // the correct way to start a function as defined by the calling convention
    push bpr
    mov spr, bpr

    // explanation of how to access args
    ldw bpr, rg0, 8  // arg 0 
    ldw bpr, rg0, 12 // arg 1

    // your code goes here
    // Example: load example_data into rg1
    // ldw example_data, rg1

    // the correct way to end a function as defined by the calling convention
    mov bpr, spr
    pop bpr
    return
"#,
    )
}

fn generate_bin_template(project_name: &str) -> String {
    format!(
        r#"// {project_name}.dsa
// Binary executable project

// Example Dependencies
// include math "libs/math/math.dsa"
include print "../resources/dsa/print.dsa"

// Data declarations - It is best practice to include these before any code!
dw message: "Hello from {project_name}.dsa!" // strings are automatically null terminated!

// Program entry point - execution starts at the first non-definition line
{project_name}:
    // Getting started: Calling external functions
    // Syntax: push (arg1), push (arg0), call namespace::function, pop (arg0), pop (arg1)
    
    // Example: Print a string (if print library is included)
    ldw message, rg0    // load address of message
    push rg0            // push argument
    call print::print   // call the print function
    pop rg0             // clean up stack

    // Program must end with halt instruction
    halt
"#,
    )
}
