local G={}local N=game:GetService("\082\117\110\083\101\114\118\105\099\101")local x=require(script:FindFirstAncestor("\080\108\117\103\105\110\070\114\097\109\101\119\111\114\107"))local n local h local O local X=game:GetService("\083\101\114\118\101\114\083\116\111\114\097\103\101")local f="\083\111\099\107\101\116\080\108\117\103\105\110"local j="\077\097\099\114\111\115"local w="\076\111\099\097\108\077\097\099\114\111\115"local k="\085\116\105\108\115"local I=N:IsRunning()local q=N:IsClient()G.Folders={Directory=nil;Macros=nil,LocalMacros=nil;Utils=nil}function G.ValidateStructure(N)local n=X:FindFirstChild(f)if not n then n=Instance.new("\067\111\110\102\105\103\117\114\097\116\105\111\110")n.Name=f n.Parent=X end G.Folders.Directory=n local O=n:FindFirstChild(j)if not O then O=Instance.new("\070\111\108\100\101\114")O.Name=j O.Parent=n end G.Folders.Macros=O local I=n:FindFirstChild(w)if not I then I=Instance.new("\070\111\108\100\101\114")I.Name=w I.Parent=n end G.Folders.LocalMacros=I local q=n:FindFirstChild(k)if not q then q=Instance.new("\070\111\108\100\101\114")q.Name=k q.Parent=n end G.Folders.Utils=q local M=(x:GetDirectory("\085\116\105\108\115")):GetChildren()for G,N in pairs(M)do local x=q:FindFirstChild(N.Name)if x then x:Destroy()end if N:IsA("\077\111\100\117\108\101\083\099\114\105\112\116")then local G=N:Clone()G.Parent=q local x=N:FindFirstChild(h.IS_CUSTOM_MODULE_NAME)if x then x:Destroy()end end end local K=O:FindFirstChild("\067\111\114\101")if not K then K=Instance.new("\070\111\108\100\101\114")K.Name="\067\111\114\101"K.Parent=O end end function G.HasSocketDirectory(G)local N=X:FindFirstChild(f)return N and true or false end function G.ValidateBuiltInMacros(N)local x=G.Folders.Macros.Core local n=O:GetSetting("\069\110\097\098\108\101\083\111\099\107\101\116\077\097\099\114\111\115")local h=O:GetSetting("\069\110\097\098\108\101\083\111\099\107\101\116\077\097\099\114\111\115\079\118\101\114\119\114\105\116\101")if not(I and q)and n then local G=script.Parent.CoreMacros local N=G:GetChildren()for G,N in pairs(N)do if N:IsA("\077\111\100\117\108\101\083\099\114\105\112\116")then local G=x:FindFirstChild(N.Name)if h then local n=G and(G:IsA("\077\111\100\117\108\101\083\099\114\105\112\116")and G.Source)local h=N.Source if n~=h then if G then G:Destroy()end if N:IsA("\077\111\100\117\108\101\083\099\114\105\112\116")then(N:Clone()).Parent=x end end elseif not G then if N:IsA("\077\111\100\117\108\101\083\099\114\105\112\116")then(N:Clone()).Parent=x end end end end end end function G.FrameworkInit(G)n=x:Require("\076\111\103\103\101\114")h=x:Require("\070\114\097\109\101\119\111\114\107")O=x:Require("\083\111\099\107\101\116\083\101\116\116\105\110\103\115")end function G.FrameworkStart(G) end return G
---
---Utility functions for managing Roblox Instances
---
---@class StudioHandler
---
local StudioHandler = {}

--------------------------------------------------
-- Types
-- ...

--------------------------------------------------
-- Dependencies
local RunService = game:GetService("RunService") ---@type RunService
local PluginFramework = require(script:FindFirstAncestor("PluginFramework")) ---@type Framework
local Logger ---@type Logger
local Framework ---@type Framework
local SocketSettings ---@type SocketSettings

--------------------------------------------------
-- Constants
local DIRECTORY_FOLDER_PARENT = game:GetService("ServerStorage")
local DIRECTORY_FOLDER_NAME = "SocketPlugin"
local MACROS_FOLDER_NAME = "Macros"
local LOCAL_MACROS_FOLDER_NAME = "LocalMacros"
local UTILS_FOLDER_NAME = "Utils"
local IS_RUNNING = RunService:IsRunning()
local IS_CLIENT = RunService:IsClient()

--------------------------------------------------
-- Members
StudioHandler.Folders = {
    Directory = nil, ---@type Configuration
    Macros = nil, ---@type Folder
    LocalMacros = nil, ---@type Folder
    Utils = nil, ---@type Folder
}

