local thj = {}
-- _G["SpellFlashCore"] = thj
_G["SFC"] = thj
thj.info = {
    key = nil,
    keyCD = nil,
    isCombat = false,
    isChanneling = false,
    isQuesting = false
}
thj.items = {}
thj.keyMapping = {}
local _, clzName = UnitClass('player');
-- thj.LS={}
thj.meta = {
    clzName = clzName
}
--[[
格式化打印方法
@param fmt 格式化字符串 eg: "测试格式 {1} {2} {3}"
@param ... 参数列表 eg: 123 "demo" false
@return string 格式化后的字符串,eg: "测试格式 123 demo false"
]]
local LogWithFormat = function(fmt, ...)
    local args = {...}
    local rv = fmt
    for i = 0, #args do
        rv = string.gsub(rv, "{" .. i .. "}", tostring(args[i]))
    end
    return rv
end
-- 日志显示级别, 0:debug及以上, 1:info及以上, 2:warn及以上, 3:error及以上， 4: 不显示
thj.LogLevel = 0
thj.logger = {
    Debug = function(fmt, ...)
        if thj.LogLevel > 0 then
            return
        end
        print("|cff808080[DEBUG]|r " .. LogWithFormat(fmt, ...))
    end,
    Info = function(fmt, ...)
        if thj.LogLevel > 1 then
            return
        end
        print("|cff00ff00[INFO]|r " .. LogWithFormat(fmt, ...))
    end,
    Warn = function(fmt, ...)
        if thj.LogLevel > 2 then
            return
        end
        print("|cffffff00[WARN]|r " .. LogWithFormat(fmt, ...))
    end,
    Error = function(fmt, ...)
        if thj.LogLevel > 3 then
            return
        end
        print("|cffff0000[ERROR]|r " .. LogWithFormat(fmt, ...))
    end
}

thj.createFrame = function(opt)
    local name, parent = opt.name, opt.parent or UIParent
    local width, height = opt.width or 300, opt.height or 200
    local f = CreateFrame("Frame", name, parent);
    f:SetWidth(width)
    f:SetHeight(height)
    f:SetPoint(unpack(opt.anchor or {"CENTER", 0, 0}))
    -- 配置事件监控
    f:SetScript("OnEvent", function(self, evtName, ...)
        if self[evtName] then
            if evtName == "COMBAT_LOG_EVENT_UNFILTERED" then
                local timestamp, subEvt, _, sourceGUID, sourceName, sourceFlags, sourceRaidFlags, destGUID, destName,
                    destFlags, destRaidFlags, extraArg1, extraArg2, extraArg3, extraArg4, extraArg5, extraArg6,
                    extraArg7, extraArg8, extraArg9, extraArg10 = CombatLogGetCurrentEventInfo()
                if self[subEvt] then
                    self[subEvt](self, sourceGUID, sourceName, destGUID, destName, extraArg1, extraArg2, extraArg3,
                        extraArg4, extraArg5, extraArg6, extraArg7, extraArg8, extraArg9, extraArg10);
                end
            else
                self[evtName](self, evtName, ...);
            end
        end
    end)
    return f;
end

