#!/bin/lua

local version = "1.5"

local server = os.getenv("REPO") or "socket://opentty.xyz:31522"
local mirror = {
    ["armitage"] = { remote = "armitage", here = "/bin/armitage", depends = { "ifconfig" }, description = "OpenTTY Network Tools" },
    ["autogc"] = { remote = "autogc", here = "/bin/autogc", description = "Auto Clean Memory" },
    ["cmatrix"] = { remote = "cmatrix", here = "/bin/cmatrix", description = "The Matrix Effect" },
    ["curl"] = { remote = "curl.lua", here = "/bin/curl", description = "Connect with a Server" },
    ["docker"] = { remote = "docker.lua", here = "/bin/docker", description = "Conteiners on OpenTTY" },
    ["expr"] = { remote = "expr.lua", here = "/bin/expr", description = "Evaluate expressions" },
    ["forge"] = { remote = "forge", here = "/lib/forge", description = "Additional API for OpenTTY" },
    ["find"] = { remote = "find", here = "/bin/find", description = "" },
    ["grep"] = { remote = "grep", here = "/bin/grep", description = "" },
    ["hash"] = { remote = "hash.lua", here = "/bin/hash", description = "Prints file hash" },
    ["head"] = { remote = "head", here = "/bin/head", description = "Prints first lines of a file" },
    ["hostname"] = { remote = "hostname.lua", here = "/bin/hostname", description = "Manage Host Name" },
    ["htop"] = { remote = "htop", here = "/bin/htop", description = "System Monitor" },
    ["ifconfig"] = { remote = "ifconfig.lua", here = "/bin/ifconfig", description = "Network Informations" },
    ["jauth2"] = { remote = "jauth2", here = "/lib/jauth2", description = "Credentials Manager" },
    ["jdb"] = { remote = "debuggers", here = "/bin/jdb", depends = { "forge" }, description = "Debugging API" },
    ["nano"] = { remote = "nano.lua", here = "/bin/nano", description = "Text Editor for OpenTTY" },
    ["nc"] = { remote = "netcat.lua", here = "/bin/nc", description = "Connect with Remote Interfaces" },
    ["pastebin"] = { remote = "pastebin", here = "/bin/pastebin", description = "PasteBin Client for OpenTTY" },
    ["ping"] = { remote = "ping.lua", here = "/bin/ping", description = "Test connection delay" },
    ["sed"] = { remote = "sed.lua", here = "/bin/sed", description = "String Editor" },
    ["sdk"] = { remote = "sdkme", here = "/bin/sdk", description = "OpenTTY Application SDK" },
    ["sync"] = { remote = "sync", here = "/bin/sync", description = "OpenTTY Updater Checker" },
    ["uname"] = { remote = "uname", here = "/bin/uname", description = "System Informations" },
    ["viewer"] = { remote = "img.lua", here = "/bin/view", description = "View Images" },
    ["viaversion"] = { remote = "viaversion", here = "/bin/axrz", description = "Change OpenTTY API on Runtime" },
    ["webproxy"] = { remote = "proxy.lua", here = "/bin/shprxy", description = "Access OpenTTY on WebProxy" },
    ["wget"] = { remote = "wget", here = "/bin/wget", description = "Download files from Network" },
    ["yang"] = { remote = "yang", here = "/bin/yang", description = "OpenTTY Package Manager" },

    ["net"] = { description = "Network Utilities", packages = { "curl", "ifconfig", "ping", "webproxy" } },
    ["file"] = { description = "File Utitlities", packages = { "find", "grep", "hash", "head", "nano", "sed" } },
    ["dev"] = { description = "Development Tools", packages = { "forge", "jdb", "sdk" } },
    ["sys"] = { description = "System Utitlities", packages = { "autogc", "hostname", "htop" } }
}

local function connect(payload)
    local ok, conn, i, o = pcall(socket.connect, server)

    io.write(payload, o)
    local content = io.read(i, 8192)

    pcall(io.close, conn, i, o)

    return content
end

