local M = {}
local fs = require("luarocks.fs")
local path = require("luarocks.path")
local dir = require("luarocks.dir")

---core function
---@return true?, string?
function M.run(rockspec, no_install)
    local compile_temp_dir = fs.make_temp_dir("build-" .. rockspec.package .. "-" .. rockspec.version)
    if rockspec.build.variables == nil then
        rockspec.build.variables = {}
    end
    -- l3build uses texlua
    if not fs.execute_env(rockspec.build.variables, [[l3build install --texmfhome ]] .. compile_temp_dir) then
        return nil, "Failed run l3build"
    end
    if no_install then
        return true
    end

    local dir_sep = package.config:sub(1, 1)
    local luadir = path.lua_dir(rockspec.name, rockspec.version)
    local texdir = dir.path(compile_temp_dir, 'tex')
    if fs.is_dir(texdir) then
        for _, name in ipairs(fs.find(texdir)) do
            local file = dir.path(texdir, name)
            if not fs.is_dir(file) and (file:match("%.lua$") or file:match("%.tlu$")) then
                -- generic/pgf/lua/pgf/manual.lua -> pgf
                local mod = name:match('^[^/]+/([^/]+)')
                -- generic/pgf/lua/pgf/manual.lua -> lua/pgf/manual.lua
                name = name:match('^[^/]+/[^/]+/(.*)')
                -- lua/pgf/manual.lua -> lua/pgf/manual -> /pgf
                -- lua/pgf.lua -> lua/pgf -> /pgf
                if name:match('(.*)%.[^.]+$'):match(dir_sep .. mod) then
                    -- lua/pgf/manual.lua -> pgf/manual.lua
                    -- lua/pgf.lua -> pgf.lua
                    name = name:match('.*'.. dir_sep .. '(' .. mod .. '[' .. dir_sep ..  '.].*)')
                end
                local dst = dir.path(luadir, name)
                fs.make_dir(dir.dir_name(dst))
                fs.copy(file, dst)
            end
        end
    end
    local bindir = path.bin_dir(rockspec.name, rockspec.version)
    local scriptsdir = dir.path(compile_temp_dir, 'scripts')
    if fs.is_dir(scriptsdir) then
        for _, name in ipairs(fs.find(scriptsdir)) do
            local file = dir.path(scriptsdir, name)
            if not fs.is_dir(file) then
                local f = io.open(file)
                local line = ""
                if f then
                    line = f:read(2)
                    f:close()
                end
                if line == '#!' then
                    local exe = dir.base_name(file):gsub("%.lua$", ""):gsub("%.tlu$", "")
                    fs.copy(file, dir.path(bindir, exe), 'exec')
                else
                    local dst = dir.path(luadir, name:match('^[^/]+/(.*)'))
                    fs.make_dir(dir.dir_name(dst))
                    fs.copy(file, dst)
                end
            end
        end
    end
    local confdir = path.conf_dir(rockspec.name, rockspec.version)
    local rootdir = dir.dir_name(confdir)
    for _, name in ipairs(fs.find(compile_temp_dir)) do
        -- don't pack source code
        if not name:match('^source' .. dir_sep) and not name:match('^' .. dir.path('font', 'source') .. dir_sep) then
            local file = dir.path(compile_temp_dir, name)
            if not fs.is_dir(file) and not file:match("%.lua$") and not file:match("%.tlu$") then
                local dst = dir.path(rootdir, name)
                fs.make_dir(dir.dir_name(dst))
                fs.copy(file, dst)
            end
        end
    end
    return true
end

return M
