local ADDON_NAME, ns = ...

-- =============================================================
-- pom_threat.lua (12.0 / Midnight secret-safe)
-- - status AND threatPct can be secret numbers
-- - NEVER compare/tonumber/math on secret values
-- - If Detailed returns secret status, try UnitThreatSituation as fallback
-- - If status is still secret but pct is plain, use pct for gradient/flash
-- =============================================================

ns.threat = ns.threat or {}
local T = ns.threat

-- -------------------------------------------------------------
-- DB helper (READ-ONLY)
-- -------------------------------------------------------------
local function GetDB()
    if not PlateOMaticDB then return nil end
    if type(PlateOMaticDB.threat) ~= "table" then return nil end
    return PlateOMaticDB.threat
end

-- -------------------------------------------------------------
-- Helpers
-- -------------------------------------------------------------
local function Clamp01(x)
    x = tonumber(x) or 0
    if x < 0 then return 0 end
    if x > 1 then return 1 end
    return x
end

local function IsSecretValue(v)
    local f = _G.issecretvalue
    if type(f) ~= "function" then return false end
    local ok, r = pcall(f, v)
    return ok and r and true or false
end

local function IsSecretNumber(v)
    if type(v) ~= "number" then return false end
    return IsSecretValue(v)
end

local function SafeNumber(v, fallback)
    if IsSecretNumber(v) then return fallback or 0, true end
    local n = tonumber(v)
    if n == nil then return fallback or 0, false end
    return n, false
end

local function GetRole()
    if GetSpecialization and GetSpecializationRole then
        local spec = GetSpecialization()
        if spec then
            return GetSpecializationRole(spec) or "NONE"
        end
    end
    return "NONE"
end

local function PickColor(tbl, a, b, fallback)
    if type(tbl) ~= "table" then return fallback end
    local c = tbl[a]
    if type(c) == "table" then return c end
    c = tbl[b]
    if type(c) == "table" then return c end
    return fallback
end

local function GetThreatColors(db)
    local c = (db and db.colors) or {}

    local high   = PickColor(c, "high",   "threatHigh", { r=1.0, g=0.0, b=0.0 })
    local med    = PickColor(c, "medium", "med",        { r=1.0, g=1.0, b=0.0 })
    local low    = PickColor(c, "low",    "threatLow",  { r=0.5, g=0.5, b=0.5 })

    local tankOk = PickColor(c, "safe",   "tankSafe",   { r=0.2, g=0.8, b=0.2 })
    local offT   = PickColor(c, "ot",     "offTank",    { r=0.6, g=0.2, b=1.0 })

    local group  = PickColor(c, "group",  "groupTint",  { r=0.2, g=0.7, b=1.0, a=1.0 })

    return high, med, low, tankOk, offT, group
end

-- -------------------------------------------------------------
-- ThreatNumbers: returns SAFE status/pct + flags
-- Strategy:
--  1) Read DetailedThreatSituation
--  2) If status is secret -> try UnitThreatSituation (often plain)
--  3) pct used only if it is NOT secret
-- -------------------------------------------------------------
local function ThreatNumbers(playerUnit, unit)
    local _, statusRaw, pctRaw = UnitDetailedThreatSituation(playerUnit, unit)

    -- Fallback source if detailed status missing OR secret
    local altStatusRaw = nil
    if statusRaw == nil or IsSecretNumber(statusRaw) then
        altStatusRaw = UnitThreatSituation(playerUnit, unit)
    end

    -- Decide final status source:
    local statusFinalRaw = statusRaw
    if IsSecretNumber(statusFinalRaw) then
        -- if alternate exists and is NOT secret, use it
        if altStatusRaw ~= nil and (not IsSecretNumber(altStatusRaw)) then
            statusFinalRaw = altStatusRaw
        end
    end
    if statusFinalRaw == nil then
        statusFinalRaw = altStatusRaw
    end

    local status, statusSecret = SafeNumber(statusFinalRaw, 0)

    local pct, pctSecret = 0, false
    if pctRaw ~= nil then
        pct, pctSecret = SafeNumber(pctRaw, 0)
    end

    return status, pct, statusSecret, pctSecret
end