local keyMapping = {
    ["BACKSPACE"] = 8,
    ["TAB"] = 9,
    ["ENTER"] = 13,
    ["SPACE"] = 32,
    ["MOUSEWHEELDOWN"] = 174,
    ["MOUSEWHEELUP"] = 175,
    ["MwD"] = 174,
    ["MwU"] = 175,
    ["F1"] = 112,
    ["F2"] = 113,
    ["F3"] = 114,
    ["F4"] = 115,
    ["F5"] = 116,
    ["F6"] = 117,
    ["F7"] = 118,
    ["F8"] = 119,
    ["F9"] = 120,
    ["F10"] = 121,
    ["F11"] = 122,
    ["F12"] = 123,
    ["1"] = 49,
    ["2"] = 50,
    ["3"] = 51,
    ["4"] = 52,
    ["5"] = 53,
    ["6"] = 54,
    ["7"] = 55,
    ["8"] = 56,
    ["9"] = 57,
    ["0"] = 48,
    ["A"] = 65,
    ["B"] = 66,
    ["C"] = 67,
    ["D"] = 68,
    ["E"] = 69,
    ["F"] = 70,
    ["G"] = 71,
    ["H"] = 72,
    ["I"] = 73,
    ["J"] = 74,
    ["K"] = 75,
    ["L"] = 76,
    ["M"] = 77,
    ["N"] = 78,
    ["O"] = 79,
    ["P"] = 80,
    ["Q"] = 81,
    ["R"] = 82,
    ["S"] = 83,
    ["T"] = 84,
    ["U"] = 85,
    ["V"] = 86,
    ["W"] = 87,
    ["X"] = 88,
    ["Y"] = 89,
    ["Z"] = 90,
    [";"] = 186,
    ["'"] = 222,
    [","] = 188,
    ["."] = 190,
    ["/"] = 191,
    ["`"] = 192,
    ["-"] = 189,
    ["="] = 187,
    ["["] = 219,
    ["\\"] = 220,
    ["]"] = 221,
    ["LEFT"] = 37,
    ["RIGHT"] = 39,
    ["UP"] = 38,
    ["DOWN"] = 40,
    ["INSERT"] = 45,
    ["DELETE"] = 46,
    ["PAGEUP"] = 33,
    ["PAGEDOWN"] = 34,
    ["HOME"] = 36,
    ["END"] = 35
}
thj.rawKeys = keyMapping
local km = thj.keyMapping;
for k, v in pairs(keyMapping) do
    km[k] = {
        key = v
    }
    km["C" .. k] = {
        control = true,
        key = v
    }
    km["A" .. k] = {
        alt = true,
        key = v
    }
    km["S" .. k] = {
        shift = true,
        key = v
    }
    km["AC" .. k] = {
        alt = true,
        control = true,
        key = v
    }
    km["CS" .. k] = {
        shift = true,
        control = true,
        key = v
    }
    km["AS" .. k] = {
        alt = true,
        shift = true,
        key = v
    }
    km["ACS" .. k] = {
        alt = true,
        control = true,
        shift = true,
        key = v
    }
end
--[[
高四位 XX10 后2位固定10，前2为数据位
]]
local cdSpells = {
    [1719] = "鲁莽",
    [107574] = "天神下凡"
}
thj.cdSpells = cdSpells;
local counterSpells = {
    SpellReflection = 10000,
    Berserk = 10001
}
thj.counterSpells = counterSpells;

local log = thj.logger;
--[[ 创建UI ]]
local SIZE = 5;
local BLOCK_COUNT = 2;
local C = {
    MAIN_SPELL_INDEX = 1,
    CD_SPELL_INDEX = 2
}
local sfo = thj.createFrame({
    name = "SFOFrame",
    width = 200,
    height = 10,
    anchor = {"TOPLEFT", 0, 0}
})
sfo:SetFrameStrata("HIGH")
sfo:SetFrameLevel(10000)

thj.frame = sfo;
--[[
UI规划
[1.定位点][2.状态][3.主技能][4.无CD][5.定位点]
]]
local function newTex(x)
    local tx = sfo:CreateTexture(nil, "ARTWORK");
    tx:SetColorTexture(0, 0, 0);
    tx:SetSize(SIZE, SIZE);
    tx:SetPoint("TOPLEFT", sfo, x, 0)
    return tx;
end
local blocks = {}
for i = 1, BLOCK_COUNT do
    local tx = newTex(i * SIZE - SIZE);
    table.insert(blocks, tx);
end

