local statesOutft = {
    available = 0,
    store = 1,
    goldenOutfitTooltip = 2
}

local window = nil
local appearanceGroup = nil
local colorModeGroup = nil
local colorBoxGroup = nil

local floor = nil
local movementCheck = nil
local showFloorCheck = nil
local showOutfitCheck = nil
local showMountCheck = nil
local showWingsCheck = nil
local showAuraCheck = nil
local showShaderCheck = nil
local showBarsCheck = nil
local showTitleCheck = nil
local showEffectsCheck = nil
local showFamiliarCheck = nil
local colorBoxes = {}
local currentColorBox = nil

local previewCreature = nil
local previewFamiliar = nil

ignoreNextOutfitWindow = 0
local floorTiles = 7
local settingsFile = "/settings/outfit.json"
local settings = {}

local tempOutfit = {}
local ServerData = {
    currentOutfit = {},
    outfits = {},
    mounts = {},
    familiars = {},
    wings = {},
    auras = {},
    shaders = {},
    healthBars = {},
    effects = {},
    title = {}
}

local lastSelectAura = "None"
local lastSelectWings = "None"
local lastSelectEffects = 0
local lastSelectShader = "Outfit - Default"
local lastSelectTitle = "None"

local function checkPresetsValidity(presets)
    for i, preset in ipairs(presets) do
        if type(preset) == "number" and preset > 0 then
            return true
        end
    end
    return false
end

local function attachEffectIfValid(UICreature, value)
    local creature = UICreature:getCreature()
    if checkPresetsValidity({ value }) then
        if creature then
            creature:attachEffect(g_attachedEffects.getById(value))
        end
    end
end

local function attachOrDetachEffect(Id, attach)
    local creature = previewCreature:getCreature()
    if checkPresetsValidity({ Id }) then
        if creature then
            if attach then
                if not creature:getAttachedEffectById(Id) then
                    local effect = g_attachedEffects.getById(Id)
                    if effect then
                        creature:attachEffect(effect)
                    end
                end
            else
                creature:detachEffectById(Id)
            end
        end
    end
end

local function showSelectionList(data, tempValue, tempField, onSelectCallback)
    window.presetsList:hide()
    window.presetsScroll:hide()
    window.presetButtons:hide()

    window.selectionList.onChildFocusChange = nil
    window.selectionList:destroyChildren()

    local focused = nil
    do
        local button = g_ui.createWidget("SelectionButton", window.selectionList)
        button:setId("0")

        button.name:setText("None")
        if tempValue == 0 then
            focused = 0
        end
    end
    if data and #data > 0 then
        for _, itemData in ipairs(data) do
            local button = g_ui.createWidget("SelectionButton", window.selectionList)
            button:setId(tostring(itemData[1]))

            local Category = modules.game_attachedeffects.getCategory(itemData[1])
            if Category == 1 then
                button.outfit:setOutfit({
                    type = modules.game_attachedeffects.thingId(itemData[1])
                })

                button.outfit:setMarginBottom(15)
                button.outfit:setCenter(true)
            elseif Category == 2 then
                button.outfit:setOutfit(previewCreature:getCreature():getOutfit())
                button.outfit:getCreature():attachEffect(g_attachedEffects.getById(itemData[1]))
            elseif Category == 5 then
                button.outfit:setImageSource(modules.game_attachedeffects.getTexture(itemData[1]))
            end

            button.name:setText(modules.game_attachedeffects.getName(itemData[1]))
            if tempValue == itemData[1] then
                focused = (itemData[1])
            end
        end
    end
    if focused ~= nil then
        local w = window.selectionList[focused]
        w:focus()
        window.selectionList:ensureChildVisible(w, {
            x = 0,
            y = 196
        })
    end

    window.selectionList.onChildFocusChange = onSelectCallback
    window.selectionList:show()
    window.selectionScroll:show()
    window.listSearch:show()
end

local AppearanceData = { "preset", "outfit", "mount", "familiar", "wings", "aura", "effects", "shader", "healthBar",
    "title" }

function init()
    connect(g_game, {
        onOpenOutfitWindow = create,
        onGameEnd = destroy
    })
end

function terminate()
    disconnect(g_game, {
        onOpenOutfitWindow = create,
        onGameEnd = destroy
    })
    destroy()
end

function onOutfitChange(creature, outfit, oldOutfit)
    -- Dummy function to handle engine callbacks
    -- This prevents the "luaCallLuaField(onOutfitChange) is being called outside the context of the lua call" warnings
end

function onMovementChange(checkBox, checked)
    local walkingSpeed = checked and 1000 or 0

    local mainCreature = previewCreature:getCreature()
    if mainCreature then
        mainCreature:setStaticWalking(walkingSpeed)
    end

    if g_game.getFeature(GamePlayerFamiliars) then
        local familiarCreature = previewFamiliar:getCreature()
        if familiarCreature then
            familiarCreature:setStaticWalking(walkingSpeed)
        end
    end

    settings.movement = checked
end

function onShowFloorChange(checkBox, checked)
    if checked then
        floor:show()

        -- Magic!
        local delay = 50
        periodicalEvent(function()
            if movementCheck:isChecked() then
                local direction = previewCreature:getDirection()
                if direction == Directions.North then
                    local newMargin = floor:getMarginTop() + 8
                    floor:setMarginTop(newMargin)
                    if newMargin >= 96 then
                        for i = 1, floorTiles do
                            floor:moveChildToIndex(floor:getChildByIndex(floorTiles * floorTiles), 1)
                        end
                        floor:setMarginTop(32)
                    end
                elseif direction == Directions.South then
                    local newMargin = floor:getMarginBottom() + 8
                    floor:setMarginBottom(newMargin)
                    if newMargin >= 64 then
                        for i = 1, floorTiles do
                            floor:moveChildToIndex(floor:getChildByIndex(1), floorTiles * floorTiles)
                        end
                        floor:setMarginBottom(0)
                    end
                elseif direction == Directions.East then
                    local newMargin = floor:getMarginRight() + 8
                    floor:setMarginRight(newMargin)
                    if newMargin >= 64 then
                        floor:setMarginRight(0)
                    end
                elseif direction == Directions.West then
                    local newMargin = floor:getMarginLeft() + 8
                    floor:setMarginLeft(newMargin)
                    if newMargin >= 64 then
                        floor:setMarginLeft(0)
                    end
                end
            else
                floor:setMargin(0)
            end
        end, function()
            return window and floor and showFloorCheck:isChecked()
        end, delay, delay)
    else
        floor:hide()
    end

    settings.showFloor = checked
end

function onShowMountChange(checkBox, checked)
    settings.showMount = checked
    updatePreview()
end

function onShowFamiliarChange(checkBox, checked)
    settings.showFamiliar = checked
    updatePreview()
end

