--:Minify:--
local cloptions = {
    a    = false,
    h    = false,
    l    = false,
    help = false,
}
local inpArgs = { ... }
local args    = {}
local name    = syscall.getTask(syscall.getpid()).name

for _, v in pairs(inpArgs) do
    if v:sub(1, 2) == "--" then
        local opt = v:sub(3)
        if cloptions[opt] == nil then
            print(name .. ": unrecognized option '" .. v .. "'.")
            print("try '" .. name .. " --help' for more information.")
            return
        end
        cloptions[opt] = true
    elseif v:sub(1, 1) == "-" then
        for i = 2, #v do
            local opt = v:sub(i, i)
            if cloptions[opt] == nil then
                print(name .. ": invalid option '-" .. opt .. "'.")
                print("try '" .. name .. " --help' for more information.")
                return
            end
            cloptions[opt] = true
        end
    else
        table.insert(args, v)
    end
end

if cloptions.help then
    print("Usage: " .. name .. " [OPTION]... [DIR]")
    print("List all entries in the specified DIRectory, or cwd if not specified.")
    print("Display directory tree structure.")
    print("")
    print("Options:")
    print("  -a          do not ignore entries starting with .")
    print("  -h          with -l, print sizes in human readable format (e.g., 1K 234M 2G)")
    print("  -l          use a long listing format (show file sizes)")
    print("  --help      display this help and exit")
    return
end

local fs  = require("fs")
local dir = args[1] or ""
if dir:sub(1, 1) ~= "/" then
    dir = syscall.getcwd() .. "/" .. dir
end
if dir:sub(-1) ~= "/" then dir = dir .. "/" end

if not fs.isDir(dir) then
    print(name .. ": cannot access '" .. (args[1] or dir) .. "': no such directory")
    return
end

local function format_size(size)
    if not cloptions.h then return tostring(size) end
    if size < 1024 then return tostring(size) .. "B"
    elseif size < 1024*1024 then return string.format("%.1fK", size/1024)
    elseif size < 1024*1024*1024 then return string.format("%.1fM", size/1024/1024)
    else return string.format("%.1fG", size/1024/1024/1024) end
end

local function pdir(current_dir, level, prefix)
    prefix = prefix or ""
    local list = fs.list(current_dir)
    if not cloptions.a then
        for i = #list, 1, -1 do
            if list[i]:sub(1, 1) == "." then table.remove(list, i) end
        end
    end
    table.sort(list)
    if current_dir:sub(-1) ~= "/" then current_dir = current_dir .. "/" end

    for i, entry in ipairs(list) do
        local full_path = current_dir .. entry
        local is_last = (i == #list)
        local branch = is_last and "`--" or "|--"
        local indent = prefix .. branch
        local suffix = ""
        local info = ""

        if fs.isDir(full_path) then
            suffix = "/"
        end

        if cloptions.l then
            local stat = fs.stat and fs.stat(full_path)
            if stat then
                local size = stat.size or 0
                info = " " .. format_size(size)
            end
        end

        print(indent .. entry .. suffix .. info)

        if fs.isDir(full_path) then
            local new_prefix = prefix .. (is_last and "    " or "|   ")
            pcall(pdir, full_path, level + 1, new_prefix)
        end
    end
end

-- Print root directory
local root_name = dir:sub(1, -2) -- remove trailing /
if root_name == "" then root_name = "/" end
print(root_name)
pdir(dir, 0, "")