-- modules/SpecClass.lua
-- SpecClass datatext for Simple DataTexts (BDT)
local _, ns = ...
local BDT = ns.DataTexts
local L = BDT.L

local mod = {}

----------------------------------------------------
-- Lua Locals
----------------------------------------------------
local ipairs = ipairs
local tinsert = table.insert
local tremove = table.remove
local format = format
local next = next
local strjoin = strjoin

----------------------------------------------------
-- WoW API Locals
----------------------------------------------------
local GetNumSpecializations   = GetNumSpecializations
local GetPvpTalentInfoByID    = GetPvpTalentInfoByID
local GetSpecialization       = GetSpecialization
local GetSpecializationInfo   = GetSpecializationInfo
local IsControlKeyDown        = IsControlKeyDown
local IsShiftKeyDown          = IsShiftKeyDown
local TogglePlayerSpellsFrame = TogglePlayerSpellsFrame
-- C_AddOns
local IsAddOnLoaded           = C_AddOns.IsAddOnLoaded
local LoadAddOn               = C_AddOns.LoadAddOn
-- C_ClassTalents
local GetActiveConfigID       = C_ClassTalents.GetActiveConfigID
local GetHasStarterBuild      = C_ClassTalents.GetHasStarterBuild
local GetStarterBuildActive   = C_ClassTalents.GetStarterBuildActive
local GetConfigIDsBySpecID    = C_ClassTalents.GetConfigIDsBySpecID
local GetLastSelectedSavedConfigID = C_ClassTalents.GetLastSelectedSavedConfigID
local LoadConfig              = C_ClassTalents.LoadConfig
local SetStarterBuildActive   = C_ClassTalents.SetStarterBuildActive
-- C_SpecializationInfo
local C_SpecializationInfo_GetAllSelectedPvpTalentIDs = C_SpecializationInfo.GetAllSelectedPvpTalentIDs
local SetSpecialization       = C_SpecializationInfo.SetSpecialization or SetSpecialization
-- C_Timer
local Delay                   = C_Timer.After
-- C_Traits
local C_Traits_GetConfigInfo  = C_Traits.GetConfigInfo
-- MenuUtil
local CreateContextMenu       = MenuUtil.CreateContextMenu
-- PlayerUtil
local CanUseClassTalents      = PlayerUtil.CanUseClassTalents
local GetCurrentSpecID        = PlayerUtil.GetCurrentSpecID

----------------------------------------------------
-- Constants Locals
----------------------------------------------------
local UNKNOWN                 = UNKNOWN
local PVP_TALENTS             = PVP_TALENTS
local BLUE_FONT_COLOR         = BLUE_FONT_COLOR
local STARTER_ID              = Constants.TraitConsts.STARTER_BUILD_TRAIT_CONFIG_ID

----------------------------------------------------
-- File Locals
----------------------------------------------------
local activeString = strjoin('', '|cff00FF00', _G.ACTIVE_PETS or L["Active"], '|r')
local inactiveString = strjoin('', '|cffFF0000', _G.FACTION_INACTIVE or L["Inactive"], '|r')
local moduleName = "Class Specialization"

----------------------------------------------------
-- Lists
----------------------------------------------------
local specList = { { text = SPECIALIZATION, isTitle = true, notCheckable = true } }
local loadoutList = { { text = L["Loadouts"], isTitle = true, notCheckable = true } }

----------------------------------------------------
-- Module Config Settings
----------------------------------------------------
local function SetupModuleConfig()
    BDT.ModuleRegistry:AddModuleConfigSetting(moduleName, "checkbox", "Show Label", "showLabel", true)
    BDT.ModuleRegistry:AddModuleConfigSetting(moduleName, "checkbox", L["Show Specialization Icon"], "showSpecIcon", true)
    BDT.ModuleRegistry:AddModuleConfigSetting(moduleName, "checkbox", L["Show Specialization Text"], "showSpecText", true)
    BDT.ModuleRegistry:AddModuleConfigSetting(moduleName, "checkbox", L["Show Loadout"], "showLoadout", true)

    BDT.ModuleRegistry:GlobalModuleSettings(moduleName)