function onShowOutfitChange(checkBox, checked)
    settings.showOutfit = checked
    showMountCheck:setEnabled(settings.showOutfit)
    showFamiliarCheck:setEnabled(settings.showOutfit)
    showWingsCheck:setEnabled(settings.showOutfit)
    showAuraCheck:setEnabled(settings.showOutfit)
    showShaderCheck:setEnabled(settings.showOutfit)
    showBarsCheck:setEnabled(settings.showOutfit)
    showEffectsCheck:setEnabled(settings.showEffects)
    updatePreview()
end

function onShowAuraChange(checkBox, checked)
    settings.showAura = checked
    updatePreview()
end

function onShowWingsChange(checkBox, checked)
    settings.showWings = checked
    updatePreview()
end

function onShowShaderChange(checkBox, checked)
    settings.showShader = checked
    updatePreview()
end

function onShowTitleChange(checkBox, checked)
    settings.showTitle = checked
    updatePreview()
end

function onShowBarsChange(checkBox, checked)
    settings.showBars = checked
    updatePreview()
end

function onShowEffectsChange(checkBox, checked)
    settings.showEffects = checked
    updatePreview()
end

local PreviewOptions = {
    ["showFloor"] = onShowFloorChange,
    ["showOutfit"] = onShowOutfitChange,
    ["showMount"] = onShowMountChange,
    ["showFamiliar"] = onShowFamiliarChange,
    ["showWings"] = onShowWingsChange,
    ["showAura"] = onShowAuraChange,
    ["showShader"] = onShowShaderChange,
    ["showBars"] = onShowBarsChange,
    ["showTitle"] = onShowTitleChange,
    ["showEffects"] = onShowEffectsChange
}

function create(player, outfitList, creatureMount, mountList, familiarList, wingsList, auraList, effectsList, shaderList)
    if ignoreNextOutfitWindow and g_clock.millis() < ignoreNextOutfitWindow + 1000 then
        return
    end
    local currentOutfit = player:getOutfit()
    if window then
        destroy()
    end

    if currentOutfit.shader == "" then
        currentOutfit.shader = "Outfit - Default"
    end

    loadSettings()
    ServerData = {
        currentOutfit = currentOutfit,
        outfits = outfitList,
        mounts = mountList,
        familiars = familiarList,
        wings = wingsList,
        auras = auraList,
        effects = effectsList,
        shaders = shaderList
        --[[
        healthBars = barsList,
        title = titleList]]

    }

    window = g_ui.displayUI("outfitwindow")

    floor = window.preview.panel.floor
    for i = 1, floorTiles * floorTiles do
        g_ui.createWidget("FloorTile", floor)
    end
    floor:hide()

    for _, appKey in ipairs(AppearanceData) do
        updateAppearanceText(appKey, "None")
    end

    previewCreature = window.preview.panel.creature
    previewCreature:setCreatureSize(128)
    previewCreature:setCenter(true)

    previewFamiliar = window.preview.panel.UIfamiliar
    previewFamiliar:setCreatureSize(128)
    previewFamiliar:setCenter(true)
    -- previewCreature:setBorderColor('red')
    -- previewCreature:setBorderWidth(2)

    if settings.currentPreset == nil then
        loadDefaultSettings()
        print("game_outfit error funtion loadSettings()")
    end
    if settings.currentPreset > 0 then
        local preset = settings.presets[settings.currentPreset]
        tempOutfit = table.copy(preset.outfit)

        updateAppearanceText("preset", preset.title)
    else
        tempOutfit = currentOutfit
    end

    updatePreview()

    updateAppearanceTexts(currentOutfit)

    if g_game.getFeature(GamePlayerMounts) then
        local isMount = g_game.getLocalPlayer():isMounted()
        if isMount then
            window.configure.mount.check:setEnabled(true)
            window.configure.mount.check:setChecked(true)
        else
            window.configure.mount.check:setEnabled(currentOutfit.mount > 0)
            window.configure.mount.check:setChecked(isMount and currentOutfit.mount > 0)
        end
    end

    window.configure.addon1.check:setChecked(bit.band(currentOutfit.addons, 1) ~= 0)
    window.configure.addon2.check:setChecked(bit.band(currentOutfit.addons, 2) ~= 0)
    window.configure.addon1.check.onCheckChange = onAddonChange
    window.configure.addon2.check.onCheckChange = onAddonChange

    configureAddons(currentOutfit.addons)

    movementCheck = window.preview.panel.movement
    showFloorCheck = window.preview.options.showFloor.check
    showOutfitCheck = window.preview.options.showOutfit.check
    showMountCheck = window.preview.options.showMount.check
    showFamiliarCheck = window.preview.options.showFamiliar.check
    showWingsCheck = window.preview.options.showWings.check
    showAuraCheck = window.preview.options.showAura.check
    showShaderCheck = window.preview.options.showShader.check
    showBarsCheck = window.preview.options.showBars.check
    showEffectsCheck = window.preview.options.showEffects.check
    showTitleCheck = window.preview.options.showTitle.check

    movementCheck.onCheckChange = onMovementChange
    for _, option in ipairs(window.preview.options:getChildren()) do
        option.check.onCheckChange = PreviewOptions[option:getId()]
    end

    movementCheck:setChecked(settings.movement)
    showFloorCheck:setChecked(settings.showFloor)

    if not settings.showOutfit then
        showMountCheck:setEnabled(false)
        showFamiliarCheck:setEnabled(false)
        showWingsCheck:setEnabled(false)
        showAuraCheck:setEnabled(false)
        showShaderCheck:setEnabled(false)
        showBarsCheck:setEnabled(false)
        showTitleCheck:setEnabled(false)
        showEffectsCheck:setEnabled(false)
    end

    showOutfitCheck:setChecked(settings.showOutfit)
    showMountCheck:setChecked(settings.showMount)
    showFamiliarCheck:setChecked(settings.showFamiliar)
    showWingsCheck:setChecked(settings.showWings)
    showAuraCheck:setChecked(settings.showAura)
    showShaderCheck:setChecked(settings.showShader)
    showBarsCheck:setChecked(settings.showBars)
    showEffectsCheck:setChecked(settings.showEffects)
    showTitleCheck:setChecked(settings.showTitle)

    colorBoxGroup = UIRadioGroup.create()
    for j = 0, 6 do
        for i = 0, 18 do
            local colorBox = g_ui.createWidget("ColorBox", window.appearance.colorBoxPanel)
            local outfitColor = getOutfitColor(j * 19 + i)
            colorBox:setBackgroundColor(outfitColor)
            colorBox:setId("colorBox" .. j * 19 + i)
            colorBox.colorId = j * 19 + i

            if colorBox.colorId == currentOutfit.head then
                currentColorBox = colorBox
                colorBox:setChecked(true)
            end
            colorBoxGroup:addWidget(colorBox)
        end
    end

    colorBoxGroup.onSelectionChange = onColorCheckChange

    appearanceGroup = UIRadioGroup.create()
    appearanceGroup:addWidget(window.appearance.settings.preset.check)
    appearanceGroup:addWidget(window.appearance.settings.outfit.check)
    appearanceGroup:addWidget(window.appearance.settings.mount.check)
    appearanceGroup:addWidget(window.appearance.settings.familiar.check)
    appearanceGroup:addWidget(window.appearance.settings.aura.check)
    appearanceGroup:addWidget(window.appearance.settings.wings.check)
    appearanceGroup:addWidget(window.appearance.settings.shader.check)
    appearanceGroup:addWidget(window.appearance.settings.healthBar.check)
    appearanceGroup:addWidget(window.appearance.settings.effects.check)
    appearanceGroup:addWidget(window.appearance.settings.title.check)
    appearanceGroup.onSelectionChange = onAppearanceChange
    appearanceGroup:selectWidget(window.appearance.settings.preset.check)

    colorModeGroup = UIRadioGroup.create()
    colorModeGroup:addWidget(window.appearance.colorMode.head)
    colorModeGroup:addWidget(window.appearance.colorMode.primary)
    colorModeGroup:addWidget(window.appearance.colorMode.secondary)
    colorModeGroup:addWidget(window.appearance.colorMode.detail)

    colorModeGroup.onSelectionChange = onColorModeChange
    colorModeGroup:selectWidget(window.appearance.colorMode.head)

    window.preview.options.showMount:setVisible(g_game.getFeature(GamePlayerMounts))
    window.configure.mount:setVisible(g_game.getFeature(GamePlayerMounts))
    window.appearance.settings.mount:setVisible(g_game.getFeature(GamePlayerMounts))

    window.preview.options.showFamiliar:setVisible(g_game.getFeature(GamePlayerFamiliars))
    window.appearance.settings.familiar:setVisible(g_game.getFeature(GamePlayerFamiliars))

    local checks = {
        { window.preview.options.showWings,     ServerData.wings },
        { window.preview.options.showAura,      ServerData.auras },
        { window.preview.options.showShader,    ServerData.shaders },
        { window.preview.options.showBars,      ServerData.healthBars },
        { window.preview.options.showEffects,   ServerData.effects },
        { window.preview.options.showTitle,     ServerData.title },
        { window.preview.options.showFamiliar,  ServerData.familiars },
        { window.appearance.settings.familiar,  ServerData.familiars },
        { window.appearance.settings.wings,     ServerData.wings },
        { window.appearance.settings.aura,      ServerData.auras },
        { window.appearance.settings.shader,    ServerData.shaders },
        { window.appearance.settings.healthBar, ServerData.healthBars },
        { window.appearance.settings.effects,   ServerData.effects },
        { window.appearance.settings.title,     ServerData.title },
    }

    for _, check in ipairs(checks) do
        local widget, data = check[1], check[2]
        if not table.empty(data) then
            widget:setVisible(true)
        else
            widget:setVisible(false)
        end
    end
    previewCreature:getCreature():setDirection(2)
    window.listSearch.search.onKeyPress = onFilterSearch
    window.listSearch.onlyMine.onCheckChange = onFilterOnlyMine
