--## Author: FocusHelper ## Version: 1.0.0 ## SavedVariables: FocusHelperDB
local DEFAULTS = {
    setFocusMod = 1,
    setFocusIcon = 8,
    announceOnChallengeStart = false,
    announceOnReadyCheck = false,
}

local MODIFIERS = {
    [1] = { binding = "SHIFT", attribute = "shift", text = "Shift" },
    [2] = { binding = "CTRL", attribute = "ctrl", text = "Ctrl" },
    [3] = { binding = "ALT", attribute = "alt", text = "Alt" },
}

local UNIT_FRAME_NAMES = {
    "PetFrame",
    "PlayerFrame",
    "PartyMemberFrame1",
    "PartyMemberFrame2",
    "PartyMemberFrame3",
    "PartyMemberFrame4",
    "PartyMemberFrame1PetFrame",
    "PartyMemberFrame2PetFrame",
    "PartyMemberFrame3PetFrame",
    "PartyMemberFrame4PetFrame",
    "PartyMemberFrame1TargetFrame",
    "PartyMemberFrame2TargetFrame",
    "PartyMemberFrame3TargetFrame",
    "PartyMemberFrame4TargetFrame",
    "TargetFrame",
    "TargetFrameToT",
    "TargetFrameToTTargetFrame",
    "FocusFrame",
    "FocusFrameToT",
    "Boss1TargetFrame",
    "Boss2TargetFrame",
    "Boss3TargetFrame",
    "Boss4TargetFrame",
    "Boss5TargetFrame",
    "ArenaEnemyFrame1",
    "ArenaEnemyFrame2",
    "ArenaEnemyFrame3",
    "ArenaPrepFrame1",
    "ArenaPrepFrame2",
    "ArenaPrepFrame3",
    "ArenaFrame1",
    "ArenaFrame2",
    "ArenaFrame3",
}

local ICON_ITEMS = {
    { text = "不标记", value = 0 },
    { text = "|TInterface\\TargetingFrame\\UI-RaidTargetingIcon_1:16|t 星星", value = 1 },
    { text = "|TInterface\\TargetingFrame\\UI-RaidTargetingIcon_2:16|t 圆圈", value = 2 },
    { text = "|TInterface\\TargetingFrame\\UI-RaidTargetingIcon_3:16|t 菱形", value = 3 },
    { text = "|TInterface\\TargetingFrame\\UI-RaidTargetingIcon_4:16|t 三角", value = 4 },
    { text = "|TInterface\\TargetingFrame\\UI-RaidTargetingIcon_5:16|t 月亮", value = 5 },
    { text = "|TInterface\\TargetingFrame\\UI-RaidTargetingIcon_6:16|t 方块", value = 6 },
    { text = "|TInterface\\TargetingFrame\\UI-RaidTargetingIcon_7:16|t 叉叉", value = 7 },
    { text = "|TInterface\\TargetingFrame\\UI-RaidTargetingIcon_8:16|t 骷髅", value = 8 },
}

local MODIFIER_ITEMS = {
    { text = "不使用", value = 0 },
    { text = "Shift + 左键", value = 1 },
    { text = "Ctrl + 左键", value = 2 },
    { text = "Alt + 左键", value = 3 },
}

local frame = CreateFrame("Frame")
local focusButton
local optionsFrame
local pendingApply = false
local hookedCompactUnitFrame = false
local lastAnnounceAt = 0

local function Print(message)
    print("|cff00ff99[FocusHelper]|r " .. tostring(message))
end

local function EnsureDB()
    --if type(FocusHelperDB) ~= "table" then FocusHelperDB = {} end

    for key, value in pairs(DEFAULTS) do
        if ShiGuangDB[key] == nil then
            ShiGuangDB[key] = value
        end
    end
end

local function GetItemText(items, value)
    for _, item in ipairs(items) do
        if item.value == value then
            return item.text
        end
    end
    return items[1].text
