local _, addon = ...
local HLY = addon.HLY
local P = addon.P

local GetNumGroupMembers = GetNumGroupMembers
local GetSpecialization = GetSpecialization
local GetSpecializationRole = GetSpecializationRole
local IsInGroup = IsInGroup
local IsInRaid = IsInRaid
local PlaySoundFile = PlaySoundFile
local UnitExists = UnitExists
local UnitGUID = UnitGUID
local UnitGroupRolesAssigned = UnitGroupRolesAssigned
local UnitIsDeadOrGhost = UnitIsDeadOrGhost
local UnitIsFeignDeath = UnitIsFeignDeath
local pairs = pairs
local strfind = strfind
local strmatch = strmatch

local SOUND_BY_ROLE = {
    DAMAGER = 567522,
    HEALER = 567285,
    TANK = 567459,
}

local function IsTrackedUnit(unit)
    return unit == "player" or strmatch(unit, "^party%d+$") or strmatch(unit, "^raid%d+$")
end

local function NormalizeRole(role)
    if role == "DAMAGER" or role == "HEALER" or role == "TANK" then
        return role
    end
    return nil
end

local function GetPlayerRoleFallback()
    local spec = GetSpecialization()
    local role = spec and GetSpecializationRole(spec)
    return NormalizeRole(role) or "DAMAGER"
end

function HLY:ResolveDeathAlertRole(unit, guid)
    local unitRole = NormalizeRole(UnitGroupRolesAssigned(unit))
    if unitRole then
        return unitRole
    end

    local cachedRole = self.deathAlertRoleByGUID and self.deathAlertRoleByGUID[guid]
    if cachedRole then
        return cachedRole
    end

    if unit == "player" then
        return GetPlayerRoleFallback()
    end

    return "DAMAGER"
end

function HLY:PlayDeathAlert(role)
    local soundKitID = SOUND_BY_ROLE[role] or SOUND_BY_ROLE.DAMAGER
    local channel = (self.db and self.db.deathAlert and self.db.deathAlert.channel) or P.hlyqol.deathAlert.channel
    return PlaySoundFile(soundKitID, channel)
end

function HLY:UpdateDeathAlertUnitState(unit, shouldAlert)
    if not IsTrackedUnit(unit) or not UnitExists(unit) then
        return
    end

    local guid = UnitGUID(unit)
    if not guid or not strfind(guid, "Player%-") then
        return
    end

    self.deathAlertRoleByGUID = self.deathAlertRoleByGUID or {}
    self.deathAlertDeadByGUID = self.deathAlertDeadByGUID or {}

    local role = self:ResolveDeathAlertRole(unit, guid)
    self.deathAlertRoleByGUID[guid] = role

    local isDead = UnitIsDeadOrGhost(unit) and not UnitIsFeignDeath(unit)
    local wasDead = self.deathAlertDeadByGUID[guid]
    self.deathAlertDeadByGUID[guid] = isDead

    if shouldAlert and isDead and not wasDead then
        self:PlayDeathAlert(role)
    end
end

function HLY:HandleDeathAlertUnitEvent(_, unit)
    if not self.db or not self.db.deathAlert or not self.db.deathAlert.enabled then
        return
    end

    self:UpdateDeathAlertUnitState(unit, true)
end

function HLY:RefreshDeathAlertState()
    self.deathAlertRoleByGUID = self.deathAlertRoleByGUID or {}
    self.deathAlertDeadByGUID = self.deathAlertDeadByGUID or {}

    for guid in pairs(self.deathAlertRoleByGUID) do
        self.deathAlertRoleByGUID[guid] = nil
    end
    for guid in pairs(self.deathAlertDeadByGUID) do
        self.deathAlertDeadByGUID[guid] = nil
    end

    self:UpdateDeathAlertUnitState("player", false)

    if not IsInGroup() then
        return
    end

    if IsInRaid() then
        local count = GetNumGroupMembers() or 0
        for i = 1, count do
            self:UpdateDeathAlertUnitState("raid" .. i, false)
        end
    else
        for i = 1, 4 do
            self:UpdateDeathAlertUnitState("party" .. i, false)
        end
    end
end

function HLY:SetupDeathAlert()
    if self.deathAlertSetup then
        return
    end

    self:RegisterEvent("GROUP_ROSTER_UPDATE", "RefreshDeathAlertState")
    self:RegisterEvent("PLAYER_ROLES_ASSIGNED", "RefreshDeathAlertState")
    self:RegisterEvent("PLAYER_ENTERING_WORLD", "RefreshDeathAlertState")
    self:RegisterEvent("UNIT_HEALTH", "HandleDeathAlertUnitEvent")
    self:RegisterEvent("UNIT_FLAGS", "HandleDeathAlertUnitEvent")
    self:RefreshDeathAlertState()

    self.deathAlertSetup = true
end