end

function destroy()
    if window then
        floor = nil
        movementCheck = nil
        showFloorCheck = nil
        showOutfitCheck = nil
        showMountCheck = nil
        showFamiliarCheck = nil
        showWingsCheck = nil
        showAuraCheck = nil
        showShaderCheck = nil
        showBarsCheck = nil
        showEffectsCheck = nil
        showTitleCheck = nil
        colorBoxes = {}
        currentColorBox = nil
        previewCreature:destroy()
        previewCreature = nil
        if previewFamiliar then
            previewFamiliar:destroy()
            previewFamiliar = nil
        end
        if appearanceGroup then
            appearanceGroup:destroy()
            appearanceGroup = nil
        end
        colorModeGroup:destroy()
        colorModeGroup = nil
        colorBoxGroup:destroy()
        colorBoxGroup = nil

        ServerData = {
            currentOutfit = {},
            outfits = {},
            mounts = {},
            familiars = {},
            wings = {},
            auras = {},
            shaders = {},
            healthBars = {},
            effects = {},
            title = {}
        }

        saveSettings()
        settings = {}
        window:destroy()
        window = nil
        lastSelectAura = "None"
        lastSelectWings = "None"
        lastSelectEffects = 0
        lastSelectShader = "Outfit - Default"
    end
end

function configureAddons(addons)
    local hasAddon1 = bit.band(addons, 1) ~= 0
    local hasAddon2 = bit.band(addons, 2) ~= 0
    window.configure.addon1.check:setEnabled(hasAddon1)
    window.configure.addon2.check:setEnabled(hasAddon2)

    window.configure.addon1.check.onCheckChange = nil
    window.configure.addon2.check.onCheckChange = nil
    window.configure.addon1.check:setChecked(bit.band(tempOutfit.addons, 1) ~= 0)
    window.configure.addon2.check:setChecked(bit.band(tempOutfit.addons, 2) ~= 0)
    window.configure.addon1.check.onCheckChange = onAddonChange
    window.configure.addon2.check.onCheckChange = onAddonChange
end

function newPreset()
    if not settings.presets then
        settings.presets = {}
    end

    local presetWidget = g_ui.createWidget("PresetButton", window.presetsList)
    local presetId = #settings.presets + 1
    presetWidget:setId(presetId)
    presetWidget.title:setText("New Preset")
    local outfitCopy = table.copy(tempOutfit)
    presetWidget.creature:setOutfit(outfitCopy)
    --  presetWidget.creature:setCenter(true)

    settings.presets[presetId] = {
        title = "New Preset",
        outfit = outfitCopy,
        aura = "None",
        effects = 0,
        wings = "None",
        shader = "None",
        mounted = window.configure.mount.check:isChecked(),
        familiar = "None"
    }

    presetWidget:focus()
    window.presetsList:ensureChildVisible(presetWidget, {
        x = 0,
        y = 196
    })

    lastSelectAura = "None"
    lastSelectWings = "None"
    lastSelectEffects = 0
    lastSelectShader = "Outfit - Default"
    lastSelectTitle = "None"
end

function deletePreset()
    local presetId = settings.currentPreset
    if presetId == 0 then
        local focused = window.presetsList:getFocusedChild()
        if focused then
            presetId = tonumber(focused:getId())
        end
    end

    if not presetId or presetId == 0 then
        return
    end

    table.remove(settings.presets, presetId)
    window.presetsList[presetId]:destroy()
    settings.currentPreset = 0
    local newId = 1
    for _, child in ipairs(window.presetsList:getChildren()) do
        child:setId(newId)
        newId = newId + 1
    end

    if previewCreature then
        local creature = previewCreature:getCreature()
        if creature then
            creature:clearAttachedEffects()
            creature:setShader("Outfit - Default")
        end
    end
    updateAppearanceText("preset", "None")
    updateAppearanceText("shader", "Outfit - Default")
    updateAppearanceText("aura", "None")
    updateAppearanceText("wings", "None")
    updateAppearanceText("effects", "None")
end

