-- Offline Training Dialog (15.24). Opened by server packet onMultiOfflineTrainingDialog.
-- NOTE: The packet's magic-skill id is 5 — this collides with Skill.Shielding in the
-- Skill enum but the server treats 5 as "magic level" for offline training only.
skillController.OFFLINE_TRAINING_MAGIC_SKILL = 5

local offlineTrainingDefs = {{
    valueId = 'magicValue',
    barId = 'magicBar',
    getLevel = function(p)
        return p:getMagicLevel()
    end,
    getBaseLevel = function(p)
        return p:getBaseMagicLevel()
    end,
    getPercent = function(p)
        return p:getMagicLevelPercent()
    end
}, {
    valueId = 'fistValue',
    barId = 'fistBar',
    getLevel = function(p)
        return p:getSkillLevel(Skill.Fist)
    end,
    getBaseLevel = function(p)
        return p:getSkillBaseLevel(Skill.Fist)
    end,
    getPercent = function(p)
        return p:getSkillLevelPercent(Skill.Fist)
    end
}, {
    valueId = 'clubValue',
    barId = 'clubBar',
    getLevel = function(p)
        return p:getSkillLevel(Skill.Club)
    end,
    getBaseLevel = function(p)
        return p:getSkillBaseLevel(Skill.Club)
    end,
    getPercent = function(p)
        return p:getSkillLevelPercent(Skill.Club)
    end
}, {
    valueId = 'swordValue',
    barId = 'swordBar',
    getLevel = function(p)
        return p:getSkillLevel(Skill.Sword)
    end,
    getBaseLevel = function(p)
        return p:getSkillBaseLevel(Skill.Sword)
    end,
    getPercent = function(p)
        return p:getSkillLevelPercent(Skill.Sword)
    end
}, {
    valueId = 'axeValue',
    barId = 'axeBar',
    getLevel = function(p)
        return p:getSkillLevel(Skill.Axe)
    end,
    getBaseLevel = function(p)
        return p:getSkillBaseLevel(Skill.Axe)
    end,
    getPercent = function(p)
        return p:getSkillLevelPercent(Skill.Axe)
    end
}, {
    valueId = 'distanceValue',
    barId = 'distanceBar',
    getLevel = function(p)
        return p:getSkillLevel(Skill.Distance)
    end,
    getBaseLevel = function(p)
        return p:getSkillBaseLevel(Skill.Distance)
    end,
    getPercent = function(p)
        return p:getSkillLevelPercent(Skill.Distance)
    end
}}

local function refresh()
    skillController:refreshOfflineTrainingDialog()
end

local offlineTrainingEvents = {
    onMagicLevelChange = refresh,
    onBaseMagicLevelChange = refresh,
    onSkillChange = refresh,
    onBaseSkillChange = refresh
}

local function clampPercent(percent)
    percent = math.floor(tonumber(percent) or 0)
    return math.max(0, math.min(100, percent))
end

local function applyBaseState(widget, value, baseValue)
    if not widget then
        return
    end

    if baseValue <= 0 or value < 0 then
        widget:setColor('#bbbbbb')
        widget:removeTooltip()
        return
    end

    if value > baseValue then
        widget:setColor('#008b00')
        widget:setTooltip(baseValue .. ' +' .. (value - baseValue))
    elseif value < baseValue then
        widget:setColor('#b22222')
        widget:setTooltip(baseValue .. ' ' .. (value - baseValue))
    else
        widget:setColor('#bbbbbb')
        widget:removeTooltip()
    end
end

function skillController:cacheOfflineTrainingWidgets()
    local modal = self.offlineTrainingModal
    if not modal or not modal.ui then
        return
    end

    local cache = {}
    for i, def in ipairs(offlineTrainingDefs) do
        cache[i] = {
            value = modal.ui:querySelector('#' .. def.valueId),
            bar = modal.ui:querySelector('#' .. def.barId)
        }
    end
    self.offlineTrainingWidgetCache = cache
end

function skillController:bindOfflineTrainingEvents()
    if self.offlineTrainingEventsConnected then
        return
    end

    connect(LocalPlayer, offlineTrainingEvents)
    self.offlineTrainingEventsConnected = true
end

function skillController:unbindOfflineTrainingEvents()
    if not self.offlineTrainingEventsConnected then
        return
    end

    disconnect(LocalPlayer, offlineTrainingEvents)
    self.offlineTrainingEventsConnected = false
end

function skillController:refreshOfflineTrainingDialog()
    local modal = self.offlineTrainingModal
    local cache = self.offlineTrainingWidgetCache
    local player = g_game.getLocalPlayer()
    if not modal or not modal.ui or not cache or not player then
        return
    end

    for i, def in ipairs(offlineTrainingDefs) do
        local entry = cache[i]
        local level = def.getLevel(player) or 0
        local baseLevel = def.getBaseLevel(player) or 0
        local percent = clampPercent(def.getPercent(player))

        if entry.value then
            entry.value:setText(tostring(level))
            applyBaseState(entry.value, level, baseLevel)
        end
        if entry.bar then
            entry.bar:setPercent(percent)
            entry.bar:setTooltip(tr('You have %s percent to go', 100 - percent))
        end
    end
end

function skillController:showOfflineTrainingDialog()
    local modal = self.offlineTrainingModal
    if modal and modal.ui and not modal.ui:isDestroyed() then
        self:refreshOfflineTrainingDialog()
        return
    end

    self.offlineTrainingModal = self:openModal('offlinetraining1524.html', {
        mode = 'html'
    })
    if self.offlineTrainingModal and self.offlineTrainingModal.ui then
        -- Widget is created from our HTML, so overwriting onDestroy is safe here.
        self.offlineTrainingModal.ui.onDestroy = function()
            self:onOfflineTrainingModalDestroy()
        end
    end

    self:bindOfflineTrainingEvents()
    self:cacheOfflineTrainingWidgets()
    self:refreshOfflineTrainingDialog()
end

function skillController:hideOfflineTrainingDialog()
    local modal = self.offlineTrainingModal
    if not modal then
        return
    end

    self.offlineTrainingModal = nil
    self.offlineTrainingWidgetCache = nil
    self:unbindOfflineTrainingEvents()
    self:closeModal(modal)
end

function skillController:onOfflineTrainingModalDestroy()
    local modal = self.offlineTrainingModal
    if modal then
        self:closeModal(modal)
        modal.htmlId = nil
        modal.ui = nil
    end

    self.offlineTrainingModal = nil
    self.offlineTrainingWidgetCache = nil
    self:unbindOfflineTrainingEvents()
end

function onMultiOfflineTrainingDialog()
    skillController:showOfflineTrainingDialog()
end

function skillController:sendStartOfflineTraining(skillType)
    g_game.sendStartOfflineTraining(skillType)
    self:hideOfflineTrainingDialog()
end
