local E, C, L = select(2, ...):unpack()

------------------------------------------------------------------------
-- Raid Frame of DarkUI
------------------------------------------------------------------------
local core = E:Module("Unitframe")
local module = core:Sub("Raid")

local oUF = select(2, ...).oUF or oUF

local cfg = C.unitframe

local mediaPath = cfg.mediaPath

local media = {
    foreground = mediaPath .. "uf_raid_foreground",

    debuffHighlight = mediaPath .. "uf_raid_debuffHigtlight",

    hpTex = mediaPath .. "uf_bartex_raid_main",
    mpTex = mediaPath .. "uf_bartex_raid_slight",

    barTex_background = mediaPath .. "uf_bartex_raid_slight",

    incoming_barTex = mediaPath .. "uf_bartex_raid_main",
}

local backdrop = {
    bgFile = [=[Interface\ChatFrame\ChatFrameBackground]=],
    insets = { top = -1, left = -1, bottom = -1, right = -1 },
}

local function postUpdateHealth(bar, unit, min, max)
    local r, g, b, t

    if UnitIsPlayer(unit) then
        t = oUF.colors.class[select(2, UnitClass(unit))]
    else
        r, g, b = 0.1, 0.8, 0.3
    end

    if t then
        r, g, b = t[1], t[2], t[3]
    end

    if UnitIsDeadOrGhost(unit) or not UnitIsConnected(unit) then
        bar.bg:SetVertexColor(0.6, 0.6, 0.6)
        bar:SetStatusBarColor(0.6, 0.6, 0.6)
    else
        bar.bg:SetVertexColor(r, g, b)

        if cfg.raid.reverseColors then
            bar:SetStatusBarColor(r, g, b)
        else
            bar:SetStatusBarColor(0, 0, 0)
        end
    end
end

local function createTexture(self)
    -- foreground
    self.FrameFG = CreateFrame("Frame", nil, self)
    self.FrameFG:SetFrameStrata("LOW")
    self.FrameFG:SetFrameLevel(5)
    self.FrameFG:SetPoint("TOPLEFT", self, "TOPLEFT", 5, -5)
    self.FrameFG:SetPoint("BOTTOMRIGHT", self, "BOTTOMRIGHT", -5, 5)

    self.FrameFG.texture = self.FrameFG:CreateTexture(nil, "BACKGROUND")
    self.FrameFG.texture:SetAllPoints(self.FrameFG)
    self.FrameFG.texture:SetTexture(media.foreground)
    self.FrameFG.texture:SetVertexColor(0.47, 0.4, 0.4)

    self.DebuffHighlight = self:CreateTexture(nil, "OVERLAY")
    self.DebuffHighlight:SetVertexColor(0, 0, 0, 0)
    self.DebuffHighlight:SetBlendMode("ADD")
    self.DebuffHighlight:SetTexture(media.debuffHighlight)
    self.DebuffHighlight:SetPoint("TOPLEFT", self.FrameFG, "TOPLEFT", -5, 5)
    self.DebuffHighlight:SetPoint("BOTTOMRIGHT", self.FrameFG, "BOTTOMRIGHT", 5, -5)

    self.DebuffHighlightAlpha = 0.9
    self.DebuffHighlightFilter = false
end

