HT.Reset = {}

HT.Reset.dex_toggles = {
    {setting="enable_god_mode",                   id="ut_item_dexterity_toggle_god_mode"},
    {setting="enable_infinite_stamina",            id="ut_item_dexterity_toggle_infinite_stamina"},
    {setting="enable_run_in_all_directions",       id="ut_item_dexterity_toggle_run_in_all_directions"},
    {setting="enable_can_run_with_any_bag",        id="ut_item_dexterity_toggle_can_run_with_any_bag"},
    {setting="enable_no_carry_cooldown",           id="ut_item_dexterity_toggle_no_carry_cooldown"},
    {setting="enable_no_flashbangs",               id="ut_item_dexterity_toggle_no_flashbangs"},
    {setting="enable_fast_mask",                   id="ut_item_dexterity_toggle_fast_mask"},
    {setting="enable_no_fall_damage",              id="ut_item_dexterity_toggle_no_fall_damage"},
    {setting="enable_instant_swap",                id="ut_item_dexterity_toggle_instant_swap"},
    {setting="enable_instant_reload",              id="ut_item_dexterity_toggle_instant_reload"},
    {setting="enable_no_recoil",                   id="ut_item_dexterity_toggle_no_recoil"},
    {setting="enable_no_spread",                   id="ut_item_dexterity_toggle_no_spread"},
    {setting="enable_unlimited_ammo",              id="ut_item_dexterity_toggle_unlimited_ammo"},
    {setting="enable_shoot_through_walls",         id="ut_item_dexterity_toggle_shoot_through_walls"},
    {setting="enable_instant_interaction",         id="ut_item_dexterity_toggle_instant_interaction"},
    {setting="enable_instant_deployment",          id="ut_item_dexterity_toggle_instant_deployment"},
    {setting="enable_unlimited_equipment",         id="ut_item_dexterity_toggle_unlimited_equipment"},
    {setting="enable_noclip",                      id="ut_item_dexterity_toggle_noclip"},
    {setting="enable_move_speed_multiplier",       id="ut_item_dexterity_toggle_move_speed_multiplier"},
    {setting="enable_fire_rate_multiplier",        id="ut_item_dexterity_toggle_fire_rate_multiplier"},
    {setting="enable_damage_multiplier",           id="ut_item_dexterity_toggle_damage_multiplier"},
    {setting="enable_throw_distance_multiplier",   id="ut_item_dexterity_toggle_throw_distance_multiplier"},
}

HT.Reset.mission_toggles = {
    {setting="enable_disable_ai",                  id="ut_item_mission_toggle_disable_ai"},
    {setting="enable_invisible_player",            id="ut_item_mission_toggle_invisible_player"},
    {setting="enable_instant_drilling",            id="ut_item_mission_toggle_instant_drilling"},
    {setting="enable_prevent_alarm_triggering",    id="ut_item_mission_toggle_prevent_alarm_triggering"},
    {setting="enable_unlimited_pagers",            id="ut_item_mission_toggle_unlimited_pagers"},
    {setting="enable_xray",                        id="ut_item_mission_toggle_xray"},
}

-- Extra in-heist cheat settings not covered by the dex/mission toggle lists above.
HT.Reset.extra_volatile_settings = {
    "enable_one_shot_kill",
    "enable_freeze_civilians",
}

-- Team Menu toggles (volatile host effects that should not carry between heists).
HT.Reset.troll_toggles = {
    {setting="enable_troll_team_god_mode",    id="ut_item_troll_toggle_team_god_mode"},
    {setting="enable_team_fall_protection",   id="ut_item_team_fall_protection"},
}