function savePreset()
    local presetId = settings.currentPreset
    if presetId == 0 then
        local focused = window.presetsList:getFocusedChild()
        if focused then
            presetId = tonumber(focused:getId())
        end
    end

    if not presetId or presetId == 0 then
        return
    end

    window.presetsList[presetId].creature:getCreature():clearAttachedEffects()
    local outfitCopy = table.copy(tempOutfit)

    window.presetsList[presetId].creature:setOutfit(outfitCopy)

    settings.presets[presetId].outfit = outfitCopy
    settings.presets[presetId].mounted = window.configure.mount.check:isChecked()
    settings.presets[presetId].familiar = tempOutfit.familiar or 0
    settings.presets[presetId].shader = "Outfit - Default"
    settings.presets[presetId].auras = lastSelectAura or "None"
    settings.presets[presetId].effects = lastSelectEffects or 0
    settings.presets[presetId].wings = lastSelectWings or "None"
    settings.presets[presetId].shaders = lastSelectShader or "None"

    settings.currentPreset = presetId

    attachEffectIfValid(window.presetsList[presetId].creature, lastSelectAura)
    attachEffectIfValid(window.presetsList[presetId].creature, lastSelectEffects)
    attachEffectIfValid(window.presetsList[presetId].creature, lastSelectWings)
    local presets = { lastSelectAura, lastSelectEffects, lastSelectWings }
    local hasValidAE = checkPresetsValidity(presets)
    local thingType = g_things.getThingType(tempOutfit.type, ThingCategoryCreature)

    if (hasValidAE and window.presetsList[presetId].creature:getCreatureSize() == 0) then
        -- TODO: Try changing square clipping size from Mehah PR
        window.presetsList[presetId].creature:setCreatureSize(thingType:getRealSize())
        window.presetsList[presetId].creature:setCenter(true)
    elseif not g_game.getFeature(GameWingsAurasEffectsShader) then
        window.presetsList[presetId].creature:setCreatureSize(thingType:getRealSize() + 32)
        window.presetsList[presetId].creature:setCenter(true)
    else
        window.presetsList[presetId].creature:setCreatureSize(thingType:getRealSize())
        window.presetsList[presetId].creature:setCenter(true)
    end



    if lastSelectShader ~= "None" and lastSelectShader ~= nil then
        if window.presetsList[presetId].creature then
            local creature = window.presetsList[presetId].creature:getCreature()
            if creature then
                creature:setShader(lastSelectShader)
            end
        end
    end

    --[[     if lastSelectTitle ~= "None" then
        window.presetsList[presetId].creature:getCreature():setTitle(lastSelectTitle, "verdana-11px-rounded", "#0000ff")
    end ]]
    -- @
end

function renamePreset()
    local presetId = settings.currentPreset
    if presetId == 0 then
        local focused = window.presetsList:getFocusedChild()
        if focused then
            presetId = tonumber(focused:getId())
        end
    end

    if not presetId or presetId == 0 then
        return
    end

    local presetWidget = window.presetsList[presetId]
    presetWidget.title:hide()
    presetWidget.rename.input:setText("")
    presetWidget.rename.save.onClick = function()
        saveRename(presetId)
    end
    presetWidget.rename:show()
end

function saveRename(presetId)
    local presetWidget = window.presetsList[presetId]
    if not presetWidget then
        return
    end

    local newTitle = presetWidget.rename.input:getText():trim()
    presetWidget.rename.input:setText("")
    presetWidget.rename:hide()
    presetWidget.title:setText(newTitle)
    presetWidget.title:show()
    settings.presets[presetId].title = newTitle

    if presetId == settings.currentPreset then
        updateAppearanceText("preset", newTitle)
    end
end

function onAppearanceChange(widget, selectedWidget)
    local id = selectedWidget:getParent():getId()
    if id == "preset" then
        showPresets()
    elseif id == "outfit" then
        showOutfits()
    elseif id == "mount" then
        showMounts()
    elseif id == "familiar" then
        showFamiliars()
    elseif id == "aura" then
        showSelectionList(ServerData.auras, tempOutfit.auras, "aura", onAuraSelect)
    elseif id == "wings" then
        showSelectionList(ServerData.wings, tempOutfit.wings, "wings", onWingsSelect)
    elseif id == "effects" then
        showSelectionList(ServerData.effects, tempOutfit.effects, "effects", onEffectBarSelect)
        -- strings
    elseif id == "shader" then
        showShaders()
    elseif id == "healthBar" then
        showHealthBars()
    elseif id == "title" then
        showTitle()
    end
end

function showPresets()
    window.listSearch:hide()
    window.selectionList:hide()
    window.selectionScroll:hide()

    local focused = nil
    if window.presetsList:getChildCount() == 0 and settings.presets then
        for presetId, preset in ipairs(settings.presets) do
            local presetWidget = g_ui.createWidget("PresetButton", window.presetsList)
            presetWidget:setId(presetId)
            presetWidget.title:setText(preset.title)
            presetWidget.creature:setOutfit(preset.outfit)

            attachEffectIfValid(presetWidget.creature, preset.auras)
            attachEffectIfValid(presetWidget.creature, preset.effects)
            attachEffectIfValid(presetWidget.creature, preset.wings)

            local presets = { preset.auras, preset.effects, preset.wings }
            local hasValidAE = checkPresetsValidity(presets)
            local thingType = g_things.getThingType(tempOutfit.type, ThingCategoryCreature)

            if (hasValidAE and presetWidget.creature:getCreatureSize() == 0) then
                -- TODO: Try changing square clipping size from Mehah PR
                presetWidget.creature:setCenter(true)
            elseif not g_game.getFeature(GameWingsAurasEffectsShader) then
                presetWidget.creature:setCreatureSize(thingType:getRealSize() + 32)
                presetWidget.creature:setCenter(true)
            else
                presetWidget.creature:setCenter(true)
            end

            if preset.shaders ~= "None" then
                presetWidget.creature:getCreature():setShader(preset.shaders)
                lastSelectShader = preset.shaders
            end

            if presetId == settings.currentPreset then
                focused = presetId
            end
        end
    end

    if focused then
        local w = window.presetsList[focused]

        w:focus()
        window.presetsList:ensureChildVisible(w, {
            x = 0,
            y = 196
        })
        onPresetSelect(nil, window.presetsList[focused])
    end

    window.presetsList.onChildFocusChange = onPresetSelect
    window.presetsList:show()
    window.presetsScroll:show()
    window.presetButtons:show()
end