local function getSpellColor(key)
    local r, g, b;
    local info = thj.info;
    local km = thj.keyMapping[key or ""];
    if not km then
        r = 0;
        g = 0;
    else
        -- r = 组合键标志位<CCAASS00> ctrl | alt | shift  
        r = (km.control and 1 or 0) * 0xC0 + (km.alt and 1 or 0) * 0x30 + (km.shift and 1 or 0) * 0xC
        -- g = 按键编码
        g = km.key;
    end
    b = ((info.isCombat and not info.isMounted) and 1 or 0) * 0xC0 + (info.isChanneling and 1 or 0) * 0x30;
    return r, g, b;
end
thj.Repaint = function()
    local info = thj.info;
    local r, g, b = getSpellColor(info.key)
    -- log.Info("UpdateSpell key = {1} , r = {2}, g = {3}, b = {4} ", info.key, r, g, b)
    blocks[C.MAIN_SPELL_INDEX]:SetColorTexture(r / 255, g / 255, b / 255)
end

local sfo = thj.frame;
local GetSpellInfo = C_Spell.GetSpellInfo

local Hekili

--[[                                  公共方法                              ]]
--[[设置战斗状态]]
thj.SetCombat = function(flag)
    thj.info.isCombat = flag;
    thj.Repaint();
end
--[[设置通道施法状态]]
thj.SetChanneling = function(flag)
    thj.info.isChanneling = flag;
    thj.Repaint();
end
local allTimer
--[[
    事件注册
]]

function HekiliAutoCast_Setup()
    local allowAcceptNew = true
    local OrigHekiliUpdate = Hekili.Update
    Hekili.Update = function()
        allowAcceptNew = true
        OrigHekiliUpdate();
    end
    local OrigGetBindingForAction = Hekili.GetBindingForAction
    Hekili.GetBindingForAction = function(key, display, i)
        local result, secondResult = OrigGetBindingForAction(key, display, i)
        if allowAcceptNew then
            thj.FlashKey(result)
            allowAcceptNew = false
        end
        return result, secondResult
    end
end
sfo:RegisterEvent("ADDON_LOADED")
function sfo:ADDON_LOADED(evt, name)
    if (name == "Hekili") then
        Hekili = _G["Hekili"]
        C_Timer.After(1, function()
            --log.Debug("Hekili loaded!")
            HekiliAutoCast_Setup()
        end)
    end
end

-- 战斗状态指示
sfo:RegisterEvent("PLAYER_REGEN_ENABLED")
function sfo:PLAYER_REGEN_ENABLED()
    -- print("PLAYER_REGEN_ENABLED  ")
    thj.SetCombat(false)
end
sfo:RegisterEvent("PLAYER_REGEN_DISABLED")
function sfo:PLAYER_REGEN_DISABLED()
    -- print("PLAYER_REGEN_DISABLED  ")
    thj.SetCombat(true)
end
-- Chennel状态指示 
sfo:RegisterUnitEvent("UNIT_SPELLCAST_CHANNEL_START", "player")
function sfo:UNIT_SPELLCAST_CHANNEL_START()
    -- print("UNIT_SPELLCAST_CHANNEL_START  ")
    thj.SetChanneling(true);
end
sfo:RegisterUnitEvent("UNIT_SPELLCAST_CHANNEL_STOP", "player")
function sfo:UNIT_SPELLCAST_CHANNEL_STOP()
    -- print("UNIT_SPELLCAST_CHANNEL_STOP  ")
    thj.SetChanneling(false);
end
local cache = {}
sfo:RegisterUnitEvent("UNIT_SPELLCAST_EMPOWER_START", "player")
function sfo:UNIT_SPELLCAST_EMPOWER_START(unitTarget, castGUID, spellID)
    -- print("UNIT_SPELLCAST_EMPOWER_START", unitTarget, castGUID, spellID)
    local name, text, texture, startTime, endTime, isTradeSkill, notInterruptible, spellID, _, numStages =
        UnitChannelInfo("player");
    local totalTime = 0;
    for i = 1, numStages + 1, 1 do
        local duration = GetUnitEmpowerStageDuration("player", i - 1)
        totalTime = totalTime + duration;
    end
    totalTime = totalTime / 1000
    log.Warn("Empower spell should stop in {1} seconds!!!", totalTime)
    C_Timer.After(totalTime, function()
        log.Debug("Delay done! Set state = UP")
        -- thj.Repaint();
    end)
