ZO_UnitVisualizer_UnwaveringModule = ZO_UnitAttributeVisualizerModuleBase:Subclass()

function ZO_UnitVisualizer_UnwaveringModule:New(...)
    return ZO_UnitAttributeVisualizerModuleBase.New(self, ...)
end

function ZO_UnitVisualizer_UnwaveringModule:Initialize(layoutData)
    self.layoutData = layoutData
end

function ZO_UnitVisualizer_UnwaveringModule:GetInitialStatValue(stat, attribute, powerType)
    return self:GetInitialValueAndMarkMostRecent(ATTRIBUTE_VISUAL_UNWAVERING_POWER, stat, attribute, powerType)
end

function ZO_UnitVisualizer_UnwaveringModule:CreateInfoTable(control, oldBarInfo, stat, attribute, power)
    if control then
        local oldInfo = oldBarInfo and oldBarInfo[attribute]
        if oldInfo then
            oldInfo.value = self:GetInitialStatValue(stat, attribute, power)
            return oldInfo
        end

        return { value = self:GetInitialStatValue(stat, attribute, power), lastValue = 0 }
    end
    return nil
end

function ZO_UnitVisualizer_UnwaveringModule:OnAdded(healthBarControl, magickaBarControl, staminaBarControl)
    self.barControls =
    {
        [ATTRIBUTE_HEALTH] = healthBarControl,
    }
    if IsPlayerActivated() then
        self:InitializeBarValues()
    end

    EVENT_MANAGER:RegisterForEvent("ZO_UnitVisualizer_UnwaveringModule" .. self:GetModuleId(), EVENT_PLAYER_ACTIVATED, function() self:InitializeBarValues() end)
end

function ZO_UnitVisualizer_UnwaveringModule:InitializeBarValues()
    local healthBarControl = self.barControls[ATTRIBUTE_HEALTH]

    local oldBarInfo = self.barInfo
    self.barInfo =
    {
        [ATTRIBUTE_HEALTH] = self:CreateInfoTable(healthBarControl, oldBarInfo, STAT_MITIGATION, ATTRIBUTE_HEALTH, COMBAT_MECHANIC_FLAGS_HEALTH),
    }

    for attribute, bar in pairs(self.barControls) do
        self:OnValueChanged(bar, self.barInfo[attribute], ANIMATION_INSTANT)
    end
end

function ZO_UnitVisualizer_UnwaveringModule:OnUnitChanged()
    self:InitializeBarValues()
end

function ZO_UnitVisualizer_UnwaveringModule:IsUnitVisualRelevant(visualType, stat, attribute, powerType)
    if visualType == ATTRIBUTE_VISUAL_UNWAVERING_POWER then
        return self.barInfo 
           and self.barInfo[attribute] ~= nil
    end
    return false
end

function ZO_UnitVisualizer_UnwaveringModule:OnUnitAttributeVisualAdded(visualType, stat, attribute, powerType, value)
    self.barInfo[attribute].value = self.barInfo[attribute].value + value
    self:OnValueChanged(self.barControls[attribute], self.barInfo[attribute])
end

function ZO_UnitVisualizer_UnwaveringModule:OnUnitAttributeVisualUpdated(visualType, stat, attribute, powerType, oldValue, newValue)
    self.barInfo[attribute].value = self.barInfo[attribute].value + (newValue - oldValue)
    self:OnValueChanged(self.barControls[attribute], self.barInfo[attribute])
end

function ZO_UnitVisualizer_UnwaveringModule:OnUnitAttributeVisualRemoved(visualType, stat, attribute, powerType, value)
    self.barInfo[attribute].value = self.barInfo[attribute].value - value
    self:OnValueChanged(self.barControls[attribute], self.barInfo[attribute])
end

local function ApplyPlatformStyleToUnwavering(control, overlay)
    ApplyTemplateToControl(control, ZO_GetPlatformTemplate(overlay))
end

function ZO_UnitVisualizer_UnwaveringModule:PlayAnimation(bar, info, instant)
    if not info.animation then
        local control = CreateControlFromVirtual("$(parent)UnwaveringOverlayContainer", bar, self.layoutData.overlayContainerTemplate)

        local overlayOffsets = self.layoutData.overlayOffsets
        local currentOffsets = IsInGamepadPreferredMode() and overlayOffsets.gamepad or overlayOffsets.keyboard
        if not currentOffsets then
            currentOffsets = overlayOffsets.shared
        end
        control:SetAnchor(TOPLEFT, bar, TOPLEFT, currentOffsets.left, currentOffsets.top)
        control:SetAnchor(BOTTOMRIGHT, bar, BOTTOMRIGHT, currentOffsets.right, currentOffsets.bottom)
        local animation = ANIMATION_MANAGER:CreateTimelineFromVirtual("UnwaveringAnimation", control)
        info.control = control

        animation:SetHandler("OnPlay", function() 
            self:GetOwner():NotifyTakingControlOf(bar) 
            if bar.warner then
                bar.warner:SetPaused(false)
            end
        end)

        animation:SetHandler("OnStop", function()
            self:GetOwner():NotifyEndingControlOf(bar)
            if bar.warner then
                bar.warner:SetPaused(true)
            end
        end)

        for i, statusBar in ipairs(bar.barControls) do
            animation:InsertAnimationFromVirtual("UnwaveringBarAnimation", statusBar)
        end

        if bar.warnerContainer then
            animation:InsertAnimationFromVirtual("UnwaveringGlowInAnimation", bar.warnerContainer)
            animation:InsertAnimationFromVirtual("UnwaveringGlowOutAnimation", bar.warnerContainer)
        end

        info.animation = animation

        ApplyPlatformStyleToUnwavering(info.control, self.layoutData.overlayContainerTemplate)
    end

    info.animation.instant = instant
    info.animation.owner = self:GetOwner()

    if instant then
        info.control:SetAlpha(1)
        info.animation:PlayInstantlyToEnd()
    else
        info.animation:PlayForward()
    end
end

function ZO_UnitVisualizer_UnwaveringModule:OnValueChanged(bar, info, instant)
    local value = info.value
    local lastValue = info.lastValue
    info.lastValue = value

    if value > 0 and lastValue <= 0 then
        self:PlayAnimation(bar, info, instant)
    elseif value <= 0 and lastValue > 0 then
        info.animation.instant = instant
        ZO_Animation_PlayBackwardOrInstantlyToStart(info.animation, instant)
    end
end

function ZO_UnitVisualizer_UnwaveringModule:ApplyPlatformStyle()
    if self.barInfo then
        for _, info in pairs(self.barInfo) do
            if info.control then
                ApplyPlatformStyleToUnwavering(info.control, self.layoutData.overlayContainerTemplate)
            end
        end
    end
end