function showOutfits()
    window.presetsList:hide()
    window.presetsScroll:hide()
    window.presetButtons:hide()

    window.selectionList.onChildFocusChange = nil
    window.selectionList:destroyChildren()

    local focused = nil
    for _, outfitData in ipairs(ServerData.outfits) do
        local button = g_ui.createWidget("SelectionButton", window.selectionList)
        button:setId(outfitData[1])

        local outfit = table.copy(previewCreature:getCreature():getOutfit())
        outfit.type = outfitData[1]
        outfit.addons = bit.band(outfitData[3], 3)
        outfit.mount = 0
        outfit.familiar = 0
        outfit.auras = 0
        outfit.wings = 0
        outfit.shader = "Outfit - Default"
        outfit.healthBar = 0
        outfit.effects = 0
        button.outfit:setOutfit(outfit)

        button.outfit:setCenter(true)

        local state = outfitData[4]
        if state then
            button.state = state
            if state ~= statesOutft.available then
                button:setImageSource("/images/ui/button-blue-qt")
            end
        end

        button.name:setText(outfitData[2])
        if tempOutfit.type == outfitData[1] then
            focused = outfitData[1]
            configureAddons(outfitData[3])
        end
    end

    if focused then
        local w = window.selectionList[focused]
        w:focus()
        window.selectionList:ensureChildVisible(w, {
            x = 0,
            y = 196
        })
    end

    window.selectionList.onChildFocusChange = onOutfitSelect
    window.selectionList:show()
    window.selectionScroll:show()
    window.listSearch:show()
end

function showMounts()
    window.presetsList:hide()
    window.presetsScroll:hide()
    window.presetButtons:hide()

    window.selectionList.onChildFocusChange = nil
    window.selectionList:destroyChildren()

    local focused = nil

    local button = g_ui.createWidget("SelectionButton", window.selectionList)
    button:setId(0)
    button.name:setText("None")
    button.state = 0
    focused = 0

    for _, mountData in ipairs(ServerData.mounts) do
        local button = g_ui.createWidget("SelectionButton", window.selectionList)
        button:setId(mountData[1])

        button.outfit:setOutfit({
            type = mountData[1]
        })

        button.outfit:setCenter(true)

        button.name:setText(mountData[2])
        if tempOutfit.mount == mountData[1] then
            focused = mountData[1]
        end

        local state = mountData[3]
        if state then
            button.state = state
            if state ~= statesOutft.available then
                button:setImageSource("/images/ui/button-blue-qt")
            end
        end
    end

    if #ServerData.mounts == 1 then
        window.selectionList:focusChild(nil)
    end

    window.configure.mount.check:setEnabled(focused)
    window.configure.mount.check:setChecked(g_game.getLocalPlayer():isMounted() and focused)

    if focused ~= nil then
        local w = window.selectionList[focused]
        w:focus()
        window.selectionList:ensureChildVisible(w, {
            x = 0,
            y = 196
        })
    end

    window.selectionList.onChildFocusChange = onMountSelect
    window.selectionList:show()
    window.selectionScroll:show()
    window.listSearch:show()
end

function showFamiliars()
    window.presetsList:hide()
    window.presetsScroll:hide()
    window.presetButtons:hide()

    window.selectionList.onChildFocusChange = nil
    window.selectionList:destroyChildren()

    local focused = nil

    local button = g_ui.createWidget("SelectionButton", window.selectionList)
    button:setId(0)
    button.name:setText("None")
    focused = 0
    for _, familiarData in ipairs(ServerData.familiars) do
        local button = g_ui.createWidget("SelectionButton", window.selectionList)
        button:setId(familiarData[1])

        button.outfit:setOutfit({
            type = familiarData[1]
        })

        button.name:setText(familiarData[2])

        button.outfit:setCenter(true)

        if tempOutfit.familiar == familiarData[1] then
            focused = familiarData[1]
        end
    end

    if #ServerData.familiars == 1 then
        window.selectionList:focusChild(nil)
    end

    if focused then
        local w = window.selectionList[focused]
        w:focus()
        window.selectionList:ensureChildVisible(w, {
            x = 0,
            y = 196
        })
    end

    window.selectionList.onChildFocusChange = onFamiliarSelect
    window.selectionList:show()
    window.selectionScroll:show()
    window.listSearch:show()
end

function showShaders()
    window.presetsList:hide()
    window.presetsScroll:hide()
    window.presetButtons:hide()

    window.selectionList.onChildFocusChange = nil
    window.selectionList:destroyChildren()

    local focused = nil
    do
        local button = g_ui.createWidget("SelectionButton", window.selectionList)
        button:setId("Outfit - Default")

        button.outfit:setOutfit({
            type = tempOutfit.type,
            addons = tempOutfit.addons
        })

        button.outfit:setCenter(true)

        button.outfit:getCreature():setShader("Outfit - Default")
        button.name:setText("Outfit - Default")
        if tempOutfit.shaders == "Outfit - Default" then
            focused = "Outfit - Default"
        end
    end

    if ServerData.shaders and #ServerData.shaders > 0 then
        for _, shaderData in ipairs(ServerData.shaders) do
            local button = g_ui.createWidget("SelectionButton", window.selectionList)
            button:setId(shaderData[2])

            button.outfit:setOutfit({
                type = tempOutfit.type,
                addons = tempOutfit.addons

            })

            button.outfit:setCenter(true)

            button.outfit:getCreature():setShader(shaderData[2])

            button.name:setText(shaderData[2])

            if tempOutfit.shaders == shaderData[2] then
                focused = shaderData[2]
            end
        end
    end
    if focused ~= nil then
        local w = window.selectionList[focused]
        w:focus()
        window.selectionList:ensureChildVisible(w, {
            x = 0,
            y = 196
        })
    end

    window.selectionList.onChildFocusChange = onShaderSelect
    window.selectionList:show()
    window.selectionScroll:show()
    window.listSearch:show()
end

function showHealthBars()
    window.presetsList:hide()
    window.presetsScroll:hide()
    window.presetButtons:hide()

    window.selectionList.onChildFocusChange = nil
    window.selectionList:destroyChildren()

    local focused = nil
    do
        local button = g_ui.createWidget("SelectionButton", window.selectionList)
        button:setId("0")

        button.outfit:hide()
        button.name:setText("None")
        if tempOutfit.healthBar == 0 then
            focused = 0
        end
    end
    if ServerData.healthBars and #ServerData.healthBars > 0 then
        for _, barData in ipairs(ServerData.healthBars) do
            local button = g_ui.createWidget("SelectionButton", window.selectionList)
            button:setId(barData)

            local Category = modules.game_attachedeffects.getCategory(barData)
            if Category == 5 then
                button.outfit:setImageSource(modules.game_attachedeffects.getTexture(barData))
                button.outfit:setWidth(64)
                button.outfit:setHeight(32)
            else
                button.outfit:setOutfit(previewCreature:getCreature():getOutfit())
                button.outfit:getCreature():attachEffect(g_attachedEffects.getById(barData))
            end

            button.bar:show()

            button.name:setText(barData)
            if tempOutfit.healthBar == barData then
                focused = barData
            end
        end
    end
    if focused ~= nil then
        local w = window.selectionList[focused]
        w:focus()
        window.selectionList:ensureChildVisible(w, {
            x = 0,
            y = 196
        })
    end

    window.selectionList.onChildFocusChange = onHealthBarSelect
    window.selectionList:show()
    window.selectionScroll:show()
    window.listSearch:show()
end