local function UnitIsThreatRelevant(unit, statusSafe)
    if UnitAffectingCombat(unit) then
        return true, "unitCombat"
    end
    if (tonumber(statusSafe) or 0) > 0 then
        return true, "hasThreat"
    end
    return false, "notRelevant"
end

-- =============================================================
-- Public: GetState(unit)
-- Returns:
--   r,g,b, shouldFlash, threatPctSafe, statusSafe, reason
-- =============================================================
function T:GetState(unit)
    local db = GetDB()
    if not db then
        return nil, nil, nil, false, 0, 0, "noDBThreat"
    end
    if db.enabled == false then
        return nil, nil, nil, false, 0, 0, "disabled"
    end

    -- If player isn't in combat, threat visuals are usually noise.
    if not UnitAffectingCombat("player") then
        return nil, nil, nil, false, 0, 0, "playerOOC"
    end

    local role = GetRole()
    local status, threatPct, statusWasSecret, pctWasSecret = ThreatNumbers("player", unit)

    local relevant, why = UnitIsThreatRelevant(unit, status)
    if not relevant then
        return nil, nil, nil, false, threatPct, status, why
    end

    local high, med, low, tankSafe, offTank, groupTint = GetThreatColors(db)

    local r, g, b

    -- Optional: DPS/Heal group tint
    if db.groupTintEnabled and role ~= "TANK" and (IsInGroup() or IsInRaid()) then
        r, g, b = groupTint.r or 0.2, groupTint.g or 0.7, groupTint.b or 1.0
    end

    -- Tank mode override (MT/OT logic) lives elsewhere
    local tankOverride = false
    local tankFlash = false
    if db.tankModeEnabled and role == "TANK" and ns and ns.GetTankModeState then
        local tr, tg, tb, tf = ns:GetTankModeState(unit)
        if tr then
            r, g, b = tr, tg, tb
            tankOverride = true
            tankFlash = tf and true or false
        end
    end

    -- Color decision
    if db.colorBarByThreat then
        if role == "TANK" then
            -- For tanks, status bands are best. If status is secret we can't safely do much here,
            -- but tankMode override should cover the important cases.
            if (not statusWasSecret) and status > 0 and (not tankOverride) then
                if status >= 3 then
                    r, g, b = tankSafe.r, tankSafe.g, tankSafe.b
                elseif status >= 1 then
                    r, g, b = med.r, med.g, med.b
                end
            end
        else
            -- DPS/Heal:
            -- Prefer pct gradient if pct is NOT secret; else use status bands if status is NOT secret.
            if (not pctWasSecret) then
                local startPct = tonumber(db.gradientStart) or 60
                local endPct   = tonumber(db.gradientEnd) or 100
                if endPct < startPct then endPct = startPct end

                if threatPct >= startPct then
                    local denom = (endPct - startPct)
                    local t = (denom > 0) and Clamp01((threatPct - startPct) / denom) or 1
                    r = (med.r or 1) + ((high.r or 1) - (med.r or 1)) * t
                    g = (med.g or 1) + ((high.g or 0) - (med.g or 1)) * t
                    b = (med.b or 0) + ((high.b or 0) - (med.b or 0)) * t
                end
            elseif (not statusWasSecret) then
                if status >= 3 then
                    r, g, b = high.r, high.g, high.b
                elseif status >= 2 then
                    r, g, b = med.r, med.g, med.b
                elseif status >= 1 then
                    r, g, b = low.r, low.g, low.b
                end
            end
        end
    end

    if not r then
        -- Nothing to override with (still safe)
        return nil, nil, nil, false, threatPct, status, (statusWasSecret and pctWasSecret) and "both_secret" or "noOverride"
    end

    -- Flash decision
    local shouldFlash = false
    if db.flashAggro then
        if role == "TANK" and db.tankModeEnabled then
            shouldFlash = tankFlash
        else
            -- Prefer pct flash if pct is plain; else status flash if status is plain
            if not pctWasSecret then
                local startPct = tonumber(db.gradientStart) or 60
                shouldFlash = (threatPct >= startPct)
            elseif not statusWasSecret then
                shouldFlash = (status >= 3)
            else
                shouldFlash = false
            end
        end
    end

    return r, g, b, shouldFlash, threatPct, status, pctWasSecret and "ok_secretPct" or "ok"
end