--:Minify:--
local args   = { ... }
local target = args[1] or "http://example.com"

local function pass(msg) syscall.devctl(1,"sfgc",10); print("  PASS  " .. msg); syscall.devctl(1,"sfgc",1) end
local function fail(msg) syscall.devctl(1,"sfgc",2);  print("  FAIL  " .. msg); syscall.devctl(1,"sfgc",1) end
local function info(msg) syscall.devctl(1,"sfgc",14); print("  ....  " .. msg); syscall.devctl(1,"sfgc",1) end
local function head(msg) syscall.devctl(1,"sfgc",4);  print("\n" .. msg);        syscall.devctl(1,"sfgc",1) end

local passed, failed = 0, 0
local function check(name, ok, err)
    if ok then passed = passed + 1; pass(name)
    else       failed = failed + 1; fail(name .. " - " .. tostring(err)) end
end

head("[ 1 ] socket() creation")
do
    local ok, fd = pcall(syscall.socket, "inet", "stream")
    check("socket(inet, stream) returns fd", ok and type(fd) == "number", fd)

    if ok then
        local cok = pcall(syscall.close, fd)
        check("close() on socket fd", cok, "close failed")
    end

    local ok2, fd2 = pcall(syscall.socket, "unix", "stream")
    check("socket(unix, stream) returns fd", ok2 and type(fd2) == "number", fd2)
    if ok2 then pcall(syscall.close, fd2) end

    local ok3 = pcall(syscall.socket, "ax25", "stream")
    check("socket(ax25) returns EAFNOSUPPORT", not ok3, "should have errored")
end

head("[ 2 ] connect() to " .. target)
local sockfd
do
    local ok, fd = pcall(syscall.socket, "inet", "stream")
    check("socket() before connect", ok, fd)

    if ok then
        sockfd = fd
        local cok, cerr = pcall(syscall.connect, fd, target)
        check("connect(" .. target .. ")", cok, cerr)
    end
end

head("[ 3 ] send() HTTP GET via socket")
do
    if sockfd then
        local sok, serr = pcall(syscall.send, sockfd, "")
        check("send() does not error", sok, serr)
    else
        check("send() skipped (no socket)", false, "socket creation failed")
    end
end

head("[ 4 ] recv() reads HTTP response")
do
    if sockfd then
        info("waiting for response (recv blocks up to 10s)...")
        local ok, body = pcall(syscall.recv, sockfd, 65536)
        check("recv() returns non-empty body", ok and body and #body > 0,
              ok and "empty response" or tostring(body))
        if ok and body and #body > 0 then
            info("received " .. #body .. " bytes")
            local preview = body:sub(1, 120):gsub("\r", ""):gsub("\n", " ")
            info("preview: " .. preview)
        end
        pcall(syscall.close, sockfd)
        sockfd = nil
    else
        check("recv() skipped (no socket)", false, "socket creation failed")
    end
end

head("[ 5 ] httpget() convenience wrapper")
do
    info("GET " .. target .. " ...")
    local ok, body = pcall(syscall.httpget, target)
    check("httpget() succeeds", ok, body)
    if ok then
        check("httpget() returns non-empty string", type(body) == "string" and #body > 0, "empty")
        if type(body) == "string" and #body > 0 then
            info("received " .. #body .. " bytes")
            local preview = body:sub(1, 120):gsub("\r", ""):gsub("\n", " ")
            info("preview: " .. preview)
            local hasHtml = body:lower():find("<html") ~= nil
                         or body:lower():find("<!doctype") ~= nil
                         or body:find("{") ~= nil
                         or body:find("HTTP") ~= nil
            check("body looks like HTTP content", hasHtml, "no recognisable content markers")
        end
    end
end

head("[ 6 ] UNIX socket loopback IPC")
do
    local sockPath = "/tmp/socktest.sock"
    pcall(syscall.remove, sockPath)

    local sok, sfd = pcall(syscall.socket, "unix", "stream")
    check("server socket(unix,stream)", sok, sfd)

    if sok then
        local bok = pcall(syscall.bind, sfd, sockPath)
        check("bind(" .. sockPath .. ")", bok, "bind failed")

        local lok = pcall(syscall.listen, sfd, 1)
        check("listen()", lok, "listen failed")

        local cok, cfd = pcall(syscall.socket, "unix", "stream")
        check("client socket(unix,stream)", cok, cfd)

        if cok then
            local connok = pcall(syscall.connect, cfd, sockPath)
            check("client connect(" .. sockPath .. ")", connok, "connect failed")

            local aok, afd = pcall(syscall.accept, sfd)
            check("accept() returns client fd", aok, afd)

            if connok and aok then
                local sendok = pcall(syscall.send, cfd, "hello hyperion")
                check("send() from client", sendok, "send failed")

                local rok, data = pcall(syscall.recv, afd, 1024)
                check("recv() on server side", rok and data == "hello hyperion",
                      rok and ("got: " .. tostring(data)) or tostring(data))

                local repok = pcall(syscall.send, afd, "hello back")
                check("send() reply from server", repok, "send failed")

                local rok2, data2 = pcall(syscall.recv, cfd, 1024)
                check("recv() reply on client", rok2 and data2 == "hello back",
                      rok2 and ("got: " .. tostring(data2)) or tostring(data2))

                pcall(syscall.close, afd)
            end

            pcall(syscall.close, cfd)
        end

        pcall(syscall.close, sfd)
        pcall(syscall.remove, sockPath)
    end
end

print("")
syscall.devctl(1,"sfgc", failed == 0 and 10 or 2)
print(string.format("Results: %d passed, %d failed", passed, failed))
syscall.devctl(1,"sfgc",1)
if failed > 0 then syscall.exit(1) end