end

local function BuildMacroText()
    local icon = tonumber(ShiGuangDB.setFocusIcon) or 8
    local macro = "/focus [@mouseover,exists]"

    if icon > 0 then
        macro = macro .. "\n/tm [@mouseover,exists] " .. icon
    end

    return macro
end

local function EnsureFocusButton()
    if focusButton then
        return focusButton
    end

    focusButton = CreateFrame("CheckButton", "FocusHelperFocusButton", UIParent, "SecureActionButtonTemplate")
    focusButton:RegisterForClicks("AnyDown", "AnyUp")
    focusButton:SetAttribute("type", "macro")
    return focusButton
end

local function ClearFrameAttributes(unitFrame)
    if not unitFrame or not unitFrame.SetAttribute then
        return
    end

    unitFrame:SetAttribute("shift-type1", nil)
    unitFrame:SetAttribute("shift-macrotext1", nil)
    unitFrame:SetAttribute("ctrl-type1", nil)
    unitFrame:SetAttribute("ctrl-macrotext1", nil)
    unitFrame:SetAttribute("alt-type1", nil)
    unitFrame:SetAttribute("alt-macrotext1", nil)
end

local function ApplyToUnitFrame(unitFrame)
    if not unitFrame or not unitFrame.SetAttribute then
        return
    end

    if InCombatLockdown() then
        pendingApply = true
        return
    end

    ClearFrameAttributes(unitFrame)

    local modifier = MODIFIERS[tonumber(ShiGuangDB.setFocusMod) or 0]
    if not modifier then
        return
    end

    unitFrame:SetAttribute(modifier.attribute .. "-type1", "macro")
    unitFrame:SetAttribute(modifier.attribute .. "-macrotext1", BuildMacroText())
end

local function ApplyGlobalBinding()
    if InCombatLockdown() then
        pendingApply = true
        return
    end

    local button = EnsureFocusButton()
    ClearOverrideBindings(button)

    local modifier = MODIFIERS[tonumber(ShiGuangDB.setFocusMod) or 0]
    if not modifier then
        return
    end

    button:SetAttribute("macrotext1", BuildMacroText())
    SetOverrideBindingClick(button, true, modifier.binding .. "-BUTTON1", button:GetName())
end

local function ApplyAllFocusBindings()
    if InCombatLockdown() then
        pendingApply = true
        return
    end

    pendingApply = false
    ApplyGlobalBinding()

    for _, frameName in ipairs(UNIT_FRAME_NAMES) do
        ApplyToUnitFrame(_G[frameName])
    end

    if C_NamePlate and C_NamePlate.GetNamePlates then
        for _, namePlate in ipairs(C_NamePlate.GetNamePlates()) do
            if namePlate and namePlate.UnitFrame then
                ApplyToUnitFrame(namePlate.UnitFrame)
            end
        end
    end
end

local function HookCompactUnitFrames()
    if hookedCompactUnitFrame or not CompactUnitFrame_UpdateName then
        return
    end

    hooksecurefunc("CompactUnitFrame_UpdateName", function(unitFrame)
        if unitFrame and unitFrame.unit and string.match(unitFrame.unit, "nameplate") then
            ApplyToUnitFrame(unitFrame)
        end
    end)

    hookedCompactUnitFrame = true
end

local function GetChatChannel()
    if IsInGroup(LE_PARTY_CATEGORY_INSTANCE) then
        return "INSTANCE_CHAT"
    end

    if IsInRaid() then
        return "RAID"
    end

    if IsInGroup() then
        return "PARTY"
    end

    return nil
end