-- Force every "live" cheat setting back to OFF and refresh the menu display,
-- WITHOUT touching any in-game units. Safe to call from the menu / at boot.
-- Used to give a clean slate after a quit or crash so cheats don't silently
-- carry over into the next session.
function HT.Reset:disableVolatileSettings()
    local function disable(setting, jsonFile, itemId)
        HT:setSetting(setting, false, false)
        if jsonFile and itemId then
            pcall(function() HT:updateJsonValue(jsonFile, itemId, false) end)
        end
    end

    for _, t in ipairs(HT.Reset.dex_toggles) do
        disable(t.setting, "dexterity", t.id)
    end
    for _, t in ipairs(HT.Reset.mission_toggles) do
        disable(t.setting, "mission", t.id)
    end
    disable("enable_one_shot_kill", "dexterity", "ut_item_dexterity_toggle_one_shot_kill")
    disable("enable_melee_range", "dexterity", "ut_item_dexterity_toggle_melee_range")
    disable("enable_melee_damage_multiplier", "dexterity", "ut_item_dexterity_toggle_melee_damage_multiplier")
    disable("enable_instant_convert", "mission", "ut_item_mission_toggle_instant_convert")
    disable("enable_freeze_civilians", nil, nil)

    -- Extra (pirate-perfection) toggles
    disable("enable_no_delay_melee", "dexterity", "ut_item_extra_toggle_no_delay_melee")
    disable("enable_high_jump", "dexterity", "ut_item_extra_toggle_high_jump")
    disable("enable_cops_dont_shoot", "mission", "ut_item_extra_toggle_cops_dont_shoot")
    disable("enable_disable_cameras", "mission", "ut_item_extra_toggle_disable_cameras")
    disable("enable_disable_pagers", "mission", "ut_item_extra_toggle_disable_pagers")
    disable("enable_prevent_panic_buttons", "mission", "ut_item_extra_toggle_prevent_panic_buttons")
    disable("enable_auto_revive", "troll", "ut_item_extra_toggle_auto_revive")
    disable("enable_infinite_body_bags", "mission", "ut_item_extra_toggle_infinite_body_bags")
    disable("enable_infinite_cable_ties", "mission", "ut_item_extra_toggle_infinite_cable_ties")
    disable("enable_non_consumable_equipment", "mission", "ut_item_extra_toggle_non_consumable_equipment")

    -- Troll Menu toggles
    for _, t in ipairs(HT.Reset.troll_toggles) do
        disable(t.setting, "troll", t.id)
    end
    if HT.TrollMenu then HT.TrollMenu:disableAll() end

    if HT.Mission then
        HT.Mission.enableDisableAi = false
        HT.Mission.enableInvisiblePlayer = false
        HT.Mission.enableFreezeCivilians = false
        HT.Mission.autoCookEnabled = false
    end

    HT:saveSettings()
end