end
-- UI update interval
local INTERVAL = 0.2
local lastKey = nil
local empowering = false
-- local lastUpdate = 0;
-- sfo:SetScript("OnUpdate", function(self, elapsed)
--     log.Debug("OnUpdate.elapsed = ", elapsed)
--     lastUpdate = lastUpdate + elapsed;
--     -- 每秒更新坐骑状态，当在坐骑上时不释放技能，否则马上进入战斗，放个技能又下马了
--     if lastUpdate > 0.1 then
--         lastUpdate = 0;
--         thj.info.isMounted = IsMounted("player");
--         thj.UpdateState();
--     end
-- end)
-- C_Timer.NewTicker(INTERVAL, function()
--     if not Hekili then
--         return
--     end
--     thj.info.isMounted = IsMounted("player");
--     thj.UpdateState();
--     local recommends = Hekili.DisplayPool["Primary"].Recommendations
--     local firstKeybind = nil

--     local curSequence = recommends[1]
--     local curSpellName, curSpellId, curKey, empowerTo = curSequence.actionName, curSequence.actionID,
--         curSequence.keybind, curSequence.empower_to or 0
--     if not curSpellId then
--         return
--     end
--     if not curKey then
--         log.Warn("Unknown spell {1}, id = {2}", curSpellName, curSpellId)
--         return
--     end

--     if curKey ~= lastKey then
--         lastKey = curKey
--         if empowerTo > 1 and not empowering then
--             empowering = true
--             log.Debug("Enpower spell detected! Level = {1}", empowerTo)
--             -- thj.info.keyState = "down"
--         end
--         -- thj.FlashKey(curKey)
--     else
--         return
--     end
--     thj.UpdateState();
--     thj.Repaint();
-- end)
--[[
    SFO API
]]

--[[
    根据按键进行技能提示
]]
thj.FlashKey = function(key, slot)
    slot = slot or ""
    -- 非战斗 或者 通道施法状态 不响应
    -- if not thj.info.isCombat or thj.info.isChanneling then
    --     return
    -- end
    if not key then
        return
    end
    if thj.cdSpells[key] then
        return
    end
    thj.info["key" .. slot] = key;
    local curSpell = Hekili.DisplayPool["Primary"].Recommendations[1]
    local empLvl = curSpell.empower_to or 0
    if empLvl > 1 then
        empowering = false
        log.Debug("Enpower spell detected!")
    end
    -- log.Info("Flash key {1} with slot {2}, empowering = {3} ", key, slot, empLvl)
    thj.Repaint()
end
--[[
    API: 根据技能ID获取技能名称
    @param id: 技能ID
    @returns 技能名称
]]
-- /dump Hekili.KeybindInfo[Hekili.Class.abilities["奥术智慧"].key]

local function GetSpellMeta(spellIdOrName)
    local hekiliDef = Hekili.Class.abilities[spellIdOrName]
    if not hekiliDef then
        log.Error("|cffff2020 Spell: {1} not found in HEKILI!|r", spellIdOrName)
        return nil
    end
    local id, name, simcName = hekiliDef.id, hekiliDef.name, hekiliDef.key;
    local key;
    local bindings = Hekili.KeybindInfo[simcName];
    if bindings then
        for k, v in pairs(bindings.upper) do
            key = v
        end
    end
    return id, name, key;
end
thj.StartQuesting = function()
    thj.info.isQuesting = true;
end
thj.StopQuesting = function()
    thj.info.isQuesting = false;
end

local cp = CreateFrame('Frame', 'hkc', UIParent)
-- 位置可移动，宽高分别为205 150
cp:SetPoint('BOTTOM', UIParent, 'BOTTOM', -485, 95)
cp:SetSize(1, 1)
--cp.TitleText:SetText("|cff777777Hekili快捷开关")
cp:SetScript('OnHide', function() cpIcon:Show() end);
cp:SetFrameStrata("LOW")
cp:Show()
cp:SetAlpha(1)