function showTitle()
    window.presetsList:hide()
    window.presetsScroll:hide()
    window.presetButtons:hide()

    window.selectionList.onChildFocusChange = nil
    window.selectionList:destroyChildren()

    local focused = nil
    do
        local button = g_ui.createWidget("SelectionButton", window.selectionList)
        button:setId("0")


        button.name:setText("None")
        if tempOutfit.tile == 0 then
            focused = 0
        end
    end
    if ServerData.title and #ServerData.title > 0 then
        for _, titleData in ipairs(ServerData.title) do
            local button = g_ui.createWidget("SelectionButton", window.selectionList)
            button:setId(tostring(titleData))

            button.outfit:setOutfit(previewCreature:getCreature():getOutfit())
            button.outfit:getCreature():getCreature():setTitle(titleData, "verdana-11px-rounded", "#0000ff")

            button.name:setText(tostring(titleData))
            if tempOutfit.tile == titleData then
                focused = tostring(titleData)
            end
        end
    end
    if focused ~= nil then
        local w = window.selectionList[focused]
        w:focus()
        window.selectionList:ensureChildVisible(w, {
            x = 0,
            y = 196
        })
    end

    window.selectionList.onChildFocusChange = onTitleSelect
    window.selectionList:show()
    window.selectionScroll:show()
    window.listSearch:show()
end

function onPresetSelect(list, focusedChild, unfocusedChild, reason)
    if focusedChild then
        local presetId = tonumber(focusedChild:getId())
        local preset = settings.presets[presetId]
        tempOutfit = table.copy(preset.outfit)

        for _, outfitData in ipairs(ServerData.outfits) do
            if tempOutfit.type == outfitData[1] then
                configureAddons(outfitData[3])
                break
            end
        end

        if g_game.getFeature(GamePlayerMounts) then
            window.configure.mount.check:setChecked(preset.mounted and tempOutfit.mount > 0)
        end

        settings.currentPreset = presetId

        updatePreview()

        updateAppearanceTexts(tempOutfit)

        updateAppearanceText("preset", preset.title)
        if g_game.getFeature(GameWingsAurasEffectsShader) then
            updateAppearanceText("aura", modules.game_attachedeffects.getName(preset.auras))
            updateAppearanceText("wings", modules.game_attachedeffects.getName(preset.wings))
            updateAppearanceText("shader", preset.shaders or "Outfit - Default")
            updateAppearanceText("effects", modules.game_attachedeffects.getName(preset.effects))
        end

        previewCreature:getCreature():clearAttachedEffects()

        if settings.showEffects and preset.effects then
            attachEffectIfValid(previewCreature, preset.effects)
        end

        if settings.showWings and preset.wings then
            attachEffectIfValid(previewCreature, preset.wings)
        end

        if settings.showAura and preset.auras then
            attachEffectIfValid(previewCreature, preset.auras)
        end

        if not settings.showShader or preset.shaders == "None" then
            if previewCreature then
                local creature = previewCreature:getCreature()
                if creature then
                    creature:setShader("Outfit - Default")
                end
            end
        else
            if previewCreature then
                local creature = previewCreature:getCreature()
                if creature then
                    creature:setShader(preset.shaders)
                end
            end
        end

        tempOutfit.wings = preset.wings
        tempOutfit.auras = preset.auras
        tempOutfit.shaders = preset.shaders
        tempOutfit.effects = preset.effects
        lastSelectAura = preset.auras
        lastSelectWings = preset.wings
        lastSelectEffects = preset.effects
        lastSelectShader = preset.shaders
    end
end

function onOutfitSelect(list, focusedChild, unfocusedChild, reason)
    if focusedChild then
        local outfitType = tonumber(focusedChild:getId())
        local outfit = focusedChild.outfit:getCreature():getOutfit()
        tempOutfit.type = outfit.type
        tempOutfit.addons = bit.band(outfit.addons, 3)

        deselectPreset()

        configureAddons(outfit.addons)

        if showOutfitCheck:isChecked() then
            updatePreview()
        end
        updateAppearanceText("outfit", focusedChild.name:getText())
    end
end

function onMountSelect(list, focusedChild, unfocusedChild, reason)
    if focusedChild then
        local mountType = tonumber(focusedChild:getId())
        tempOutfit.mount = mountType

        deselectPreset()

        if showMountCheck:isChecked() then
            updatePreview()
        end

        window.configure.mount.check:setEnabled(tempOutfit.mount > 0)
        window.configure.mount.check:setChecked(g_game.getLocalPlayer():isMounted() and tempOutfit.mount > 0)

        updateAppearanceText("mount", focusedChild.name:getText())
    end
end

function onFamiliarSelect(list, focusedChild, unfocusedChild, reason)
    if focusedChild then
        local familiarType = tonumber(focusedChild:getId())

        tempOutfit.familiar = familiarType

        deselectPreset()

        -- Only set outfit if familiarType is valid (not 0/None)
        if familiarType and familiarType > 0 then
            previewFamiliar:setOutfit({
                type = familiarType
            })
        else
            -- Hide/clear the familiar when "None" is selected
            previewFamiliar:setVisible(false)
        end

        updatePreview()

        if settings.showFamiliar and g_game.getFeature(GamePlayerFamiliars) and familiarType ~= nil and familiarType > 0 then
            previewCreature:setMarginRight(50)
            previewFamiliar:setCreatureSize(124)
            previewFamiliar:setCenter(true)
            previewFamiliar:setMarginLeft(70)
        else
            previewCreature:setMarginRight(0)
            previewFamiliar:setMarginLeft(0)
            window.preview.panel.bars:setMarginRight(20)
        end

        updateAppearanceText("familiar", focusedChild.name:getText())
    end
end

function onAuraSelect(list, focusedChild, unfocusedChild, reason)
    local auraName = window.appearance.settings["aura"].name:getText()
    if auraName ~= "None" then
        local auraId = tonumber(lastSelectAura)
        if auraId then
            previewCreature:getCreature():detachEffectById(auraId)
        end
    end
    if focusedChild then
        local auraType = tonumber(focusedChild:getId())

        if checkPresetsValidity({ auraType }) then
            previewCreature:getCreature():attachEffect(g_attachedEffects.getById(auraType))
            lastSelectAura = auraType
            tempOutfit.auras = auraType
            updatePreview()
            deselectPreset()
            updateAppearanceText("aura", modules.game_attachedeffects.getName(auraType))
        else
            lastSelectAura = "None"
            tempOutfit.auras = 0
            updateAppearanceText("aura", "None")
        end
    end
end

function onWingsSelect(list, focusedChild, unfocusedChild, reason)
    local wingsName = window.appearance.settings["wings"].name:getText()
    if wingsName ~= "None" then
        local wingsId = tonumber(lastSelectWings)
        if wingsId then
            previewCreature:getCreature():detachEffectById(wingsId)
        end
    end

    if focusedChild then
        local wingsType = tonumber(focusedChild:getId())

        if checkPresetsValidity({ wingsType }) then
            previewCreature:getCreature():attachEffect(g_attachedEffects.getById(wingsType))
            lastSelectWings = wingsType
            tempOutfit.wings = wingsType
            updatePreview()
            deselectPreset()
            updateAppearanceText("wings", modules.game_attachedeffects.getName(wingsType))
        else
            lastSelectWings = "None"
            tempOutfit.wings = 0
            updateAppearanceText("wings", "None")
        end
    end
