console_commands_to_register : [..]string;

add_console_registration_code :: (w: *Workspace) {
    builder : String_Builder;
    print_to_builder(*builder, "register_commands :: () {\n");
    for console_commands_to_register {
        print_to_builder(*builder, "array_add(*console_command_procs, %__command_front);\n", it);
        print_to_builder(*builder, "array_add(*console_command_names, \"%\");\n", it);
    }
    print_to_builder(*builder, "}\n");
    add_build_string(builder_to_string(*builder), w.*);
}

add_console_commands :: (message: *Message, w: *Workspace) {
    if message.kind == .PHASE {
        phase_message := cast(*Message_Phase) message;
        if phase_message.phase == .TYPECHECKED_ALL_WE_CAN {
            if console_commands_to_register.count > 0 {
                add_console_registration_code(w);
                array_reset(*console_commands_to_register);
            }
        }
    }
    if message.kind != .TYPECHECKED then return;
    code := cast(*Message_Typechecked) message;

    all_commands_builder : String_Builder;

	for code.declarations {
		import := it.expression.enclosing_load.enclosing_import;
        expression := it.expression;
    	if expression.expression && expression.expression.kind == .PROCEDURE_HEADER {
            header := cast(*Code_Procedure_Header) expression.expression;
            is_command := false;
            for expression.notes {
                if it.text == "Command" {
                    is_command = true;
                }
            }
            if !is_command then continue;

            if expression.flags & .SCOPE_FILE {
        	    compiler_report(sprint("Command % is file scoped, that is not okay. Commands must be exported.", expression.name), make_location(cast(*Code_Node)expression), .ERROR);
            }
            arg_count := header.arguments.count;
            arg_count_min := header.arguments.count;

            for arg, i : header.arguments {
                if arg.expression != null then arg_count_min -= 1;
            }


            builder : String_Builder;
            print_to_builder(*builder, "%__command_front :: (args: []string) -> string {\n", expression.name);
            print_to_builder(*builder, "if !verify_argument_count(%, %, args.count) return sprint(\"Wrong number of arguments! Expected \%, got \%.\", %, args.count);\n", arg_count_min, arg_count, arg_count);

            get_call_string :: (num: int) -> string {
                sep := "";
                call_args_builder : String_Builder;
                for 0..num-1 {
                    print_to_builder(*call_args_builder, "%xx a%", sep, it);
                    sep = ", ";
                }                
                return builder_to_string(*call_args_builder);
            }

            
            for arg, i : header.arguments {
                type_tag := arg.type_inst.result.type;
                arg_name := arg.name;
                if type_tag == {
                    case .INTEGER;
                        print_to_builder(*builder, "a% : int; success% : bool;\n", i, i);
                        print_to_builder(*builder, "if args.count > % {\n", i);
                        print_to_builder(*builder, "a%, success% = string_to_int(args[%]);\n", i, i, i);
                        print_to_builder(*builder, "if !success% then return sprint(\"Can't parse value \% for argument % at position % to type %.\", args[%]);\n", i, arg_name, i, type_tag, i);
                        print_to_builder(*builder, "}\n");
                    case .FLOAT;
                        print_to_builder(*builder, "a% : float; success% : bool;\n", i, i);
                        print_to_builder(*builder, "if args.count > % {\n", i);
                        print_to_builder(*builder, "a%, success% = string_to_float(args[%]);\n", i, i, i);
                        print_to_builder(*builder, "if !success% then return sprint(\"Can't parse value \% for argument % at position % to type %.\", args[%]);\n", i, arg_name, i, type_tag, i);
                        print_to_builder(*builder, "}\n");
                    case .BOOL;
                        print_to_builder(*builder, "a% : bool; success% : bool;\n", i, i);
                        print_to_builder(*builder, "if args.count > % {\n", i);
                        print_to_builder(*builder, "a%, success% = string_to_bool(args[%]);\n", i, i, i);
                        print_to_builder(*builder, "if !success% then return sprint(\"Can't parse value \% for argument % at position % to type %.\", args[%]);\n", i, arg_name, i, type_tag, i);
                        print_to_builder(*builder, "}\n");
                    case .STRING;
                        print_to_builder(*builder, "a% : string;;\n", i);
                        print_to_builder(*builder, "if args.count > % {\n", i);
                        print_to_builder(*builder, "a% = args[%];\n", i, i);
                        print_to_builder(*builder, "}\n");
                    case;
                	    compiler_report(sprint("Argument % is of type %, which is not handled by automatic command registration.", arg_name, type_tag), make_location(cast(*Code_Node)arg), .ERROR);
                }
            }
            for arg_count_min..arg_count {
                print_to_builder(*builder, "if args.count == % then return sprint(\"\%\", %(%));\n", it, expression.name, get_call_string(it));
            }
            print_to_builder(*builder, "return \"Something really really weird has happened. Your argument count somehow went trough all the return checks....\";\n");
            print_to_builder(*builder, "}\n");
            str := builder_to_string(*builder);
            // print("Generated: %\n", str);
            array_add(*console_commands_to_register, sprint("%", expression.name));
            add_build_string(str, w.*);
            free(str);
    	}
	}
	return;
    
}