local cpIcon = CreateFrame('Frame', 'cpIcon', UIParent)
--local _,className = UnitClass("player")
--local texture = cpIcon:CreateTexture()
--if className == "HUNTER" then className = "SHAMAN" end
--texture:SetTexture("Interface\\Addons\\OrzUI\\Media\\Emotes\\禁")
--texture:SetAllPoints(cpIcon)
local cptext = cpIcon:CreateFontString()
cptext:SetFont(STANDARD_TEXT_FONT, 15, "OUTLINE")
cptext:SetText("2-UI")
cptext:SetPoint("TOPLEFT", cpIcon, "TOPLEFT", 3, -3)
thj.debugger = text;
cpIcon:SetSize( 50, 20 )
cpIcon:SetPoint('RIGHT', cp, 'LEFT', 0, 0)
cpIcon:SetFrameStrata("LOW")
cpIcon:SetMovable(true)
cpIcon:SetClampedToScreen(true)
cpIcon:SetScript('OnMouseUp', function()
    cpIcon:StopMovingOrSizing();
end);
cpIcon:SetScript('OnMouseDown', function()
    cpIcon:StartMoving();
     Hekili:FireToggle('cooldowns')
end);
cpIcon:Show()

local function SetDisplayMode(mode)
    Hekili.DB.profile.toggles.mode.value = mode
    if WeakAuras and WeakAuras.ScanEvents then
        WeakAuras.ScanEvents('HEKILI_TOGGLE', 'mode', mode)
    end
    -- if ns.UI.Minimap then ns.UI.Minimap:RefreshDataText() end
    Hekili:UpdateDisplayVisibility()
    Hekili:ForceUpdate('HEKILI_TOGGLE', true)
end