end

SetupModuleConfig()

----------------------------------------------------
-- Helpers
----------------------------------------------------
local function AddTexture(texture)
    if not texture then return '' end
    local icon = format('|T%s:16:16:0:0:50:50:4:46:4:46|t', texture)
    return icon
end

local function StarterChecked()
    return GetStarterBuildActive and GetStarterBuildActive()
end

local function EnsureTalentUI()
    if IsAddOnLoaded("Blizzard_PlayerSpells") then
        return true
    end

    local loaded, reason = UIParentLoadAddOn("Blizzard_PlayerSpells")

    if not loaded then
        print(format(L["Failed to load Blizzard_PlayerSpells: %s"], tostring(reason)))
        return false
    end

    return true
end

local queuedLoadoutID
local LoadoutFunc
do
    LoadoutFunc = function(_, arg1)
        if arg1 == STARTER_ID then
            if GetStarterBuildActive() then
                return
            end
            if not InCombatLockdown() then
                SetStarterBuildActive(true)
            end
            return
        end

        if not InCombatLockdown() then
            queuedLoadoutID = arg1
            C_ClassTalents.LoadConfig(arg1, true)
        end
    end
end

local function SpecChecked(data) return data and data.arg1 == GetSpecialization() end
local function SpecFunc(_, arg1) SetSpecialization(arg1) end

local function WrapMenuFunc(func)
    return function(self, arg1)
        if func then
            func(self, arg1)
        end
        if DropDownList1 then
            DropDownList1:Hide()
        end
    end
end