local function createBar(self)
    self.Health = CreateFrame("StatusBar", nil, self, "BackdropTemplate")
    self.Health:SetFrameStrata("LOW")
    self.Health:SetFrameLevel(3)
    self.Health:SetPoint("TOPLEFT", self.FrameFG, "TOPLEFT", 3, -3)
    self.Health:SetPoint("BOTTOMRIGHT", self.FrameFG, "BOTTOMRIGHT", -3, 3)

    self.Health:SetStatusBarTexture(media.hpTex)
    self.Health:SetAlpha(1)

    self.Health:SetBackdrop(backdrop)
    self.Health:SetBackdropColor(0, 0, 0, 0.85)

    self.Health.bg = self.Health:CreateTexture(nil, "BORDER")
    self.Health.bg:SetTexture(media.barTex_background)
    self.Health.bg:SetAllPoints(self.Health)
    self.Health.bg:SetAlpha(0.3)

    self.Health.smoothing = Enum.StatusBarInterpolation.ExponentialEaseOut
    self.Health.colorSmooth = true
    self.Health.colorClass = cfg.raid.colorHealth

    --power bar
    self.Power = CreateFrame("StatusBar", nil, self)
    self.Power:SetFrameStrata("LOW")
    self.Power:SetFrameLevel(4)
    self.Power:SetHeight(4)
    self.Power:SetPoint("LEFT", self.Health, 6, 0)
    self.Power:SetPoint("RIGHT", self.Health, -6, 0)
    self.Power:SetPoint("BOTTOM", self.Health, 0, 6)
    self.Power:SetStatusBarTexture(media.mpTex)

    self.Power.bg = self.Power:CreateTexture(nil, "BORDER")
    self.Power.bg.multiplier = 0.3
    self.Power.bg:SetAllPoints()
    self.Power.bg:SetTexture(media.mpTex)

    self.Power.frequentUpdates = true
    self.Power.colorClass = true
    self.Power.colorReaction = true
    self.Power.colorTapping = true
    self.Power.colorDisconnected = true
    self.Power.smoothing = Enum.StatusBarInterpolation.ExponentialEaseOut
    self.Power.PostUpdateColor = core.PostUpdatePowerColor

    --Incoming heal
    local healingAll = CreateFrame("StatusBar", nil, self.Health)
    healingAll:SetPoint("TOP")
    healingAll:SetPoint("BOTTOM")
    healingAll:SetPoint("LEFT", self.Health:GetStatusBarTexture(), "RIGHT")
    healingAll:SetWidth(self.Health:GetWidth() or 40)
    healingAll:SetStatusBarTexture(media.incoming_barTex)
    healingAll:SetStatusBarColor(0, 1, 0.5, 0.2)

    local damageAbsorb = CreateFrame("StatusBar", nil, self.Health)
    damageAbsorb:SetPoint("TOP")
    damageAbsorb:SetPoint("BOTTOM")
    damageAbsorb:SetPoint("LEFT", healingAll:GetStatusBarTexture(), "RIGHT")
    damageAbsorb:SetWidth(self.Health:GetWidth() or 40)
    damageAbsorb:SetStatusBarTexture(media.incoming_barTex)
    damageAbsorb:SetStatusBarColor(1, 1, 0, 0.2)

    local overDamageAbsorbIndicator = self.Health:CreateTexture(nil, "ARTWORK", nil, 1)
    overDamageAbsorbIndicator:SetWidth(15)
    overDamageAbsorbIndicator:SetTexture("Interface\\RaidFrame\\Shield-Overshield")
    overDamageAbsorbIndicator:SetBlendMode("ADD")
    overDamageAbsorbIndicator:SetAlpha(0.7)
    overDamageAbsorbIndicator:SetPoint("TOPLEFT", self.Health, "TOPRIGHT", -7, 2)
    overDamageAbsorbIndicator:SetPoint("BOTTOMLEFT", self.Health, "BOTTOMRIGHT", -7, -2)

    local healAbsorb = CreateFrame("StatusBar", nil, self.Health)
    healAbsorb:SetPoint("TOP")
    healAbsorb:SetPoint("BOTTOM")
    healAbsorb:SetPoint("RIGHT", self.Health:GetStatusBarTexture())
    healAbsorb:SetWidth(self.Health:GetWidth() or 40)
    healAbsorb:SetReverseFill(true)
    healAbsorb:SetStatusBarTexture(media.incoming_barTex)
    healAbsorb:SetStatusBarColor(0, 0.5, 0.8, 0.5)
    healAbsorb:SetFrameLevel(self.Health:GetFrameLevel())

    local overHealAbsorbIndicator = self.Health:CreateTexture(nil, "ARTWORK", nil, 1)
    overHealAbsorbIndicator:SetWidth(15)
    overHealAbsorbIndicator:SetTexture("Interface\\RaidFrame\\Absorb-Overabsorb")
    overHealAbsorbIndicator:SetBlendMode("ADD")
    overHealAbsorbIndicator:SetAlpha(0.5)
    overHealAbsorbIndicator:SetPoint("TOPRIGHT", self.Health, "TOPLEFT", 5, 2)
    overHealAbsorbIndicator:SetPoint("BOTTOMRIGHT", self.Health, "BOTTOMLEFT", 5, -2)

    self.Health.HealingAll = healingAll
    self.Health.DamageAbsorb = damageAbsorb
    self.Health.OverDamageAbsorbIndicator = overDamageAbsorbIndicator
    self.Health.HealAbsorb = healAbsorb
    self.Health.OverHealAbsorbIndicator = overHealAbsorbIndicator
end