function HT.Reset:all(silent)
    silent = silent == true

    for _, t in ipairs(HT.Reset.dex_toggles) do
        HT:setSetting(t.setting, false)
        pcall(function() HT:setMenuToggle(t.id, false) end)
        pcall(function() HT:updateJsonValue("dexterity", t.id, false) end)
    end
    for _, t in ipairs(HT.Reset.mission_toggles) do
        HT:setSetting(t.setting, false)
        pcall(function() HT:setMenuToggle(t.id, false) end)
        pcall(function() HT:updateJsonValue("mission", t.id, false) end)
    end


    pcall(function()
        local p = managers.player:player_unit()
        if alive(p) then p:character_damage():set_god_mode(false) end
    end)

    pcall(function()
        _G.CloneClass(PlayerMovement)
        PlayerMovement._change_stamina    = PlayerMovement.orig._change_stamina
        PlayerMovement.is_stamina_drained = PlayerMovement.orig.is_stamina_drained
    end)

    pcall(function()
        _G.CloneClass(PlayerStandard)
        PlayerStandard._can_run_directional = PlayerStandard.orig._can_run_directional
    end)

    pcall(function()
        if HT.Dexterity.tweakDataCarryTypes then
            for carry_type, data in pairs(HT.Dexterity.tweakDataCarryTypes) do
                if tweak_data.carry.types[carry_type] and type(data) == "table" then
                    tweak_data.carry.types[carry_type].can_run = data.can_run
                    tweak_data.carry.types[carry_type].throw_distance_multiplier = data.throw_distance_multiplier
                end
            end
        end
    end)

    pcall(function()
        _G.CloneClass(PlayerManager)
        PlayerManager.carry_blocked_by_cooldown = PlayerManager.orig.carry_blocked_by_cooldown
    end)

    pcall(function()
        _G.CloneClass(CoreEnvironmentControllerManager)
        CoreEnvironmentControllerManager.set_flashbang = CoreEnvironmentControllerManager.orig.set_flashbang
    end)

    pcall(function()
        if HT.Dexterity.tweakDataPlayerPutOnMaskTime then
            tweak_data.player.put_on_mask_time = HT.Dexterity.tweakDataPlayerPutOnMaskTime
        end
    end)

    pcall(function()
        _G.CloneClass(PlayerDamage)
        PlayerDamage.damage_fall = PlayerDamage.orig.damage_fall
    end)

    pcall(function()
        _G.CloneClass(PlayerStandard)
        PlayerStandard._get_swap_speed_multiplier = PlayerStandard.orig._get_swap_speed_multiplier
    end)

    pcall(function()
        _G.CloneClass(RaycastWeaponBase)
        RaycastWeaponBase.reload_speed_multiplier = RaycastWeaponBase.orig.reload_speed_multiplier
        _G.CloneClass(NewRaycastWeaponBase)
        NewRaycastWeaponBase.reload_speed_multiplier = NewRaycastWeaponBase.orig.reload_speed_multiplier
    end)

    pcall(function()
        _G.CloneClass(NewRaycastWeaponBase)
        NewRaycastWeaponBase.recoil_multiplier    = NewRaycastWeaponBase.orig.recoil_multiplier
        NewRaycastWeaponBase.spread_multiplier    = NewRaycastWeaponBase.orig.spread_multiplier
        NewRaycastWeaponBase.fire_rate_multiplier = NewRaycastWeaponBase.orig.fire_rate_multiplier
    end)

    pcall(function()
        _G.CloneClass(RaycastWeaponBase)
        RaycastWeaponBase.ammo_usage = RaycastWeaponBase.orig.ammo_usage
        _G.CloneClass(NewRaycastWeaponBase)
        NewRaycastWeaponBase.ammo_usage = NewRaycastWeaponBase.orig.ammo_usage
        pcall(function()
            _G.CloneClass(SawWeaponBase)
            SawWeaponBase.fire = SawWeaponBase.orig.fire
        end)
    end)

    pcall(function() HT.Dexterity:setShootThroughWalls(false, false) end)

    pcall(function()
        _G.CloneClass(BaseInteractionExt)
        BaseInteractionExt._get_timer = BaseInteractionExt.orig._get_timer
    end)

    pcall(function()
        _G.CloneClass(PlayerManager)
        PlayerManager.selected_equipment_deploy_timer = PlayerManager.orig.selected_equipment_deploy_timer
    end)

    pcall(function()
        _G.CloneClass(PlayerManager)
        PlayerManager.on_used_body_bag              = PlayerManager.orig.on_used_body_bag
        PlayerManager.remove_equipment              = PlayerManager.orig.remove_equipment
        PlayerManager.remove_special                = PlayerManager.orig.remove_special
    end)

    HT.Dexterity.enableNoclip = false
    HT.Dexterity.noclipAxisMove = {x=0, y=0, z=0}

    pcall(function()
        _G.CloneClass(PlayerManager)
        PlayerManager.movement_speed_multiplier = PlayerManager.orig.movement_speed_multiplier
    end)

    pcall(function()
        _G.CloneClass(CopDamage)
        CopDamage.damage_bullet = CopDamage.orig.damage_bullet
        CopDamage.damage_melee  = CopDamage.orig.damage_melee
    end)

    if HT:isInHeist() then
        HT.Mission.enableDisableAi = false
        pcall(function()
            for _, v in pairs(managers.enemy:all_civilians()) do
                pcall(function() v.unit:brain():set_active(true) end)
            end
            for _, v in pairs(managers.enemy:all_enemies()) do
                pcall(function() v.unit:brain():set_active(true) end)
            end
            if SecurityCamera and SecurityCamera.cameras then
                for _, u in pairs(SecurityCamera.cameras) do
                    pcall(function() u:base()._detection_interval = 0.1 end)
                end
            end
        end)

        HT.Mission.enableInvisiblePlayer = false
        pcall(function() HT.Mission:setInvisiblePlayer(false) end)

        pcall(function()
            _G.CloneClass(TimerGui)
            TimerGui._set_jamming_values = TimerGui.orig._set_jamming_values
            TimerGui._start              = TimerGui.orig._start
            if _G.SecurityLockGui and SecurityLockGui.orig then
                SecurityLockGui._start = SecurityLockGui.orig._start
            end
        end)

        pcall(function()
            _G.CloneClass(GroupAIStateBase)
            GroupAIStateBase.on_police_called = GroupAIStateBase.orig.on_police_called
        end)

        pcall(function() HT.Mission:setUnlimitedPagers(false) end)

        pcall(function()
            if managers.enemy then
                for _, d in pairs(managers.enemy:all_enemies())   do pcall(function() d.unit:contour():remove("mark_enemy", false) end) end
                for _, d in pairs(managers.enemy:all_civilians()) do pcall(function() d.unit:contour():remove("mark_enemy", false) end) end
            end
            if EnemyManager and EnemyManager.orig then
                _G.CloneClass(EnemyManager)
                EnemyManager.register_enemy    = EnemyManager.orig.register_enemy
                EnemyManager.register_civilian = EnemyManager.orig.register_civilian
                EnemyManager.on_enemy_died     = EnemyManager.orig.on_enemy_died
                EnemyManager.on_civilian_died  = EnemyManager.orig.on_civilian_died
            end
        end)

        pcall(function() HT.Mission:disableAutoCook() end)
    end

    -- Newer toggles that aren't covered by the dex/mission loops above. Each
    -- setX(false) restores its own tweak_data/hook and clears its flag.
    pcall(function() HT.Dexterity:setMeleeRange(false) end)
    pcall(function() HT.Dexterity:setMeleeDamageMultiplier(false, HT:getSetting("melee_damage_multiplier") or 10, false) end)
    pcall(function() HT.Dexterity:setOneShotKill(false) end)
    pcall(function() HT.Mission:setInstantConvert(false) end)
    pcall(function() HT.Mission:setFreezeCivilians(false) end)

    if HT.Extra then
        pcall(function() HT.Extra:setNoDelayMelee(false) end)
        pcall(function() HT.Extra:setHighJump(false) end)
        pcall(function() HT.Extra:setCopsDontShoot(false) end)
        pcall(function() HT.Extra:setPreventPanicButtons(false) end)
        pcall(function() HT.Extra:setDisableCameras(false) end)
        pcall(function() HT.Extra:setDisablePagers(false) end)
        pcall(function() HT.Extra:setAutoRevive(false) end)
        pcall(function() HT.Extra:setInfiniteBodyBags(false) end)
        pcall(function() HT.Extra:setInfiniteCableTies(false) end)
        pcall(function() HT.Extra:setNonConsumableEquipment(false) end)
    end

    -- Troll Menu toggles: clear flags/units, settings, and the menu checkboxes.
    if HT.TrollMenu then pcall(function() HT.TrollMenu:disableAll() end) end
    for _, t in ipairs(HT.Reset.troll_toggles) do
        HT:setSetting(t.setting, false)
        pcall(function() HT:setMenuToggle(t.id, false) end)
        pcall(function() HT:updateJsonValue("troll", t.id, false) end)
    end

    for _, id in ipairs({
        "ut_item_dexterity_toggle_melee_range",
        "ut_item_dexterity_toggle_melee_damage_multiplier",
        "ut_item_dexterity_toggle_one_shot_kill",
        "ut_item_mission_toggle_instant_convert",
        "ut_item_mission_toggle_freeze_civilians",
        "ut_item_extra_toggle_no_delay_melee",
        "ut_item_extra_toggle_high_jump",
        "ut_item_extra_toggle_cops_dont_shoot",
        "ut_item_extra_toggle_prevent_panic_buttons",
        "ut_item_extra_toggle_disable_cameras",
        "ut_item_extra_toggle_disable_pagers",
        "ut_item_extra_toggle_auto_revive",
        "ut_item_extra_toggle_infinite_body_bags",
        "ut_item_extra_toggle_infinite_cable_ties",
        "ut_item_extra_toggle_non_consumable_equipment",
    }) do
        pcall(function() HT:setMenuToggle(id, false) end)
    end

    HT:saveSettings()
    HT.Dexterity.godModeReset = false

    if not silent then
        HT:addAlert("All cheats reset", HT.colors.warning, false)
    end
end
