local MOD_NAME = "SN1SpeedRestore"

local TADPOLE_BASE_SPEED = 850.0
local WAKEMAKER_SPEED_BOOST = 600.0
local PLAYER_FINS_SPEED = 175.0

local TARGETS = {
    { cls = "GE_TadpoleInitialAttributes_C",  speed = TADPOLE_BASE_SPEED,    attr = "MaxSwimSpeed" },
    { cls = "GE_WakeMakerSpeedBoost_C",       speed = WAKEMAKER_SPEED_BOOST, attr = nil },
    { cls = "GE_FinsSpeedBoost_C",            speed = PLAYER_FINS_SPEED,     attr = nil },
}

local function log(msg) print("[" .. MOD_NAME .. "] " .. msg .. "\n") end

local function safe(fn)
    local ok, r = pcall(fn)
    return ok and r or nil
end

local function is_valid(o)
    return o and o.IsValid and o:IsValid()
end

local function find_cdo(cls_name)
    local cdo = safe(function() return StaticFindObject("Default__" .. cls_name) end)
    if is_valid(cdo) then return cdo end
    local cls = safe(function() return StaticFindObject(cls_name) end)
    if is_valid(cls) then
        return safe(function() return cls:GetDefaultObject() end)
    end
end

local function patch_ge(t)
    local ge = find_cdo(t.cls)
    if not is_valid(ge) then return false end
    local mods = safe(function() return ge.Modifiers end)
    local count = safe(function() return mods:GetArrayNum() end) or 0
    if count == 0 then return false end

    local patched = false
    for i = 1, count do
        local mod = safe(function() return mods[i] end)
        if mod then
            local attr_obj = safe(function() return mod.Attribute end)
            local attr_name = attr_obj and (safe(function() return attr_obj:GetFullName() end) or "") or ""
            local skip = string.find(attr_name, "CrushDepth")
                or (t.attr and attr_name ~= "" and i ~= 1 and not string.find(attr_name, t.attr))
            if not skip then
                local mag = safe(function() return mod.ModifierMagnitude end)
                if mag then
                    local sf = safe(function() return mag.ScalableFloatMagnitude end)
                        or safe(function() return mag.Magnitude end)
                    if sf then
                        if pcall(function() sf.Value = t.speed end) then patched = true end
                    end
                end
            end
        end
    end
    return patched
end

local done = {}

local function apply()
    ExecuteInGameThread(function()
        local all_done = true
        for _, t in ipairs(TARGETS) do
            if not done[t.cls] then
                if patch_ge(t) then
                    done[t.cls] = true
                    log("Patched " .. t.cls .. " = " .. t.speed)
                else
                    all_done = false
                end
            end
        end
        if all_done then log("All patched.") end
        return all_done
    end)
end

local function retry(n)
    apply()
    if n > 0 then
        ExecuteWithDelay(5000, function()
            for _, t in ipairs(TARGETS) do
                if not done[t.cls] then retry(n - 1); return end
            end
        end)
    end
end

RegisterLoadMapPostHook(function()
    done = {}
    retry(5)
end)

retry(5)

log("Loaded.")