local function createTag(self)
    self.Tags = {}

    self.Tags.name = self:CreateTag(self.Health, "[dd:raidname]")
        :SetFont(STANDARD_TEXT_FONT, 10, "THICKOUTLINE")
        :SetPoint("CENTER", 0, 4)
        :SetJustifyH("CENTER")
        :SetShadowColor(0, 0, 0, 0)
        :done()

    self.Tags.hpval = self:CreateTag(self.Health, "[dd:misshp]")
        :SetFont(STANDARD_TEXT_FONT, 9, "OUTLINE")
        :SetPoint("BOTTOM", 0, 12)
        :SetJustifyH("CENTER")
        :SetShadowOffset(1.25, -1.25)
        :done()
end

local function createRaidDebuffs(self)
    if not cfg.raid.raidDebuffs.enable then return end

    local frame = CreateFrame("Frame", nil, self)
    frame:SetSize(18, 18)
    frame:SetPoint("RIGHT", -20, 0)
    frame:SetFrameLevel(self:GetFrameLevel() + 3)
    frame:CreateShadow()

    frame.icon = frame:CreateTexture(nil, "ARTWORK")
    frame.icon:SetAllPoints()
    frame.icon:SetTexCoord(unpack(C.media.texCoord))
    frame.count = frame:CreateFontText(12, "", false, "BOTTOMRIGHT", 6, -3)
    frame.time = frame:CreateFontText(12, "", false, "CENTER", 1, 0)

    frame.ShowDispellableDebuff = true
    frame.ShowBossDebuff = true
    frame.BossDebuffPriority = 9999999
    frame.EnableTooltip = cfg.raid.raidDebuffs.enableTooltip
    frame.ShowDebuffBorder = cfg.raid.raidDebuffs.showDebuffBorder
    frame.FilterDispellableDebuff = cfg.raid.raidDebuffs.filterDispellableDebuff
    frame.Debuffs = C.aura.raidDebuffs

    self.RaidDebuffs = frame
end

local function createStyle(self)
    self.colors = C.oUF_colors
    self.cUnit = "raid"

    core:SafeRegisterForClicks(self)
    self:SetScript("OnEnter", UnitFrame_OnEnter)
    self:SetScript("OnLeave", UnitFrame_OnLeave)

    createTexture(self)
    createBar(self)
    createTag(self)
    createRaidDebuffs(self)

    -- SpellsIndicator (corner buff colored dots)
    if cfg.raid.spellsIndicator then
        local si = CreateFrame("Frame", nil, self.Health)
        si:SetAllPoints()
        si:SetFrameLevel(self.Health:GetFrameLevel() + 5)
        si.size = 5
        self.SpellsIndicator = si
    end

    -- BuffsIndicator (important buff icons, bottom-right)
    if cfg.raid.buffsIndicator then
        local bi = CreateFrame("Frame", nil, self.Health)
        bi:SetAllPoints()
        bi:SetFrameLevel(self.Health:GetFrameLevel() + 4)
        bi.size = cfg.raid.indicatorSize
        bi.enable = true
        self.BuffsIndicator = bi
    end

    -- DebuffsIndicator (debuff icons with dispel border, bottom-left)
    if cfg.raid.debuffsIndicator then
        local di = CreateFrame("Frame", nil, self.Health)
        di:SetAllPoints()
        di:SetFrameLevel(self.Health:GetFrameLevel() + 4)
        di.size = cfg.raid.indicatorSize
        di.enable = true
        self.DebuffsIndicator = di
    end

    self.RaidTargetIndicator = core:CreateIcon(self.FrameFG, "ARTWORK", 18, 1, self, "CENTER", "CENTER", 0, 6)
    self.ReadyCheckIndicator = core:CreateIcon(self, "OVERLAY", 14, -1, self, "TOPRIGHT", "TOPRIGHT", -10, -12)
    self.LeaderIndicator = core:CreateIcon(self, "OVERLAY", 14, -1, self, "TOPLEFT", "TOPLEFT", 12, -12)
    self.AssistantIndicator = core:CreateIcon(self, "OVERLAY", 14, -1, self, "TOPLEFT", "TOPLEFT", 12, -12)
    self.GroupRoleIndicator = core:CreateIcon(self.FrameFG, "OVERLAY", 18, -1, self, "TOP", "TOP", 0, -2)
    self.GroupRoleIndicator:SetDesaturated(1)

    self.ResurrectIndicator = core:CreateIcon(self, "OVERLAY", 16, -1, self, "CENTER", "CENTER", 0, 0)
    self.SummonIndicator = core:CreateIcon(self, "OVERLAY", 20, -1, self, "CENTER", "CENTER", 0, 0)

    -- TargetBorder + ThreatBorder (via FrameFG vertex color)
    local defaultFGColor = { 0.47, 0.4, 0.4 }
    local targetColor = { 0.8, 0.7, 0.3 }
    local threatColors = {
        [1] = { 0.7, 0.7, 0.3 },
        [2] = { 0.7, 0.4, 0 },
        [3] = { 0.7, 0.1, 0.1 },
    }

    local function updateBorderColor(frame)
        if UnitIsUnit("target", frame.unit) then
            frame.FrameFG.texture:SetVertexColor(unpack(targetColor))
            return
        end

        local status = UnitThreatSituation(frame.unit)
        if status and status > 0 and threatColors[status] then
            frame.FrameFG.texture:SetVertexColor(unpack(threatColors[status]))
        else
            frame.FrameFG.texture:SetVertexColor(unpack(defaultFGColor))
        end
    end

    self:RegisterEvent("PLAYER_TARGET_CHANGED", updateBorderColor, true)
    self:RegisterEvent("GROUP_ROSTER_UPDATE", updateBorderColor, true)
    self:RegisterEvent("UNIT_THREAT_SITUATION_UPDATE", function(frame, _, unit)
        if unit == frame.unit then updateBorderColor(frame) end
    end)
    self:RegisterEvent("UNIT_THREAT_LIST_UPDATE", function(frame, _, unit)
        if unit == frame.unit then updateBorderColor(frame) end
    end)
    tinsert(self.__elements, updateBorderColor)

    -- PrivateAuras
    local pa = CreateFrame("Frame", nil, self)
    pa:SetPoint("CENTER", self.Health, 0, 0)
    pa:SetSize(20, 20)
    pa.size = 20
    pa.spacing = 0
    pa.initialAnchor = "CENTER"
    pa.growthX = "RIGHT"
    pa.growthY = "UP"
    pa.num = 1
    pa.borderScale = 0
    pa.disableCooldown = false
    pa.disableCooldownText = true
    self.PrivateAuras = pa

    core:SetFader(self, cfg.raid.fader)
