local addonName, addonTable = ...
---@type MK
local MK = addonTable.MK
local core = addonTable
local TRANSLATE = core.TRANSLATE or function(msg) return msg end
local IsSecretValue = issecretvalue

local BLACKLIST_MENU_ICON_TEXTURE = "Interface\\AddOns\\" .. addonName .. "\\Art\\Ui\\Icon\\Blacklist.png"
local BLACKLIST_MENU_ICON_MARKUP = "|T" .. BLACKLIST_MENU_ICON_TEXTURE .. ":16:16:0:0|t "
local BLACKLIST_MENU_COLOR_CODE = "|cffff2020"
local BLACKLIST_MENU_RESET_CODE = "|r"

local UNIT_POPUP_MENU_TAGS = {
    "MENU_UNIT_PLAYER",
    "MENU_UNIT_PARTY",
    "MENU_UNIT_RAID",
    "MENU_UNIT_RAID_PLAYER",
    "MENU_UNIT_FRIEND",
    "MENU_UNIT_GUILD",
    "MENU_UNIT_CHAT_ROSTER",
    "MENU_UNIT_TARGET",
    "MENU_UNIT_FOCUS",
    "MENU_UNIT_PVP_SCOREBOARD",
    "MENU_UNIT_COMMUNITIES_MEMBER",
}

local function IsBlacklistUnitPopupSecretValue(value)
    if type(IsSecretValue) ~= "function" then
        return false
    end

    local ok, isSecret = pcall(IsSecretValue, value)
    return not ok or isSecret == true
end

local function GetUnitPopupContextField(contextData, fieldName)
    if type(contextData) ~= "table" or IsBlacklistUnitPopupSecretValue(contextData) then
        return nil
    end

    local ok, value = pcall(function()
        return contextData[fieldName]
    end)
    if not ok or IsBlacklistUnitPopupSecretValue(value) then
        return nil
    end
    return value
end

local function TrimString(value)
    if IsBlacklistUnitPopupSecretValue(value) or type(value) ~= "string" then
        return nil
    end
    if strtrim then
        value = strtrim(value)
    else
        value = value:match("^%s*(.-)%s*$") or value
    end
    if value == "" then
        return nil
    end
    return value
end

local function SplitPlayerName(playerName, realm)
    playerName = TrimString(playerName)
    realm = TrimString(realm)
    if not playerName then
        return nil, nil
    end

    if playerName:find("-", 1, true) then
        local namePart, realmPart = strsplit("-", playerName)
        playerName = TrimString(namePart) or playerName
        realm = TrimString(realmPart) or realm
    end

    return playerName, realm
end

local function GetFullPlayerNameFromUnitPopup(contextData)
    local contextName = GetUnitPopupContextField(contextData, "name")
    local contextRealm = GetUnitPopupContextField(contextData, "server")
    local playerName, realm = SplitPlayerName(contextName, contextRealm)
    if playerName then
        return playerName, realm
    end

    local unit = GetUnitPopupContextField(contextData, "unit")
    if unit and UnitNameUnmodified then
        local ok, name, unitRealm = pcall(UnitNameUnmodified, unit)
        name = ok and TrimString(name) or nil
        if name then
            return name, TrimString(unitRealm)
        end
    end

    return nil, nil
end

local function IsLocalPlayerFromUnitPopup(contextData, playerName, realm)
    if GetUnitPopupContextField(contextData, "isSelf") == true then
        return true
    end

    if not (MK and MK.NormalizeBlacklistPlayerName and UnitNameUnmodified) then
        return false
    end

    local ok, currentName, currentRealm = pcall(UnitNameUnmodified, "player")
    currentName = ok and TrimString(currentName) or nil
    if not currentName then
        return false
    end
    currentRealm = TrimString(currentRealm)
        or GetNormalizedRealmName and TrimString(GetNormalizedRealmName())
        or GetRealmName and TrimString(GetRealmName())

    local targetEntry = MK:NormalizeBlacklistPlayerName(playerName, realm)
    local currentEntry = MK:NormalizeBlacklistPlayerName(currentName, currentRealm)
    return targetEntry and currentEntry and targetEntry.key == currentEntry.key
end

local function AddUnitPopupPlayerToBlacklist(data)
    if not (MK and MK.AddPlayerToBlacklist) then
        return
    end

    local playerName = type(data) == "table" and data.name or data
    local realm = type(data) == "table" and data.realm or nil
    local note = MK.GetBlacklistNoteManual and MK:GetBlacklistNoteManual() or ""
    local ok, record = MK:AddPlayerToBlacklist(playerName, realm, note, "unit_popup_menu")
    if ok and MK.PrintBlacklistAdded then
        MK:PrintBlacklistAdded(record)
    end
end

local function ModifyUnitPopupMenu(_, rootDescription, contextData)
    if not (rootDescription and rootDescription.CreateButton and type(contextData) == "table") then
        return
    end

    local playerName, realm = GetFullPlayerNameFromUnitPopup(contextData)
    if not playerName or IsLocalPlayerFromUnitPopup(contextData, playerName, realm) then
        return
    end

    if rootDescription.CreateDivider then
        rootDescription:CreateDivider()
    end

    local menuText = BLACKLIST_MENU_ICON_MARKUP
        .. BLACKLIST_MENU_COLOR_CODE
        .. TRANSLATE("加入黑名单")
        .. BLACKLIST_MENU_RESET_CODE
    rootDescription:CreateButton(menuText, AddUnitPopupPlayerToBlacklist, {
        name = playerName,
        realm = realm,
    })
end

local function RegisterBlacklistUnitPopupMenus()
    if core.blacklistUnitPopupMenusRegistered then
        return true
    end
    if not (Menu and Menu.ModifyMenu) then
        return false
    end

    for _, tag in ipairs(UNIT_POPUP_MENU_TAGS) do
        Menu.ModifyMenu(tag, function(owner, rootDescription, contextData)
            ModifyUnitPopupMenu(owner, rootDescription, contextData)
        end)
    end
    core.blacklistUnitPopupMenusRegistered = true
    return true
end

if not RegisterBlacklistUnitPopupMenus() then
    local eventFrame = CreateFrame("Frame")
    eventFrame:RegisterEvent("PLAYER_LOGIN")
    eventFrame:RegisterEvent("ADDON_LOADED")
    eventFrame:SetScript("OnEvent", function(self)
        if RegisterBlacklistUnitPopupMenus() then
            self:UnregisterAllEvents()
        end
    end)
end