----------------------------------------------------
-- Module Creation
----------------------------------------------------
function mod.Create(slotFrame)
    local f = CreateFrame("Frame", nil, slotFrame)
    f:SetAllPoints(slotFrame)
    f:EnableMouse(false)

    local text = slotFrame.text
    if not text then
        text = slotFrame:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
        text:SetPoint("CENTER")
        slotFrame.text = text
    end

    -- Create the menu frame for this module
    local menuFrame = CreateFrame("Frame", "BDT_SpecMenuFrame", UIParent, "UIDropDownMenuTemplate")

    local activeSpecIndex = nil

    ----------------------------------------------------
    -- Build/refresh spec and loadout lists
    ----------------------------------------------------
    local function BuildSpecList()
        if #specList <= 1 then
            local n = GetNumSpecializations and GetNumSpecializations() or 0
            for index = 1, n do
                local id, name, _, icon = GetSpecializationInfo(index)
                if id then
                    tinsert(specList, { arg1 = index, text = format('|T%s:16:16:0:0|t  %s', icon or "", name), checked = SpecChecked, func = WrapMenuFunc(SpecFunc) })
                end
            end
        end
    end

    local function BuildLoadoutList()
        local builds = nil
        local classTalentsAvailable = GetConfigIDsBySpecID and GetLastSelectedSavedConfigID
        local specIndex = GetSpecialization()
        local info = specIndex and (select(1, GetSpecializationInfo(specIndex)) and { id = select(1, GetSpecializationInfo(specIndex)), icon = select(4, GetSpecializationInfo(specIndex)), name = select(2, GetSpecializationInfo(specIndex)) } or nil)

        loadoutList = { { text = L["Loadouts"], isTitle = true, notCheckable = true } } -- recreate
        if classTalentsAvailable and info and info.id then
            builds = GetConfigIDsBySpecID(info.id) or {}
            -- include starter if supported
            if GetHasStarterBuild and GetHasStarterBuild() and STARTER_ID then
                tinsert(builds, STARTER_ID)
            end

            for idx, configID in ipairs(builds) do
                if configID == STARTER_ID then
                    tinsert(loadoutList, {
                        text = format('|cff%02x%02x%02x%s|r', BLUE_FONT_COLOR.r*255, BLUE_FONT_COLOR.g*255, BLUE_FONT_COLOR.b*255, L["Starter Build"]),
                        checked = StarterChecked,
                        func = WrapMenuFunc(LoadoutFunc),
                        arg1 = STARTER_ID
                    })
                else
                    local configInfo = C_Traits_GetConfigInfo and C_Traits_GetConfigInfo(configID)
                    tinsert(loadoutList, {
                        text = (configInfo and configInfo.name) or UNKNOWN,
                        checked = function(data)
                            local active = GetLastSelectedSavedConfigID and GetLastSelectedSavedConfigID(info.id) or nil
                            return active and data.arg1 == active
                        end,
                        func = WrapMenuFunc(LoadoutFunc),
                        arg1 = configID })
                end
            end
        end
    end

    ----------------------------------------------------
    -- Update displayed text
    ----------------------------------------------------
    local function UpdateDisplay()
        BuildSpecList()

        local settings = {
            showLabel    = BDT:GetModuleSetting(moduleName, "showLabel", true),
            showSpecIcon = BDT:GetModuleSetting(moduleName, "showSpecIcon", true),
            showSpecText = BDT:GetModuleSetting(moduleName, "showSpecText", true),
            showLoadout  = BDT:GetModuleSetting(moduleName, "showLoadout", true)
        }

        local specIndex = GetSpecialization()
        if not specIndex then
            text:SetText("|cff9d9d9d?")
            BDT.FontManager:ApplyModuleFont(moduleName, text)
            return
        end

        local infoID, infoName, _, infoIcon = GetSpecializationInfo(specIndex)
        if not infoID then
            text:SetText("|cff9d9d9d?")
            BDT.FontManager:ApplyModuleFont(moduleName, text)
            return
        end

        activeSpecIndex = specIndex

        -- Build activeLoadoutText
        local activeLoadoutText = ""
        if CanUseClassTalents and CanUseClassTalents() and GetLastSelectedSavedConfigID then
            local classTalentID = GetLastSelectedSavedConfigID(infoID)
            if classTalentID == STARTER_ID then
                activeLoadoutText = "|cff00aaffStarter|r"
            elseif classTalentID then
                local cfg = C_Traits_GetConfigInfo and C_Traits_GetConfigInfo(classTalentID)
                activeLoadoutText = cfg and cfg.name or ""
            end
        end

        -- Helper to format spec display
        local function formatSpecDisplay(icon, name, showIcon, showText, tag)
            if not (showIcon or showText) then return "" end
            local parts = {}
            if tag then parts[#parts + 1] = tag end
            if showIcon and icon then
                parts[#parts + 1] = format('|T%s:16:16:0:0:64:64:4:60:4:60|t', icon)
            end
            if showText then
                parts[#parts + 1] = name or UNKNOWN
            end
            return table.concat(parts, showIcon and showText and " " or "")
        end

        local displayParts = {}

        -- Main spec display
        local specTag = settings.showLabel and L["Spec"]..": " or ""
        local specDisplay = formatSpecDisplay(infoIcon, infoName, settings.showSpecIcon, settings.showSpecText, specTag)
        if specDisplay ~= "" then
            displayParts[#displayParts + 1] = specDisplay
        end

        -- Loadout
        if settings.showLoadout and activeLoadoutText ~= "" then
            displayParts[#displayParts + 1] = activeLoadoutText
        end

        local display = table.concat(displayParts, " / ")
        text:SetText(BDT.FormatUtils:ColorModuleText(moduleName, display))
        BDT.FontManager:ApplyModuleFont(moduleName, text)
    end

    f.Update = UpdateDisplay

    ----------------------------------------------------
    -- Tooltip
    ----------------------------------------------------
    slotFrame:EnableMouse(true)
    slotFrame:SetScript("OnEnter", function(self)
        BDT.Tooltip:SetOwner(self, BDT.FormatUtils:FindBestAnchorPoint(self))
        BDT.Tooltip:ClearLines()
        if not BDT.db.profile.hideModuleTitle then
            BDT.FormatUtils:AddTooltipHeader(BDT.Tooltip, nil, SPECIALIZATION)
            BDT.FormatUtils:AddTooltipLine(BDT.Tooltip, nil, " ")
        end

        for i = 1, GetNumSpecializations() or 0 do
            local id, name, _, icon = GetSpecializationInfo(i)
            if id and name then
                BDT.FormatUtils:AddTooltipLine(BDT.Tooltip, nil, strjoin(' ', BDT.FormatUtils:ColorModuleText(moduleName, name), AddTexture(icon), (i == activeSpecIndex and activeString or inactiveString)), nil, 1, 1, 1)
            end
        end

        BDT.FormatUtils:AddTooltipLine(BDT.Tooltip, nil, " ")
        BDT.FormatUtils:AddTooltipLine(BDT.Tooltip, nil, L["Loadouts"], nil, 0.69, 0.31, 0.31)

        BuildLoadoutList()
        for index, loadout in ipairs(loadoutList) do
            if index > 1 then
                local textStr = (type(loadout.checked) == "function" and loadout.checked(loadout) and activeString) or inactiveString
                BDT.FormatUtils:AddTooltipLine(BDT.Tooltip, nil, strjoin(' - ', loadout.text, textStr), nil, 1, 1, 1)
            end
        end

        BDT.FormatUtils:AddTooltipLine(BDT.Tooltip, nil, " ")
        BDT.FormatUtils:AddTooltipLine(BDT.Tooltip, nil, L["Left Click: Change Talent Specialization"])
        BDT.FormatUtils:AddTooltipLine(BDT.Tooltip, nil, L["Control + Left Click: Change Loadout"])
        BDT.FormatUtils:AddTooltipLine(BDT.Tooltip, nil, L["Shift + Left Click: Show Talent Specialization UI"])

        BDT.Tooltip:Show()
    end)
    slotFrame:SetScript("OnLeave", function() BDT.Tooltip:Hide() end)

    ----------------------------------------------------
    -- Click Handler
    ----------------------------------------------------
    slotFrame:SetScript("OnClick", function(self, button)
        if button == "LeftButton" then
            if IsShiftKeyDown() then
                if EnsureTalentUI() and not InCombatLockdown() then
                    TogglePlayerSpellsFrame()
                end
                return
            end

            if IsControlKeyDown() then
                BuildLoadoutList()
                CreateContextMenu(menuFrame, function(_, root) BDT:HandleMenuList(root, loadoutList, nil, 1) end)
            else
                BuildSpecList()
                CreateContextMenu(menuFrame, function(_, root) BDT:HandleMenuList(root, specList, nil, 1) end)
            end
        end
    end)

    ----------------------------------------------------
    -- Event Handler
    ----------------------------------------------------
    local function OnEvent(self, event, ...)
        if event == "TRAIT_CONFIG_UPDATED" and queuedLoadoutID then
            C_ClassTalents.UpdateLastSelectedSavedConfigID(GetCurrentSpecID(), queuedLoadoutID)
            queuedLoadoutID = nil
        elseif event == "CONFIG_COMMIT_FAILED" then
            queuedLoadoutID = nil
        end
        BuildSpecList()
        BuildLoadoutList()
        UpdateDisplay()
    end

    f:SetScript("OnEvent", OnEvent)
    f:RegisterEvent("PLAYER_ENTERING_WORLD")
    f:RegisterEvent("ACTIVE_TALENT_GROUP_CHANGED")
    f:RegisterEvent("PLAYER_TALENT_UPDATE")
    f:RegisterEvent("TRAIT_CONFIG_DELETED")
    f:RegisterEvent("TRAIT_CONFIG_UPDATED")
    f:RegisterEvent("CONFIG_COMMIT_FAILED")

    UpdateDisplay()

    return f
end

-- Register with BDT
BDT.ModuleRegistry:RegisterDatatext(moduleName, mod)

return mod
