require "MS/MS_MatrixManager"
require "MS/MS_ModOptions"
require "MS/SettingPanel/MS_GlobalSettingsPanel"
require "MS/Patch/MS_ISEquippedItem_HealthBtn_GlobalSettings"
StatusWidget = {}
StatusWidget.indicators = {}
StatusWidget.globalControls = {}
StatusWidget.indicatorsByType = {}
StatusWidget.hasActiveAnimations = false
StatusWidget.pendingMoodleVisibility = StatusWidget.pendingMoodleVisibility or {}

-- ---------------------------------------------------------------------------------------- --
-- Create UI
-- ---------------------------------------------------------------------------------------- --
function StatusWidget.createUI(playerIndex, player)
    if not player:isLocalPlayer() then
        return
    end
    
    if not StatusWidget.indicators[playerIndex] then
        StatusWidget.indicators[playerIndex] = {}
    end

    if not StatusWidget.indicatorsByType[playerIndex] then
        StatusWidget.indicatorsByType[playerIndex] = {}
    end
    
    local function createIndicator(name, indicatorType)
        local config = MSConfig.getIndicatorConfig(playerIndex, indicatorType)
        
        local width, height
        if config.style == "bar" then
            width = config.barSize.width
            height = config.barSize.height
        else
            width = config.circularSize
            height = config.circularSize
        end
        
        local x = config.position.x
        local y = config.position.y
        
        local indicator = nil
        if indicatorType == "ISThirstStatusIndicator" then
            indicator = ISThirstStatusIndicator:new(x, y, width, height, player)
        elseif indicatorType == "ISHungerStatusIndicator" then
            indicator = ISHungerStatusIndicator:new(x, y, width, height, player)
        elseif indicatorType == "ISEnduranceStatusIndicator" then
            indicator = ISEnduranceStatusIndicator:new(x, y, width, height, player)
        elseif indicatorType == "ISFatigueStatusIndicator" then
            indicator = ISFatigueStatusIndicator:new(x, y, width, height, player)
        elseif indicatorType == "ISStressStatusIndicator" then
            indicator = ISStressStatusIndicator:new(x, y, width, height, player)
        elseif indicatorType == "ISPanicStatusIndicator" then
            indicator = ISPanicStatusIndicator:new(x, y, width, height, player)
        elseif indicatorType == "ISTemperatureStatusIndicator" then
            indicator = ISTemperatureStatusIndicator:new(x, y, width, height, player)
        elseif indicatorType == "ISWindchillStatusIndicator" then
            indicator = ISWindchillStatusIndicator:new(x, y, width, height, player)
        elseif indicatorType == "ISHealthStatusIndicator" then
            indicator = ISHealthStatusIndicator:new(x, y, width, height, player)
        elseif indicatorType == "ISBoredomStatusIndicator" then
            indicator = ISBoredomStatusIndicator:new(x, y, width, height, player)
        elseif indicatorType == "ISUnhappynessStatusIndicator" then
            indicator = ISUnhappynessStatusIndicator:new(x, y, width, height, player)
        elseif indicatorType == "ISDiscomfortStatusIndicator" then
            indicator = ISDiscomfortStatusIndicator:new(x, y, width, height, player)
        elseif indicatorType == "ISSicknessStatusIndicator" then
            indicator = ISSicknessStatusIndicator:new(x, y, width, height, player)
        elseif indicatorType == "ISCatchAColdStatusIndicator" then
            indicator = ISCatchAColdStatusIndicator:new(x, y, width, height, player)
        elseif indicatorType == "ISFoodHealingStatusIndicator" then
            indicator = ISFoodHealingStatusIndicator:new(x, y, width, height, player)
        elseif indicatorType == "ISPoisonStatusIndicator" then
            indicator = ISPoisonStatusIndicator:new(x, y, width, height, player)
        elseif indicatorType == "ISCalorieStatusIndicator" then
            indicator = ISCalorieStatusIndicator:new(x, y, width, height, player)
        elseif indicatorType == "ISPainStatusIndicator" then
            indicator = ISPainStatusIndicator:new(x, y, width, height, player)
        elseif indicatorType == "ISBleedingStatusIndicator" then
            indicator = ISBleedingStatusIndicator:new(x, y, width, height, player)
        elseif indicatorType == "ISCarryWeightStatusIndicator" then
            indicator = ISCarryWeightStatusIndicator:new(x, y, width, height, player)
        elseif indicatorType == "ISProteinsStatusIndicator" then
            indicator = ISProteinsStatusIndicator:new(x, y, width, height, player)
        elseif indicatorType == "ISCarbohydratesStatusIndicator" then
            indicator = ISCarbohydratesStatusIndicator:new(x, y, width, height, player)
        elseif indicatorType == "ISLipidsStatusIndicator" then
            indicator = ISLipidsStatusIndicator:new(x, y, width, height, player)
        elseif indicatorType == "ISWeightStatusIndicator" then
            indicator = ISWeightStatusIndicator:new(x, y, width, height, player)
        elseif indicatorType == "ISMedicineStatusIndicator" then
            indicator = ISMedicineStatusIndicator:new(x, y, width, height, player)
        elseif indicatorType == "ISDirtinessStatusIndicator" then
            indicator = ISDirtinessStatusIndicator:new(x, y, width, height, player)
        elseif indicatorType == "ISBloodinessStatusIndicator" then
            indicator = ISBloodinessStatusIndicator:new(x, y, width, height, player)
        elseif indicatorType == "ISAngerStatusIndicator" then
            indicator = ISAngerStatusIndicator:new(x, y, width, height, player)
        elseif indicatorType == "ISWetnessStatusIndicator" then
            indicator = ISWetnessStatusIndicator:new(x, y, width, height, player)
        elseif indicatorType == "ISDrunkennessStatusIndicator" then
            indicator = ISDrunkennessStatusIndicator:new(x, y, width, height, player)
        elseif indicatorType == "ISStiffnessStatusIndicator" then
            indicator = ISStiffnessStatusIndicator:new(x, y, width, height, player)
        elseif indicatorType == "ISNoxiousExposureStatusIndicator" then
            indicator = ISNoxiousExposureStatusIndicator:new(x, y, width, height, player)
        end
        
        if indicator then
            indicator:initialise()
            indicator:addToUIManager()
            StatusWidget.indicators[playerIndex][name] = indicator
            StatusWidget.indicatorsByType[playerIndex][indicatorType] = indicator
        end
        
        return indicator
    end

    createIndicator("health", "ISHealthStatusIndicator")
    createIndicator("thirst", "ISThirstStatusIndicator")
    createIndicator("hunger", "ISHungerStatusIndicator")
    createIndicator("endurance", "ISEnduranceStatusIndicator")
    createIndicator("fatigue", "ISFatigueStatusIndicator")
    createIndicator("panic", "ISPanicStatusIndicator")
    createIndicator("stress", "ISStressStatusIndicator")
    createIndicator("wetness", "ISWetnessStatusIndicator")
    createIndicator("windchill", "ISWindchillStatusIndicator")
    createIndicator("temperature", "ISTemperatureStatusIndicator")
    createIndicator("boredom", "ISBoredomStatusIndicator")
    createIndicator("unhappyness", "ISUnhappynessStatusIndicator")
    createIndicator("discomfort", "ISDiscomfortStatusIndicator")
    createIndicator("poison", "ISPoisonStatusIndicator")
    createIndicator("noxiousExposure", "ISNoxiousExposureStatusIndicator")
    createIndicator("sickness", "ISSicknessStatusIndicator")
    createIndicator("catchACold", "ISCatchAColdStatusIndicator")
    createIndicator("foodHealing", "ISFoodHealingStatusIndicator")
    createIndicator("calorie", "ISCalorieStatusIndicator")
    createIndicator("pain", "ISPainStatusIndicator")
    createIndicator("bleeding", "ISBleedingStatusIndicator")
    createIndicator("carryWeight", "ISCarryWeightStatusIndicator")
    createIndicator("proteins", "ISProteinsStatusIndicator")
    createIndicator("carbohydrates", "ISCarbohydratesStatusIndicator")
    createIndicator("lipids", "ISLipidsStatusIndicator")
    createIndicator("weight", "ISWeightStatusIndicator")
    createIndicator("medicine", "ISMedicineStatusIndicator")
    createIndicator("dirtiness", "ISDirtinessStatusIndicator")
    createIndicator("bloodiness", "ISBloodinessStatusIndicator")
    createIndicator("anger", "ISAngerStatusIndicator")
    createIndicator("drunkenness", "ISDrunkennessStatusIndicator")
    createIndicator("stiffness", "ISStiffnessStatusIndicator")

    local controlConfig = MSConfig.getGlobalConfig(playerIndex)
    local controlX = controlConfig.controlPosition and controlConfig.controlPosition.x or 10
    local controlY = controlConfig.controlPosition and controlConfig.controlPosition.y or 10
    local controlSize = 48

    local globalControl = ISGlobalControlPanel:new(controlX, controlY, controlSize, controlSize, player, playerIndex)
    globalControl:initialise()
    globalControl:addToUIManager()
    if ModernStatus_shouldShowBlueCogButton then
        globalControl:setVisible(ModernStatus_shouldShowBlueCogButton() == true)
    end
    StatusWidget.globalControls[playerIndex] = globalControl

    -- Re-apply saved vanilla moodles visibility after UI creation/reload, especially in MP.
    -- Only force the saved ON state during startup. For a saved OFF state, let
    -- external replacers such as MoodlesInLua keep vanilla MoodlesUI hidden.
    if controlConfig and (controlConfig.hideOriginalMoodles == true or controlConfig.hideVanillaMoodles == true or controlConfig.hideOriginalMoodle == true) then
        globalControl:applyHideOriginalMoodles(true)
        StatusWidget.pendingMoodleVisibility[playerIndex] = { control = globalControl, shouldHide = true, ticks = 180 }
    end

    MS_MatrixManager.refreshPlayer(playerIndex)