-- 爆发监控/控制按钮 
--[[local btnCD = thj.createSwitchButton({
    name = "CoolDownButton",
    parent = cp,
    text = "爆发",
    getter = function()
        return Hekili.DB.profile.toggles.cooldowns.value
    end,
    setter = function(v)
        Hekili:FireToggle('cooldowns')
    end,
    width = 50,
    height = 20,
    anchor = {"LEFT", cpIcon, "RIGHT", 0, 0},
    tip = function()
        return Hekili.DB.profile.toggles.cooldowns.key or "未设置"
    end
})
local btnMinorCD = thj.createSwitchButton({
    name = "MinorCDButton",
    parent = cp,
    text = "大招",
    getter = function()
        return Hekili.DB.profile.toggles.essences.value
    end,
    setter = function(v)
        Hekili:FireToggle('essences')
    end,
    width = 50,
    height = 20,
    anchor = {"LEFT", btnCD, "RIGHT", 0, 0},
    tip = function()
        return Hekili.DB.profile.toggles.essences.key or "未设置"
    end
})
-- 保命 监控/控制按钮 
local btnDefensives = thj.createSwitchButton({
    name = "DefensivesButton",
    parent = cp,
    text = "保命",
    getter = function()
        return Hekili.DB.profile.toggles.defensives.value
    end,
    setter = function(v)
        Hekili:FireToggle('defensives')
    end,
    width = 50,
    height = 20,
    anchor = {"LEFT", btnMinorCD, "RIGHT", 0, 0},
    tip = function()
        return Hekili.DB.profile.toggles.defensives.key or "未设置"
    end
}) 
-- 打断 监控/控制按钮 
local btnInterrupt = thj.createSwitchButton({
    name = "InterruptsButton",
    parent = cp,
    text = "打断",
    getter = function()
        return Hekili.DB.profile.toggles.interrupts.value
    end,
    setter = function(v)
        Hekili:FireToggle('interrupts')
    end,
    width = 50,
    height = 20,
    anchor = {"TOP", cpIcon, "BOTTOM", 0, 0},
    tip = function()
        return Hekili.DB.profile.toggles.interrupts.key or "未设置"
    end
}) 
-- 嗑药 监控/控制按钮 
local btnPotions = thj.createSwitchButton({
    name = "PotionButton",
    parent = cp,
    text = "药剂",
    getter = function()
        return Hekili.DB.profile.toggles.potions.value
    end,
    setter = function(v)
        Hekili:FireToggle('potions')
    end,
    width = 50,
    height = 20,
    anchor = {"LEFT", btnInterrupt, "RIGHT", 0, 0},
    tip = function()
        return Hekili.DB.profile.toggles.potions.key or "未设置"
    end
}) 

-----------------模式切换按钮----------------
-- 自动模式 监控/控制按钮 
local btnAuto = thj.createSwitchButton({
    name = "AutoButton",
    parent = cp,
    text = "自动",
    getter = function()
        return Hekili.DB.profile.toggles.mode.value == "automatic"
    end,
    setter = function(v)
        SetDisplayMode('automatic')
    end,
    width = 50,
    height = 20,
    anchor = {"LEFT", btnPotions, "RIGHT", 0, 0}
}) 
-- AOE 监控/控制按钮 
local btnAOE = thj.createSwitchButton({
    name = "AOEButton",
    parent = cp,
    text = "AOE",
    getter = function()
        return Hekili.DB.profile.toggles.mode.value == "aoe"
    end,
    setter = function(v)
        SetDisplayMode('aoe')
    end,
    width = 50,
    height = 20,
    anchor = {"LEFT", btnAuto, "RIGHT", 0, 0}
}) 
-- 单体 监控/控制按钮 
local btnSingle = thj.createSwitchButton({
    name = "SingleButton",
    parent = cp,
    text = "单体",
    getter = function()
        return Hekili.DB.profile.toggles.mode.value == "single"
    end,
    setter = function(v)
        SetDisplayMode('single')
    end,
    width = 50,
    height = 20,
    anchor = {"TOP", btnInterrupt, "BOTTOM", 0, 0}
})
-- 双显 监控/控制按钮 
local btnDual = thj.createSwitchButton({
    name = "DualButton",
    parent = cp,
    text = "双显",
    getter = function()
        return Hekili.DB.profile.toggles.mode.value == "dual"
    end,
    setter = function(v)
        SetDisplayMode('dual')
    end,
    width = 50,
    height = 20,
    anchor = {"LEFT", btnSingle, "RIGHT", 0, 0}
})
-- 响应 监控/控制按钮 
local btnReactive = thj.createSwitchButton({
    name = "ReactiveButton",
    parent = cp,
    text = "响应",
    getter = function()
        return Hekili.DB.profile.toggles.mode.value == "reactive"
    end,
    setter = function(v)
        SetDisplayMode('reactive')
    end,
    width = 50,
    height = 20,
    anchor = {"LEFT", btnDual, "RIGHT", 0, 0}
})
-- 漏斗 监控/控制按钮 
local btnFunnel = thj.createSwitchButton({
    name = "FunnelButton",
    parent = cp,
    text = "漏斗",
    getter = function()
        return Hekili.DB.profile.toggles.mode.value == "funnel"
    end,
    setter = function(v)
        SetDisplayMode('funnel')
    end,
    width = 50,
    height = 20,
    anchor = {"LEFT", btnReactive, "RIGHT", 0, 0},
    tip = "漏斗模式：AOE时用群攻技能攒能量，施放单体终结技。\n适用于敏锐、奇袭、增强、毁灭专精。"
})
-- 播放按键声音钮 
local btnVoice = thj.createSwitchButton({
    name = "VoiceButton",
    parent = cp,
    text = "语音",
    getter = function()
        return HSstop
    end,
    setter = function(v)
        HSstop = false
    end,
    width = 60,
    height = 20,
    anchor = {"LEFT", btnFunnel, "RIGHT", 0, 0},
    tip = "语音播报下一个按键"
})]]