local function install(pkg, verbose)
    if verbose then
        print(":: Installing " .. pkg .. "...")
    end

    local info = mirror[pkg]

    if info.depends then
        print(":: Building dependencies")
        for _, dep in ipairs(info.depends) do
            install(dep, verbose)
        end
    end

    local content = connect("get lib/" .. info.remote)
    if content then
        local status = io.write(content, info.here)

        if verbose then
            if status == 0 then
                print(":: Installed " .. info.here)
            else
                print(":: Installation error for " .. pkg)
            end
        end

        return status == 0
    else
        if verbose then
            print(":: Connection error")
        end

        return nil
    end
end
local function remove(pkg, verbose)
    if verbose then
        print(":: Removing " .. pkg .. "...")
    end

    local info = mirror[pkg]

    local status = os.remove(info.here)

    if verbose then
        if status == 0 then
            print(":: Removed " .. info.here)
        elseif status == 127 then
            print(":: Package not installed")
        else
            print(":: Removing error for " .. pkg)
        end
    end

    return status == 0
end

local function main()
    if arg[1] == nil or arg[1] == "help" then
        print("Yang Package Manager v" .. version)
        print("Usage: yang <command> [package]")
        print("Commands:")
        print("  install <package>  - Install a package")
        print("  remove <package>   - Remove a package")
        print("  update             - Check for updates")
        print("  list               - List available packages")
        print("  info <package>     - Show package information")
        print("  help               - Show this help")
    elseif arg[1] == "install" then
        if os.getuid() > 0 then
            print("Permission denied!")
            os.exit(13)
        end

        if arg[2] then
            for i = 2, #arg - 1 do
                local pkg = arg[i]

                if mirror[pkg] then
                    if mirror[pkg].packages then
                        print(":: Installing collection: " .. pkg)
                        print(":: Description: " .. mirror[pkg].description)
                        print("")

                        local sucess_count = 0
                        local total_count = #mirror[pkg].packages

                        for _, query in ipairs(mirror[pkg].packages) do
                            if install(query, false) then
                                sucess_count = sucess_count + 1
                            end
                        end

                        print(":: Collection installation complete!")
                        print("-> Sucessfully installed: " .. sucess_count .. "/" .. total_count .. " packages")
                    elseif mirror[pkg].remote then
                        install(pkg, true)
                    else
                        print("yang: install: " .. pkg .. ": invalid package (not remote source)")
                        os.exit(1)
                    end
                else
                    print("yang: install: " .. pkg .. ": not found")
                    os.exit(127)
                end
            end
        else
            print("yang: usage: yang remove [package]")
        end
    elseif arg[1] == "remove" then
        if os.getuid() > 0 then
            print("Permission denied!")
            os.exit(13)
        end

        if arg[2] then
            for i = 2, #arg - 1 do
                local pkg = arg[i]

                if mirror[pkg] then
                    if mirror[pkg].packages then
                        print(":: Removing collection: " .. pkg)
                        print("")

                        local remove_count = 0

                        for _, query in ipairs(mirror[pkg].packages) do
                            if remove(query, false) then
                                remove_count = remove_count + 1
                            end
                        end

                        print(":: Removed " .. remove_count .. " packages from collection '" .. pkg .. "'")
                    elseif mirror[pkg].remote then
                        remove(pkg, true)
                    else
                        print("yang: remove: " .. pkg .. ": invalid package")
                        os.exit(2)
                    end
                else
                    print("yang: remove: " .. pkg .. ": not found")
                    os.exit(127)
                end
            end
        else
            print("yang: usage: yang remove [package]")
        end
    elseif arg[1] == "update" then
        local response = connect("fetch")
        if response then
            print(":: " .. response)
        else
            print(":: Connection error")
            os.exit(101)
        end
    elseif arg[1] == "list" then
        print("Available packages:")
        for name, info in pairs(mirror) do
            if not info.packages then
                print("- " .. name .. ": " .. info.description)
            end
        end
    elseif arg[1] == "info" then
        if arg[2] then
            local pkg = arg[2]

            if mirror[pkg] then
                local info = mirror[pkg]
                if info.packages then
                else
                    print("Package: " .. pkg)
                    print("Description: " .. info.description)
                    print("Path: " .. info.here)

                    if info.depends then
                        print("Dependencies: " .. table.concat(info.depends, ", "))
                    end
                end
            else
                print(":: " .. pkg .. " not found")
                os.exit(127)
            end
        else
            print("yang: usage: yang info [package]")
        end
    end
end

os.setproc("name", "yang")
main()