end

function onShaderSelect(list, focusedChild, unfocusedChild, reason)
    if focusedChild then
        local shaderType = focusedChild:getId()
        if previewCreature then
            local creature = previewCreature:getCreature()
            if creature then
                if shaderType ~= "None" then
                    -- Enable shader display when selecting a shader
                    settings.showShader = true
                    -- Update checkbox without triggering event
                    if showShaderCheck then
                        showShaderCheck.onCheckChange = nil
                        showShaderCheck:setChecked(true)
                        showShaderCheck.onCheckChange = onShowShaderChange
                    end

                    lastSelectShader = shaderType
                    tempOutfit.shaders = shaderType
                    creature:setShader(shaderType)
                else
                    lastSelectShader = "Outfit - Default"
                    tempOutfit.shaders = "Outfit - Default"
                    creature:setShader("Outfit - Default")
                end
            end
        end

        deselectPreset()

        updateAppearanceText("shader", focusedChild.name:getText())
    end
end

function onHealthBarSelect(list, focusedChild, unfocusedChild, reason)
    if window.appearance.settings["healthBar"].name:getText() ~= "None" then
        previewCreature:getCreature():detachEffectById(tonumber(window.appearance.settings["healthBar"].name:getText()))
    end
    if focusedChild then
        local barType = tonumber(focusedChild:getId())
        tempOutfit.healthBar = barType
        updatePreview()
        if barType > 0 then
            previewCreature:getCreature():attachEffect(g_attachedEffects.getById(barType))
        end

        deselectPreset()

        updateAppearanceText("healthBar", focusedChild.name:getText())
    end
end

function onEffectBarSelect(list, focusedChild, unfocusedChild, reason)
    local effectName = window.appearance.settings["effects"].name:getText()
    if effectName ~= "None" then
        local effectId = tonumber(lastSelectEffects)
        if effectId then
            previewCreature:getCreature():detachEffectById(effectId)
        end
    end

    if focusedChild then
        local effect_id = tonumber(focusedChild:getId())

        if checkPresetsValidity({ effect_id }) then
            previewCreature:getCreature():attachEffect(g_attachedEffects.getById(effect_id))
            lastSelectEffects = effect_id
            tempOutfit.effects = effect_id
            updatePreview()
            deselectPreset()
            updateAppearanceText("effects", modules.game_attachedeffects.getName(effect_id))
        else
            lastSelectEffects = 0
            tempOutfit.effects = 0
            updateAppearanceText("effects", "None")
        end
    end
end

function onTitleSelect(list, focusedChild, unfocusedChild, reason)
    if window.appearance.settings["title"].name:getText() ~= "None" then
        previewCreature:getCreature():clearTitle()
    end

    if focusedChild then
        local titleType = tostring(focusedChild:getId())

        if titleType ~= "None" then
            previewCreature:getCreature():setTitle(titleType, "verdana-11px-rounded", "#0000ff")
            lastSelectTitle = titleType
        else
            lastSelectTitle = "None"
            previewCreature:getCreature():clearTitle()
        end

        updatePreview()
        deselectPreset()
        updateAppearanceText("title", focusedChild.name:getText())
    end
end

function updateAppearanceText(widget, text)
    if window.appearance.settings[widget] then
        window.appearance.settings[widget].name:setText(text)
    end
end

function updateAppearanceTexts(outfit)
    for _, appKey in ipairs(AppearanceData) do
        updateAppearanceText(appKey, "None")
    end

    for key, value in pairs(outfit) do
        local newKey = key
        local appKey = key
        if key == "type" then
            newKey = "outfits"
            appKey = "outfit"
        end
        local dataTable = ServerData[newKey]
        if dataTable then
            for _, data in ipairs(dataTable) do
                if outfit[key] == data[1] or outfit[key] == data[2] then
                    if appKey and data[2] then
                        updateAppearanceText(appKey, data[2])
                    end
                end
            end
        end
    end
end

function deselectPreset()
    settings.currentPreset = 0
end

function onAddonChange(widget, checked)
    local addonId = widget:getParent():getId()

    local addons = tempOutfit.addons
    if addonId == "addon1" then
        addons = checked and bit.bor(addons, 1) or bit.band(addons, bit.bnot(1))
    elseif addonId == "addon2" then
        addons = checked and bit.bor(addons, 2) or bit.band(addons, bit.bnot(2))
    end

    settings.currentPreset = 0

    tempOutfit.addons = addons
    updatePreview()
    if appearanceGroup:getSelectedWidget() == window.appearance.settings.outfit.check then
        showOutfits()
    end
end

function onColorModeChange(widget, selectedWidget)
    local colorMode = selectedWidget:getId()
    if colorMode == "head" then
        colorBoxGroup:selectWidget(window.appearance.colorBoxPanel["colorBox" .. tempOutfit.head])
    elseif colorMode == "primary" then
        colorBoxGroup:selectWidget(window.appearance.colorBoxPanel["colorBox" .. tempOutfit.body])
    elseif colorMode == "secondary" then
        colorBoxGroup:selectWidget(window.appearance.colorBoxPanel["colorBox" .. tempOutfit.legs])
    elseif colorMode == "detail" then
        colorBoxGroup:selectWidget(window.appearance.colorBoxPanel["colorBox" .. tempOutfit.feet])
    end
end

function onColorCheckChange(widget, selectedWidget)
    local colorId = selectedWidget.colorId
    local colorMode = colorModeGroup:getSelectedWidget():getId()
    if colorMode == "head" then
        tempOutfit.head = colorId
    elseif colorMode == "primary" then
        tempOutfit.body = colorId
    elseif colorMode == "secondary" then
        tempOutfit.legs = colorId
    elseif colorMode == "detail" then
        tempOutfit.feet = colorId
    end

    updatePreview()

    if appearanceGroup:getSelectedWidget() == window.appearance.settings.outfit.check then
        showOutfits()
    end
end

