-- Ensures that all scripts included with a DevModule are marked as Disabled.
-- This makes sure there are no race conditions resulting in the Install script
-- running after the scripts included with the module.

local function assertScriptsAreDisabled(devModuleScripts: {Script|LocalScript})
    local enabledScripts = {}

    for _, devModuleScript in ipairs(devModuleScripts) do
        if not devModuleScript.Disabled then
            table.insert(enabledScripts, devModuleScript.Name)
        end
    end

    if #enabledScripts > 0 then
        error(ENABLED_SCRIPTS_ERROR:format(table.concat(enabledScripts, ", ")))
    end
end

function DevModuleInstaller:Install(devModule: Instance)
    local devModuleType = typeof(devModule)
    assert(devModuleType == "Instance", ("expected a DevModule to install, got %s"):format(devModuleType))

    script.InstallStarted:Fire()

    log("info", ("Installing %s from %s..."):format(devModule.Name, devModule.Parent.Name))

    local devModuleScripts = getDevModuleScripts(devModule)
    assertScriptsAreDisabled(devModuleScripts)

    if DEV_MODULE_STORAGE:FindFirstChild(devModule.Name) then
        log("info", "A version of this DevModule already exists. Skipping...")
        devModule:Destroy()
        return
    end

    if DevModuleInstaller.PruneDevelopmentFiles then
        log("info", "Pruning development files...")
        prune(devModule)
    end

    -- The `true` flag searches all descendants of an instance, which is needed
    -- here since the Packages folder is nested.
    local packages = devModule:FindFirstChild(PACKAGE_NAME, true)
    if packages then
        log("info", "Linking packages...")
        dedupePackages(packages)
    end

    log("info", "Overlaying services...")
    for _, child in ipairs(devModule:GetChildren()) do
        -- GetService errors if the given name is not a service so we wrap it in
        -- a pcall to use the result in a conditional.
        local success, service = pcall(function()
            return game:GetService(child.Name)
        end)

        if success then
            overlay(child, service)
        end
    end

    log("info", "Enabling scripts...")
    for _, devModuleScript in ipairs(devModuleScripts) do
        devModuleScript.Disabled = false
        log("info", ("Enabled %s"):format(devModuleScript.Name))
    end

    script.InstallFinished:Fire()

    log("info", ("Safe to remove %s"):format(devModule:GetFullName()))
    log("info", ("Removing %s..."):format(devModule:GetFullName()))
    devModule:Destroy()

    log("info", ("Successfully installed %s!"):format(devModule.Name))
end

return DevModuleInstaller