end

function module:OnInit()
    if not C.unitframe.raid.enable then return end

    local showParty = cfg.party.enable and not cfg.party.standalone

    oUF:Factory(function()
        oUF:RegisterStyle("DarkUI:raid", createStyle)
        oUF:SetActiveStyle("DarkUI:raid")

        local groups, group = {}, nil
        local visibility = showParty and "custom [group] show; hide" or "custom [group:raid] show; hide"

        for i = 1, NUM_RAID_GROUPS do
            local name = "DarkUIRaidGroup" .. i

            group = oUF:SpawnHeader(
                name,
                nil,
                "showPlayer",
                true,
                "showSolo",
                cfg.raid.showSolo,
                "showParty",
                showParty,
                "showRaid",
                true,
                "point",
                "LEFT",
                "yOffset",
                -6,
                "xoffset",
                -10,
                "groupFilter",
                tostring(i),
                "groupBy",
                "GROUP",
                "groupingOrder",
                "TANK,HEALER,DAMAGER,NONE",
                "unitsPerColumn",
                5,
                "columnAnchorPoint",
                "TOPLEFT",
                "oUF-initialConfigFunction",
                ([[
                        self:SetWidth(%d)
                        self:SetHeight(%d)
                    ]]):format(cfg.raid.size, cfg.raid.size)
            )
            group:SetVisibility(visibility)

            group:SetScale(cfg.scale)
            groups[i] = group

            if i == 1 then
                group:SetPoint(unpack(cfg.raid.position))
                E:RegisterMover(group, L.UF_MOVER_RAID, "unitframe.raid.position", 200, 150)
            else
                group:SetPoint("TOPLEFT", groups[i - 1], "BOTTOMLEFT", 0, 6)
            end
        end

        -- Hide Default Frames
        if CompactPartyFrame then CompactPartyFrame:UnregisterAllEvents() end
        if CompactRaidFrameManager_SetSetting then
            CompactRaidFrameManager_SetSetting("IsShown", "0")
            UIParent:UnregisterEvent("GROUP_ROSTER_UPDATE")
            CompactRaidFrameManager:UnregisterAllEvents()
            CompactRaidFrameManager:SetParent(E.FrameHider)
        end
        if _G.CompactRaidFrameContainer then _G.CompactRaidFrameContainer:UnregisterAllEvents() end
    end)
end