function updatePreview()
    local direction = previewCreature:getDirection()
    local previewOutfit = table.copy(tempOutfit)

    if not settings.showOutfit then
        previewCreature:hide()
    else
        previewCreature:show()
    end

    if not settings.showMount then
        previewOutfit.mount = 0
    end

    if not settings.showFamiliar or previewOutfit.familiar == 0 then
        previewOutfit.familiar = 0
        previewCreature:setMarginRight(0)
        previewFamiliar:setMarginLeft(0)
        window.preview.panel.bars:setMarginRight(20)
        previewFamiliar:setVisible(false)
    else
        if previewOutfit.familiar and previewOutfit.familiar > 0 then
            previewFamiliar:setVisible(true)
            previewCreature:setMarginRight(50)
            window.preview.panel.bars:setMarginRight(40)
            previewFamiliar:setCreatureSize(124)
            previewFamiliar:setCenter(true)
            previewFamiliar:setMarginLeft(70)
        end
    end

    if settings.showAura then
        attachOrDetachEffect(lastSelectAura, true)
    else
        attachOrDetachEffect(lastSelectAura, false)
    end

    if settings.showWings then
        attachOrDetachEffect(lastSelectWings, true)
    else
        attachOrDetachEffect(lastSelectWings, false)
    end

    if settings.showEffects then
        attachOrDetachEffect(lastSelectEffects, true)
    else
        attachOrDetachEffect(lastSelectEffects, false)
    end

    if not settings.showShader then
        if previewCreature then
            local creature = previewCreature:getCreature()
            if creature then
                creature:setShader("Outfit - Default")
            end
        end
    else
        if previewCreature and lastSelectShader then
            local creature = previewCreature:getCreature()
            if creature then
                creature:setShader(lastSelectShader)
            end
        end
    end

    if not settings.showBars then
        previewOutfit.healthBar = 0
        window.preview.panel.bars:hide()
    else
        if g_game.getFeature(GamePlayerMounts) and settings.showMount and previewOutfit.mount > 0 then
            window.preview.panel.bars:setMarginTop(-10)
            window.preview.panel.bars:setMarginLeft(60)
        else
            window.preview.panel.bars:setMarginTop(-10)
            window.preview.panel.bars:setMarginLeft(50)
        end
        local name = g_game.getCharacterName()
        window.preview.panel.bars.name:setText(name)
        if name:find("g") or name:find("j") or name:find("p") or name:find("q") or name:find("y") then
            window.preview.panel.bars.name:setHeight(14)
        else
            window.preview.panel.bars.name:setHeight(11)
        end
        window.preview.panel.bars.name:setMarginLeft(-43)

        local healthBar = window.preview.panel.bars.healthBar
        local manaBar = window.preview.panel.bars.manaBar
        manaBar:setMarginTop(0)
        healthBar:setMarginTop(1)
        healthBar.image:setMargin(0)
        healthBar.image:hide()
        manaBar.image:setMargin(0)
        manaBar.image:hide(0)

        window.preview.panel.bars:show()
    end

    previewCreature:setOutfit(previewOutfit)
    previewCreature:getCreature():setDirection(direction)

    for _, paperdoll in ipairs(g_game.getLocalPlayer():getPaperdolls()) do
        if paperdoll:canDrawOnUI() then
            local clone = paperdoll:clone()
            previewCreature:getCreature():attachPaperdoll(clone)
        end
    end
end

function rotate(value)
    if not previewCreature then
        return
    end

    local creature = previewCreature:getCreature()
    if not creature then
        return
    end

    local direction = previewCreature:getDirection()

    direction = direction + value

    if direction > Directions.West then
        direction = Directions.North
    elseif direction < Directions.North then
        direction = Directions.West
    end

    creature:setDirection(direction)
    if g_game.getFeature(GamePlayerFamiliars) and previewFamiliar then
        local familiarCreature = previewFamiliar:getCreature()
        if familiarCreature then
            familiarCreature:setDirection(direction)
        end
    end
    if floor then
        floor:setMargin(0)
    end
end

function onFilterOnlyMine(self, checked)
    addEvent(function()
        local children = window.selectionList:getChildren()
        for _, child in ipairs(children) do
            if checked and (not child.state or child.state ~= 0) then
                window.selectionList:focusChild(nil)
                child:hide()
            else
                child:show()
            end
        end
    end)
end

function onFilterSearch()
    addEvent(function()
        if not window then return end
        local searchText = window.listSearch.search:getText():lower():trim()
        local children = window.selectionList:getChildren()
        if searchText:len() >= 1 then
            for _, child in ipairs(children) do
                local text = child.name:getText():lower()
                if text:find(searchText) then
                    child:show()
                else
                    child:hide()
                end
            end
        else
            for _, child in ipairs(children) do
                child:show()
            end
        end
    end)
end

function saveSettings()
    if not g_resources.fileExists(settingsFile) then
        g_resources.makeDir("/settings")
        -- Safely attempt to write initial file
        local writeStatus, writeError = pcall(function()
            return g_resources.writeFileContents(settingsFile, "[]")
        end)

        if not writeStatus then
            g_logger.debug("Could not create outfit settings file during logout: " .. tostring(writeError))
            return
        end
    end

    local fullSettings = {}
    do
        local json_status, json_data = pcall(function()
            return json.decode(g_resources.readFileContents(settingsFile))
        end)

        if not json_status then
            g_logger.error("[saveSettings] Couldn't load JSON: " .. json_data)
            return
        end
        fullSettings = json_data
    end

    fullSettings[g_game.getCharacterName()] = settings

    local json_status, json_data = pcall(function()
        return json.encode(fullSettings)
    end)

    if not json_status then
        g_logger.error("[saveSettings] Couldn't save JSON: " .. json_data)
        return
    end

    -- Safely attempt to write the settings file
    local writeStatus, writeError = pcall(function()
        return g_resources.writeFileContents(settingsFile, json.encode(fullSettings))
    end)

    if not writeStatus then
        g_logger.debug("Could not save outfit settings during logout: " .. tostring(writeError))
    end
end

function loadSettings()
    if not g_resources.fileExists(settingsFile) then
        g_resources.makeDir("/settings")
    end

    if g_resources.fileExists(settingsFile) then
        local json_status, json_data = pcall(function()
            return json.decode(g_resources.readFileContents(settingsFile))
        end)

        if not json_status then
            g_logger.error("[loadSettings] Couldn't load JSON: " .. json_data)
            return
        end

        settings = json_data[g_game.getCharacterName()]
        if not settings then
            loadDefaultSettings()
        end
    else
        loadDefaultSettings()
    end
end

function loadDefaultSettings()
    settings = {
        movement = true,
        showFloor = true,
        showOutfit = true,
        showMount = true,
        showFamiliar = true,
        showWings = true,
        showAura = true,
        showShader = true,
        showBars = true,
        showTitle = true,
        showEffects = true,
        presets = {},
        currentPreset = 0
    }
    settings.currentPreset = 0
end

function accept()
    if g_game.getFeature(GamePlayerMounts) then
        local player = g_game.getLocalPlayer()
        local isMountedChecked = window.configure.mount.check:isChecked()
        if not player:isMounted() and isMountedChecked then
            player:mount()
        elseif player:isMounted() and not isMountedChecked then
            player:dismount()
        end
        if settings.currentPreset > 0 then
            settings.presets[settings.currentPreset].mounted = isMountedChecked
        end
    end
    if g_game.getFeature(GamePlayerFamiliars) then
        if settings.currentPreset > 0 then
            -- Check if familiar configuration exists before accessing it
            if window.configure.familiar and window.configure.familiar.check then
                settings.presets[settings.currentPreset].familiar = window.configure.familiar.check:isChecked()
            else
                -- Default to false if the familiar check doesn't exist
                settings.presets[settings.currentPreset].familiar = false
            end
        end
    end
    g_game.changeOutfit(tempOutfit)
    destroy()
end
