local MODERN_FOLDERS = {
    Fine     = "fine",
    Caution  = "caution",
    Critical = "critical",
    Danger   = "danger",
    Poison   = "poison",
    Death    = "danger",
}

local MODERN_SPEED = {
    Fine     = 200,
    Caution  = 200,
    Critical = 150,
    Danger   = 120,
    Poison   = 200,
    Death    = 9999,
}

local CLASSIC_FOLDERS = {
    Fine     = "fine_classic",
    Caution  = "caution_classic",
    Danger   = "danger_classic",
    Poison   = "poison_classic",
    Death    = "danger_classic",
}

local CLASSIC_SPEED = 100

local function loadFrames(folder)
    local frames, i = {}, 0
    while i < 200 do
        local t = getTexture(string.format("42/media/ui/%s/frame_%02d.png", folder, i))
            or getTexture(string.format("media/ui/%s/frame_%02d.png", folder, i))
        if not t then break end
        if t.setMinFilter then t:setMinFilter(Texture.FilterMode.Linear) end
        if t.setMagFilter then t:setMagFilter(Texture.FilterMode.Linear) end
        frames[#frames+1] = t
        i = i + 1
    end
    return frames
end

local function getModernState(p)
    if not p or not p.isAlive or not p:isAlive() then return "Death" end
    local bd = p:getBodyDamage()
    if not bd then return "Fine" end
    local poisoned = false
    if bd.IsPoisoned and bd:IsPoisoned() then poisoned = true end
    local foodSick = bd.getFoodSicknessLevel and bd:getFoodSicknessLevel() or 0
    local sickLvl  = bd.getSicknessLevel     and bd:getSicknessLevel()     or 0
    if foodSick >= 20 or sickLvl >= 20 then poisoned = true end
    if poisoned then return "Poison" end
    local hp = bd:getHealth() or 100
    if     hp >= 90 then return "Fine"
    elseif hp >= 60 then return "Caution"
    elseif hp >= 30 then return "Critical"
    elseif hp >  0 then return "Danger"
    else return "Death" end
end

local function getClassicState(p)
    if not p or not p.isAlive or not p:isAlive() then return "Death" end
    local bd = p:getBodyDamage()
    if not bd then return "Fine" end
    local poisoned = false
    if bd.IsPoisoned and bd:IsPoisoned() then poisoned = true end
    local foodSick = bd.getFoodSicknessLevel and bd:getFoodSicknessLevel() or 0
    local sickLvl  = bd.getSicknessLevel     and bd:getSicknessLevel()     or 0
    if foodSick >= 20 or sickLvl >= 20 then return "Poison" end
    local hp = bd:getHealth() or 100
    if hp >= 70 then return "Fine"
    elseif hp >= 35 then return "Caution"
    elseif hp > 0 then return "Danger"
    else return "Death" end
end

REHealthHUD = ISCollapsableWindow:derive("REHealthHUD")

function REHealthHUD:new(x, y, w, h)
    local o = ISCollapsableWindow:new(x, y, w, h)
    setmetatable(o, self)
    self.__index = self
    o:initialise()
    o:addToUIManager()
    o.title = getText("UI_REH_Status_Condition")
    o.resizable = true
    o.modernFrame, o.classicFrame = 1, 1
    o.modernTimer, o.classicTimer = 0, 0
    o.animModern, o.animClassic = {}, {}
    for k, folder in pairs(MODERN_FOLDERS) do o.animModern[k] = loadFrames(folder) end
    for k, folder in pairs(CLASSIC_FOLDERS) do o.animClassic[k] = loadFrames(folder) end
    if o.closeButton then o.closeButton:setVisible(false) end
    if o.pinButton then o.pinButton:setVisible(false) end
    if o.collapseButton then o.collapseButton:setVisible(false) end
    return o
end

function REHealthHUD:render()
    if REHUD_cfg.showBox then ISCollapsableWindow.render(self) end
    local p = getSpecificPlayer(0) or getPlayer()
    if not p then return end

    local useClassic = (REHUD_cfg.statusTheme == "classic")
    local status = useClassic and getClassicState(p) or getModernState(p)
    local isDead = (status == "Death")

    local frames, speed
    if useClassic then
        frames = self.animClassic[status] or self.animClassic["Fine"]
        speed = (status == "Death") and 9999 or CLASSIC_SPEED
    else
        frames = self.animModern[status] or self.animModern["Fine"]
        speed = MODERN_SPEED[status] or 200
    end

    if not frames or #frames == 0 then return end

    local paused = UIManager.getSpeedControls():getCurrentGameSpeed() == 0
    local dt = UIManager.getMillisSinceLastUpdate()

    if not isDead then
        if not paused then
            if useClassic then
                self.classicTimer = self.classicTimer + dt
                while self.classicTimer >= speed do
                    self.classicTimer = self.classicTimer - speed
                    self.classicFrame = (self.classicFrame % #frames) + 1
                end
            else
                self.modernTimer = self.modernTimer + dt
                while self.modernTimer >= speed do
                    self.modernTimer = self.modernTimer - speed
                    self.modernFrame = (self.modernFrame % #frames) + 1
                end
            end
        end
    else
        self.classicFrame, self.modernFrame = 1, 1
    end

    local currentFrameIdx = useClassic and self.classicFrame or self.modernFrame
    local frame = frames[currentFrameIdx]

    if isDead then
        local df = useClassic and self.animClassic["Danger"] or self.animModern["Danger"]
        if df and df[1] then frame = df[1] end
    end
    
    if not frame then return end

    local padL = REHUD_cfg.showBox and 2 or 0
    local padT = REHUD_cfg.showBox and 13 or 0
    local availW = math.floor(self.width - (padL * 2))
    local availH = math.floor(self.height - padT - 2)
    local alpha = math.max(0.25, math.min(1, REHUD_cfg.animAlpha or 1))

    self:drawTextureScaled(frame, math.floor(padL), math.floor(padT + 8), availW, math.max(1, availH - 8), alpha, 1, 1, 1)

    if self.resizeWidget then
        self.resizeWidget:setX(self.width - self.resizeWidget.width)
        self.resizeWidget:setY(self.height - self.resizeWidget.height)
        self.resizeWidget:prerender()
        self.resizeWidget:render()
    end
end

function REHealthHUD:drawTitle()
    if not REHUD_cfg.showHeader then return end
    local c = self.textColor
    self:drawText(self.title, 8, 3, c.r, c.g, c.b, c.a, UIFont.Small)
end

function REHealthHUD:getClientBottom() return 0 end

local lastInv = nil
safeAdd(Events.OnPlayerUpdate, function()
    local inv = getPlayerInventory and getPlayerInventory(0)
    local now = inv and inv:isVisible() or false
    if lastInv == nil then lastInv = now end
    if now ~= lastInv then
        lastInv = now
        if REHUD_cfg.uiSounds then playOgg(now and "Accept" or "Cancel") end
        if REHUD_cfg.uiLink and REHUD_HUD then
            REHUD_HUD:setVisible(now)
            REHUD_cfg.winVisible = now
        end
    end
end)