local function AnnounceFocusIcon(force)
    local icon = tonumber(ShiGuangDB.setFocusIcon) or 8
    if icon <= 0 then
        if force then
            Print("当前没有选择标记，未通报。")
        end
        return
    end

    if C_Secrets and C_Secrets.ShouldAurasBeSecret and C_Secrets.ShouldAurasBeSecret() then
        return
    end

    local now = GetTime()
    if not force and now - lastAnnounceAt < 10 then
        return
    end

    local channel = GetChatChannel()
    if not channel then
        if force then
            Print("你当前不在队伍中，未通报。")
        end
        return
    end

    lastAnnounceAt = now
    C_ChatInfo.SendChatMessage("我负责打断 {rt" .. icon .. "}", channel)
end

local function CreateDropdown(parent, labelText, items, getValue, setValue, yOffset)
    local label = parent:CreateFontString(nil, "OVERLAY", "GameFontNormal")
    label:SetPoint("TOPLEFT", 18, yOffset)
    label:SetText(labelText)

    local dropdown = CreateFrame("Frame", nil, parent, "UIDropDownMenuTemplate")
    dropdown:SetPoint("TOPLEFT", 0, yOffset - 20)
    UIDropDownMenu_SetWidth(dropdown, 180)
    UIDropDownMenu_SetText(dropdown, GetItemText(items, getValue()))

    UIDropDownMenu_Initialize(dropdown, function(self, level)
        for _, item in ipairs(items) do
            local info = UIDropDownMenu_CreateInfo()
            info.text = item.text
            info.value = item.value
            info.checked = getValue() == item.value
            info.func = function()
                setValue(item.value)
                UIDropDownMenu_SetText(dropdown, item.text)
                CloseDropDownMenus()
            end
            UIDropDownMenu_AddButton(info, level)
        end
    end)

    return dropdown
end

local function CreateCheckButton(parent, text, tooltip, getValue, setValue, yOffset)
    local check = CreateFrame("CheckButton", nil, parent, "ChatConfigCheckButtonTemplate")
    check:SetPoint("TOPLEFT", 18, yOffset)
    check.Text:SetText(text)
    check:SetChecked(getValue())
    check:SetScript("OnClick", function(self)
        setValue(self:GetChecked())
    end)

    if tooltip and tooltip ~= "" then
        check:SetScript("OnEnter", function(self)
            GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
            GameTooltip:SetText(tooltip, 1, 1, 1, 1, true)
            GameTooltip:Show()
        end)
        check:SetScript("OnLeave", function()
            GameTooltip:Hide()
        end)
    end

    return check
end

local function CreateOptionsFrame()
    if optionsFrame then
        return optionsFrame
    end

    local f = CreateFrame("Frame", "FocusHelperOptionsFrame", UIParent, "BasicFrameTemplateWithInset")
    f:SetSize(360, 300)
    f:SetPoint("CENTER")
    f:SetFrameStrata("DIALOG")
    f:SetMovable(true)
    f:EnableMouse(true)
    f:RegisterForDrag("LeftButton")
    f:SetScript("OnDragStart", f.StartMoving)
    f:SetScript("OnDragStop", f.StopMovingOrSizing)
    f:Hide()

    f.Title = f:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
    f.Title:SetPoint("CENTER", f.TitleBg, "CENTER", 0, 0)
    f.Title:SetText("FocusHelper 焦点助手")

    CreateDropdown(f, "设置焦点快捷键", MODIFIER_ITEMS, function()
        return tonumber(ShiGuangDB.setFocusMod) or 0
    end, function(value)
        ShiGuangDB.setFocusMod = value
        ApplyAllFocusBindings()
    end, -42)

    CreateDropdown(f, "设置焦点时自动标记", ICON_ITEMS, function()
        return tonumber(ShiGuangDB.setFocusIcon) or 8
    end, function(value)
        ShiGuangDB.setFocusIcon = value
        ApplyAllFocusBindings()
    end, -112)

    CreateCheckButton(f, "大秘境开始时通报标记", "触发大秘境开始事件后，在队伍频道发送：我负责打断 {rt图标}", function()
        return not not ShiGuangDB.announceOnChallengeStart
    end, function(value)
        ShiGuangDB.announceOnChallengeStart = value
    end, -188)

    CreateCheckButton(f, "就位确认时通报标记", "如果你也想保留 PlateColor 的就位确认通报逻辑，可以开启这个选项。", function()
        return not not ShiGuangDB.announceOnReadyCheck
    end, function(value)
        ShiGuangDB.announceOnReadyCheck = value
    end, -218)

    local apply = CreateFrame("Button", nil, f, "UIPanelButtonTemplate")
    apply:SetSize(96, 24)
    apply:SetPoint("BOTTOMLEFT", 18, 16)
    apply:SetText("重新应用")
    apply:SetScript("OnClick", function()
        ApplyAllFocusBindings()
        Print("快捷焦点绑定已重新应用。")
    end)

    local announce = CreateFrame("Button", nil, f, "UIPanelButtonTemplate")
    announce:SetSize(96, 24)
    announce:SetPoint("LEFT", apply, "RIGHT", 10, 0)
    announce:SetText("立即通报")
    announce:SetScript("OnClick", function()
        AnnounceFocusIcon(true)
    end)

    local close = CreateFrame("Button", nil, f, "UIPanelButtonTemplate")
    close:SetSize(72, 24)
    close:SetPoint("BOTTOMRIGHT", -18, 16)
    close:SetText("关闭")
    close:SetScript("OnClick", function()
        f:Hide()
    end)

    optionsFrame = f
    return f
