#include <luna/Units.h>
#include <os/ArgumentParser.h>
#include <os/File.h>
#include <sys/memstat.h>

Result<int> luna_main(int argc, char** argv)
{
    bool reserved { false };
    bool human_readable { false };

    os::ArgumentParser parser;
    parser.add_description("Query the amount of memory available and used in the system.");
    parser.add_system_program_info("free"_sv);
    parser.add_switch_argument(reserved, 'r', "show-reserved"_sv, "show reserved system memory"_sv);
    parser.add_switch_argument(human_readable, 'h', "human-readable"_sv, "show output in human-readable units"_sv);
    parser.parse(argc, argv);

    struct membuf buf;
    memstat(&buf);

    if (human_readable)
    {
        auto total = TRY(to_dynamic_unit(buf.mem_total, 10, false, Unit::Binary, true));
        auto free = TRY(to_dynamic_unit(buf.mem_free, 10, false, Unit::Binary, true));
        auto used = TRY(to_dynamic_unit(buf.mem_used, 10, false, Unit::Binary, true));

        os::println("%s total memory, out of which:", total.chars());
        os::println("%s used", used.chars());
        os::println("%s free", free.chars());
    }
    else
    {
        os::println("%lu total memory, out of which:", buf.mem_total);
        os::println("%lu used", buf.mem_used);
        os::println("%lu free", buf.mem_free);
    }

    if (reserved)
    {
        if (human_readable)
        {
            auto reserved_string = TRY(to_dynamic_unit(buf.mem_reserved, 10, false, Unit::Binary, true));

            os::println("%s reserved", reserved_string.chars());
        }
        else { os::println("%lu reserved", buf.mem_reserved); }
    }

    return 0;
}