local addonName, ns = ...
local L = ns.L
local W = ns.Widgets

local currentOtherTank = nil
local currentOtherTankClass = nil
local isPlayerTank = false

local frame = CreateFrame("Button", "NaowhQOL_CoTankFrame", UIParent, "SecureUnitButtonTemplate, BackdropTemplate")
frame:SetSize(150, 20)
frame:SetPoint("CENTER", UIParent, "CENTER", 200, 0)
frame:RegisterForClicks("AnyUp")
frame:SetAttribute("type1", "target")
frame:Hide()

local borderFrame = CreateFrame("Frame", nil, frame, "BackdropTemplate")
borderFrame:SetPoint("TOPLEFT", -1, 1)
borderFrame:SetPoint("BOTTOMRIGHT", 1, -1)
borderFrame:SetBackdrop({
    edgeFile = [[Interface\Buttons\WHITE8X8]],
    edgeSize = 1,
})
borderFrame:SetBackdropBorderColor(0, 0, 0, 1)

local healthBg = frame:CreateTexture(nil, "BACKGROUND")
healthBg:SetAllPoints()
healthBg:SetColorTexture(0.1, 0.1, 0.1, 0.8)

local healthBar = CreateFrame("StatusBar", nil, frame)
healthBar:SetAllPoints()
healthBar:SetStatusBarTexture("Interface\\Buttons\\WHITE8X8")
healthBar:SetStatusBarColor(0, 0.8, 0.2)
healthBar:SetMinMaxValues(0, 100)
healthBar:SetValue(100)

local nameText = healthBar:CreateFontString(nil, "OVERLAY")
nameText:SetFont(ns.DefaultFontPath(), 12, "OUTLINE")
nameText:SetPoint("CENTER", healthBar, "CENTER", 0, 0)

local function FindOtherTank()
    if not IsInRaid() then return nil end

    local numMembers = GetNumGroupMembers()
    for i = 1, numMembers do
        local unit = "raid" .. i
        if UnitExists(unit) and not UnitIsUnit(unit, "player") then
            local role = UnitGroupRolesAssigned(unit)
            if role == "TANK" then
                return unit
            end
        end
    end
    return nil
end

local function IsPlayerTankSpec()
    if PlayerUtil and PlayerUtil.IsPlayerEffectivelyTank then
        return PlayerUtil.IsPlayerEffectivelyTank()
    end
    local role = UnitGroupRolesAssigned("player")
    return role == "TANK"
end

local function ShouldBeVisible()
    local db = NaowhQOL.coTank
    if not db or not db.enabled then return false end
    if db.unlock then return true end

    if not IsInRaid() then return false end
    if not IsPlayerTankSpec() then return false end

    local otherTank = FindOtherTank()
    return otherTank ~= nil
end

local function UpdateHealth()
    if not currentOtherTank or not UnitExists(currentOtherTank) then
        healthBar:SetValue(0)
        nameText:Hide()
        return
    end

    local db = NaowhQOL.coTank

    healthBar:SetMinMaxValues(0, UnitHealthMax(currentOtherTank))
    healthBar:SetValue(UnitHealth(currentOtherTank))

    if db.useClassColor then
        if currentOtherTankClass then
            local color = RAID_CLASS_COLORS[currentOtherTankClass]
            if color then
                healthBar:SetStatusBarColor(color.r, color.g, color.b)
            end
        end
    else
        healthBar:SetStatusBarColor(db.healthColorR or 0, db.healthColorG or 0.8, db.healthColorB or 0.2)
    end

    if db.showName then
        local name = UnitName(currentOtherTank)
        if name then
            if db.nameFormat == "abbreviated" and db.nameLength then
                name = string.sub(name, 1, db.nameLength)
            end
            nameText:SetText(name)
            nameText:SetFont(ns.Media.ResolveFont(db.font), db.nameFontSize or 12, "OUTLINE")
            if db.nameColorUseClassColor then
                if currentOtherTankClass then
                    local color = RAID_CLASS_COLORS[currentOtherTankClass]
                    if color then
                        nameText:SetTextColor(color.r, color.g, color.b)
                    end
                end
            else
                nameText:SetTextColor(db.nameColorR or 1, db.nameColorG or 1, db.nameColorB or 1)
            end
            nameText:Show()
        else
            nameText:Hide()
        end
    else
        nameText:Hide()
    end
end