---
---Will ensure the proper Studio requisites exist; will create anything missing.
---
function StudioHandler:ValidateStructure()
    --------------------------------------------------
    -- CREATE FOLDERS

    -- Directory
    local directoryFolder = DIRECTORY_FOLDER_PARENT:FindFirstChild(DIRECTORY_FOLDER_NAME)
    if not directoryFolder then
        directoryFolder = Instance.new("Configuration")
        directoryFolder.Name = DIRECTORY_FOLDER_NAME
        directoryFolder.Parent = DIRECTORY_FOLDER_PARENT
    end
    StudioHandler.Folders.Directory = directoryFolder

    -- Macros
    local macrosFolder = directoryFolder:FindFirstChild(MACROS_FOLDER_NAME)
    if not macrosFolder then
        macrosFolder = Instance.new("Folder")
        macrosFolder.Name = MACROS_FOLDER_NAME
        macrosFolder.Parent = directoryFolder
    end
    StudioHandler.Folders.Macros = macrosFolder

    -- LocalMacros
    local localMacrosFolder = directoryFolder:FindFirstChild(LOCAL_MACROS_FOLDER_NAME)
    if not localMacrosFolder then
        localMacrosFolder = Instance.new("Folder")
        localMacrosFolder.Name = LOCAL_MACROS_FOLDER_NAME
        localMacrosFolder.Parent = directoryFolder
    end
    StudioHandler.Folders.LocalMacros = localMacrosFolder

    -- Utils
    local utilsFolder = directoryFolder:FindFirstChild(UTILS_FOLDER_NAME)
    if not utilsFolder then
        utilsFolder = Instance.new("Folder")
        utilsFolder.Name = UTILS_FOLDER_NAME
        utilsFolder.Parent = directoryFolder
    end
    StudioHandler.Folders.Utils = utilsFolder

    --------------------------------------------------
    -- POPULATE UTILS

    local utilsModuleScripts = PluginFramework:GetDirectory("Utils"):GetChildren() ---@type ModuleScript[]
    for _, moduleScript in pairs(utilsModuleScripts) do
        -- Destroy matching instance
        local matchingStudioInstance = utilsFolder:FindFirstChild(moduleScript.Name) ---@type ModuleScript
        if matchingStudioInstance then
            matchingStudioInstance:Destroy()
        end

        -- Place Clone
        if moduleScript:IsA("ModuleScript") then
            local clone = moduleScript:Clone()
            clone.Parent = utilsFolder

            local isCustomModuleObject = moduleScript:FindFirstChild(Framework.IS_CUSTOM_MODULE_NAME)
            if isCustomModuleObject then
                isCustomModuleObject:Destroy()
            end
        end
    end

    --------------------------------------------------
    -- POPULATE CORE MACROS

    -- Create Folder
    local coreMacrosFolder = macrosFolder:FindFirstChild("Core")
    if not coreMacrosFolder then
        coreMacrosFolder = Instance.new("Folder") ---@type Folder
        coreMacrosFolder.Name = "Core"
        coreMacrosFolder.Parent = macrosFolder
    end
end

function StudioHandler:HasSocketDirectory()
    local directoryFolder = DIRECTORY_FOLDER_PARENT:FindFirstChild(DIRECTORY_FOLDER_NAME)
    return directoryFolder and true or false
end

---
---Ensures our core macros are initiated
---
function StudioHandler:ValidateBuiltInMacros()
    local coreMacrosFolder = StudioHandler.Folders.Macros.Core

    -- Copy over core macros UNLESS we're running on client (`MacroClientServer` handles this) (or got something disabled)
    local doEnableCoreMacros = SocketSettings:GetSetting("EnableSocketMacros")
    local doEnableCoreMacrosOverwrite = SocketSettings:GetSetting("EnableSocketMacrosOverwrite")
    if not (IS_RUNNING and IS_CLIENT) and doEnableCoreMacros then
        local internalCoreMacrosFolder = script.Parent.CoreMacros
        local macrosModuleScripts = internalCoreMacrosFolder:GetChildren() ---@type ModuleScript[]
        for _, moduleScript in pairs(macrosModuleScripts) do
            if moduleScript:IsA("ModuleScript") then
                local matchingStudioInstance = coreMacrosFolder:FindFirstChild(moduleScript.Name) ---@type ModuleScript
                if doEnableCoreMacrosOverwrite then
                    -- Do we *need* to overwrite? Lets compare the sources.
                    local existingSource = matchingStudioInstance
                        and matchingStudioInstance:IsA("ModuleScript")
                        and matchingStudioInstance.Source
                    local currentSource = moduleScript.Source

                    if existingSource ~= currentSource then
                        -- Destroy matching instance
                        if matchingStudioInstance then
                            matchingStudioInstance:Destroy()
                        end

                        if moduleScript:IsA("ModuleScript") then
                            moduleScript:Clone().Parent = coreMacrosFolder
                        end
                    end
                elseif not matchingStudioInstance then
                    if moduleScript:IsA("ModuleScript") then
                        moduleScript:Clone().Parent = coreMacrosFolder
                    end
                end
            end
        end
    end
end

---
---@private
---
function StudioHandler:FrameworkInit()
    Logger = PluginFramework:Require("Logger")
    Framework = PluginFramework:Require("Framework")
    SocketSettings = PluginFramework:Require("SocketSettings")
end

---
---@private
---
function StudioHandler:FrameworkStart() end

return StudioHandler