end

-- ---------------------------------------------------------------------------------------- --
-- Animations
-- ---------------------------------------------------------------------------------------- --
local function updateAnimations()
    for playerIndex, pending in pairs(StatusWidget.pendingMoodleVisibility or {}) do
        if not pending or not pending.control or pending.ticks <= 0 then
            StatusWidget.pendingMoodleVisibility[playerIndex] = nil
        else
            -- Re-apply while other moodle mods finish creating/replacing their UI elements.
            pending.control:applyHideOriginalMoodles(pending.shouldHide == true)
            pending.ticks = pending.ticks - 1
        end
    end

    if not StatusWidget.hasActiveAnimations then return end
    
    StatusWidget.hasActiveAnimations = false
    for playerIndex, indicators in pairs(StatusWidget.indicators) do
        for _, indicator in pairs(indicators) do
            if not indicator.hidden and indicator._runtimeAutoHidden ~= true and indicator._matrixAutoHidden ~= true and indicator:isVisible() then
                local delta = 1/30
                
                if indicator.iconAnimActive then
                    indicator:updateIconAnimation(delta)
                    StatusWidget.hasActiveAnimations = true
                end
                
                if indicator.barAnimActive then
                    indicator:updateBarAnimation(delta)
                    StatusWidget.hasActiveAnimations = true
                end

                if indicator.iconSwayActive then
                    indicator:updateIconSwayAnimation(delta)
                    StatusWidget.hasActiveAnimations = true
                end
            end
        end
    end
end

-- ---------------------------------------------------------------------------------------- --
-- onPlayerDeath remove ui
-- ---------------------------------------------------------------------------------------- --
function StatusWidget.onPlayerDeath(player)
    if not player:isLocalPlayer() then return end
    
    local playerIndex = player:getPlayerNum()

    if not StatusWidget.indicators[playerIndex] then return end

    for name, indicator in pairs(StatusWidget.indicators[playerIndex]) do
        indicator:removeFromUIManager()
    end

    StatusWidget.indicators[playerIndex] = {}
    StatusWidget.indicatorsByType[playerIndex] = {}
 
    if StatusWidget.globalControls[playerIndex] then
        StatusWidget.globalControls[playerIndex]:removeFromUIManager()
        StatusWidget.globalControls[playerIndex] = nil
    end
end

-- ---------------------------------------------------------------------------------------- --
-- Events
-- ---------------------------------------------------------------------------------------- --
Events.OnPlayerDeath.Add(StatusWidget.onPlayerDeath)
Events.OnTick.Add(updateAnimations)
Events.OnCreatePlayer.Add(function(playerIndex, player)
    StatusWidget.createUI(playerIndex, player)
end)