end

local function ToggleOptionsFrame()
    local f = CreateOptionsFrame()
    if f:IsShown() then
        f:Hide()
    else
        f:Show()
    end
end

local function HandleSlashCommand(message)
    message = (message or ""):lower():match("^%s*(.-)%s*$")

    if message == "apply" then
        ApplyAllFocusBindings()
        Print("快捷焦点绑定已重新应用。")
    elseif message == "announce" then
        AnnounceFocusIcon(true)
    else
        ToggleOptionsFrame()
        Print("命令：/fh 打开设置，/fh apply 重新应用，/fh announce 立即通报。")
    end
end

frame:RegisterEvent("ADDON_LOADED")
frame:RegisterEvent("PLAYER_LOGIN")
frame:RegisterEvent("PLAYER_ENTERING_WORLD")
frame:RegisterEvent("PLAYER_REGEN_ENABLED")
frame:RegisterEvent("NAME_PLATE_UNIT_ADDED")
frame:RegisterEvent("CHALLENGE_MODE_START")
frame:RegisterEvent("READY_CHECK")
frame:SetScript("OnEvent", function(_, event, arg1)
    if event == "ADDON_LOADED" then
        EnsureDB()
        SLASH_FOCUSHELPER1 = "/fh"
        SLASH_FOCUSHELPER2 = "/focushelper"
        SlashCmdList.FOCUSHELPER = HandleSlashCommand
        return
    end

    EnsureDB()

    if event == "PLAYER_LOGIN" then
        HookCompactUnitFrames()
        ApplyAllFocusBindings()
    elseif event == "PLAYER_ENTERING_WORLD" then
        ApplyAllFocusBindings()
    elseif event == "PLAYER_REGEN_ENABLED" then
        if pendingApply then
            ApplyAllFocusBindings()
        end
    elseif event == "NAME_PLATE_UNIT_ADDED" then
        if C_NamePlate and C_NamePlate.GetNamePlateForUnit then
            local namePlate = C_NamePlate.GetNamePlateForUnit(arg1)
            if namePlate and namePlate.UnitFrame then
                ApplyToUnitFrame(namePlate.UnitFrame)
            end
        end
    elseif event == "CHALLENGE_MODE_START" then
        if ShiGuangDB.announceOnChallengeStart then
            AnnounceFocusIcon(false)
        end
    elseif event == "READY_CHECK" then
        if ShiGuangDB.announceOnReadyCheck then
            AnnounceFocusIcon(false)
        end
    end
end)