local function UpdateDisplay()
    local db = NaowhQOL.coTank
    if not db then
        if not InCombatLockdown() then frame:Hide() end
        return
    end

    if not InCombatLockdown() then
        frame:EnableMouse(true)
    end
    ns.DisplayUtils.SetFrameUnlocked(frame, db.unlock, L["SIDEBAR_TAB_COTANK"] or "Co-Tank")

    if not InCombatLockdown() then
        frame:SetSize(db.width or 150, db.height or 20)
    end

    if not frame.posInitialized or frame.lastAnchorFrame ~= (db.anchorFrame or "UIParent") then
        local anchorFrameName = db.anchorFrame or "UIParent"
        local anchorParent = (_G[anchorFrameName] and type(_G[anchorFrameName]) == "table" and _G[anchorFrameName].GetObjectType) and _G[anchorFrameName] or UIParent
        frame:ClearAllPoints()
        frame:SetPoint(db.point or "CENTER", anchorParent, db.point or "CENTER", db.x or 200, db.y or 0)
        frame.posInitialized = true
        frame.lastAnchorFrame = anchorFrameName
    end

    healthBg:SetAlpha(db.bgAlpha or 0.6)

    if ShouldBeVisible() then
        currentOtherTank = FindOtherTank()

        if not InCombatLockdown() then
            frame:SetAttribute("unit", currentOtherTank)
        end

        if db.unlock and not currentOtherTank then
            healthBar:SetValue(75)
            healthBar:SetMinMaxValues(0, 100)
            healthBar:SetStatusBarColor(0, 0.8, 0.2)
            if frame.unlockLabel then frame.unlockLabel:Hide() end
            frame:SetBackdrop(nil)
            if db.showName then
                local previewName = L["COTANK_PREVIEW_NAME"] or "TankName"
                if db.nameFormat == "abbreviated" and db.nameLength then
                    previewName = string.sub(previewName, 1, db.nameLength)
                end
                nameText:SetText(previewName)
                nameText:SetFont(ns.Media.ResolveFont(db.font), db.nameFontSize or 12, "OUTLINE")
                nameText:SetTextColor(db.nameColorR or 1, db.nameColorG or 1, db.nameColorB or 1)
                nameText:Show()
            else
                nameText:Hide()
            end
        else
            UpdateHealth()
        end

        if not InCombatLockdown() then frame:Show() end
    else
        if not InCombatLockdown() then
            frame:SetAttribute("unit", nil)
        end
        if not InCombatLockdown() then frame:Hide() end
    end
end

function frame:Refresh()
    UpdateDisplay()
end

local eventFrame = CreateFrame("Frame")
eventFrame:RegisterEvent("PLAYER_LOGIN")
eventFrame:RegisterEvent("GROUP_ROSTER_UPDATE")
eventFrame:RegisterEvent("PLAYER_ROLES_ASSIGNED")
eventFrame:RegisterEvent("ROLE_CHANGED_INFORM")
eventFrame:RegisterEvent("PLAYER_SPECIALIZATION_CHANGED")
eventFrame:RegisterEvent("PLAYER_ENTERING_WORLD")
eventFrame:RegisterEvent("PLAYER_REGEN_ENABLED")

eventFrame:SetScript("OnEvent", ns.PerfMonitor:Wrap("CoTank", function(self, event, arg1)
    if event == "PLAYER_LOGIN" then
        local db = NaowhQOL.coTank
        if not db then return end

        W.MakeDraggable(frame, {
            db = db,
            onDragStop = function()
                db.anchorFrame = "UIParent"
                frame.lastAnchorFrame = "UIParent"
            end,
        })

        isPlayerTank = IsPlayerTankSpec()
        UpdateDisplay()

        ns.SettingsIO:RegisterRefresh("coTank", function()
            UpdateDisplay()
        end)
        return
    end

    if event == "GROUP_ROSTER_UPDATE" or event == "PLAYER_ROLES_ASSIGNED"
       or event == "ROLE_CHANGED_INFORM" or event == "PLAYER_ENTERING_WORLD" then
        isPlayerTank = IsPlayerTankSpec()
        currentOtherTank = FindOtherTank()
        if currentOtherTank then
            local _, cls = UnitClass(currentOtherTank)
            currentOtherTankClass = cls
        else
            currentOtherTankClass = nil
        end
        UpdateDisplay()
        return
    end

    if event == "PLAYER_SPECIALIZATION_CHANGED" then
        isPlayerTank = IsPlayerTankSpec()
        UpdateDisplay()
        return
    end

    if event == "PLAYER_REGEN_ENABLED" then
        currentOtherTank = FindOtherTank()
        if currentOtherTank then
            local _, cls = UnitClass(currentOtherTank)
            currentOtherTankClass = cls
        else
            currentOtherTankClass = nil
        end
        frame:SetAttribute("unit", currentOtherTank)
        UpdateDisplay()
        return
    end
end))

local updateFrame = CreateFrame("Frame")
local updateElapsed = 0
local UPDATE_INTERVAL = 0.1

local function CoTankOnUpdate(self, elapsed)
    updateElapsed = updateElapsed + elapsed
    if updateElapsed < UPDATE_INTERVAL then return end
    updateElapsed = 0
    local db = NaowhQOL.coTank
    if db and db.unlock and not currentOtherTank then return end
    UpdateHealth()
end

frame:HookScript("OnShow", function()
    updateElapsed = 0
    updateFrame:SetScript("OnUpdate", CoTankOnUpdate)
end)
frame:HookScript("OnHide", function()
    updateFrame:SetScript("OnUpdate", nil)
end)

ns.CoTankDisplay = frame
