-------------------------
-- AiB Gear Check
-------------------------

local EQUIPMENT_SLOTS = {
    { id = 13, name = "Schmuck 1" },
    { id = 14, name = "Schmuck 2" },
    { id = 16, name = "Haupthand" },
    { id = 17, name = "Nebenhand" },
}

local ENCHANTABLE_SLOTS = {
    { id = 1,  name = "Kopf" },
    { id = 3,  name = "Schulter" },
    { id = 5,  name = "Brust" },
    { id = 7,  name = "Beine" },
    { id = 8,  name = "Füße" },
    { id = 11, name = "Ring 1" },
    { id = 12, name = "Ring 2" },
    { id = 16, name = "Haupthand" },
    { id = 17, name = "Nebenhand" },
}

local ALL_SLOT_NAMES = {
    [1]="Kopf",      [2]="Hals",       [3]="Schulter",
    [5]="Brust",     [6]="Taille",     [7]="Beine",
    [8]="Füße",      [9]="Handgelenk", [10]="Hände",
    [11]="Ring 1",   [12]="Ring 2",    [13]="Schmuck 1",
    [14]="Schmuck 2",[15]="Rücken",    [16]="Haupthand",
    [17]="Nebenhand",
}

-- Hals/Ringe: Pflicht-Sockel | Kopf/Gürtel/Armschienen: optional
local GEM_SLOTS          = { 1, 2, 6, 9, 11, 12 }
local GEM_MANDATORY      = { [2]=true, [11]=true, [12]=true }
local OIL_WARN_MS        = 600000   -- 10 Minuten in ms
local EMBELL_BONUS_ID    = "8960"

-- Optimale Öl-SpellIDs
local APPROVED_OILS = { [8052]=true, [8054]=true }

-- Zugelassene Gem-IDs (beste Qualität = 3, Midnight)
local APPROVED_GEMS = {
    [240856]=true, [240858]=true, [240860]=true, [240862]=true,
    [240864]=true, [240866]=true, [240868]=true, [240870]=true,
    [240872]=true, [240874]=true, [240876]=true, [240878]=true,
    [240880]=true, [240882]=true, [240884]=true, [240886]=true,
    [240888]=true, [240890]=true, [240892]=true, [240894]=true,
    [240896]=true, [240898]=true, [240900]=true, [240902]=true,
    [240904]=true, [240906]=true, [240908]=true, [240910]=true,
    [240912]=true, [240914]=true, [240916]=true, [240918]=true,
    [240967]=true, [240969]=true, [240971]=true, [240983]=true,
}

-- Zugelassene Enchant-IDs (beste Qualität = 3, Midnight)
-- Plus IDs mit value=2 wo kein Epic existiert (z.B. Bein-Verzauberungen)
local APPROVED_ENCHANTS = {
    -- Epic (value=3) Enchants
    [7949]=true, [7957]=true, [7959]=true, [7961]=true, [7963]=true,
    [7965]=true, [7967]=true, [7969]=true, [7971]=true, [7973]=true,
    [7975]=true, [7977]=true, [7979]=true, [7981]=true, [7983]=true,
    [7985]=true, [7987]=true, [7989]=true, [7991]=true, [7993]=true,
    [7995]=true, [7997]=true, [7999]=true, [8001]=true, [8003]=true,
    [8005]=true, [8007]=true, [8009]=true, [8011]=true, [8013]=true,
    [8015]=true, [8017]=true, [8019]=true, [8021]=true, [8023]=true,
    [8025]=true, [8027]=true, [8029]=true, [8031]=true, [8033]=true,
    [8035]=true, [8037]=true, [8039]=true, [8041]=true, [8043]=true,
    [8045]=true, [8047]=true,
    -- DK-Runen (Rune of the Fallen Crusader etc.)
    [3368]=true, [3370]=true, [3847]=true,
    [7905]=true, [7908]=true, [7910]=true,
    [7935]=true, [7937]=true, [7939]=true,
    [8052]=true, [8054]=true, [8056]=true,
    [8159]=true, [8161]=true, [8163]=true,  -- Bein-Verzauberungen
    [8609]=true, [8611]=true, [8613]=true, [8615]=true,
}

-- Mainstat-Gem IDs: alle Größen zählen als "vorhanden"
-- Qualität wird separat via APPROVED_GEMS geprüft (nur Epic = optimal)
local MAINSTAT_GEM_IDS = {
    [240967]=true, [240969]=true, [240971]=true, [240983]=true,  -- groß (optimal)
    [240966]=true, [240968]=true, [240970]=true, [240982]=true,  -- klein (nicht optimal)
}

local DEFAULTS = {
    showOnInstance   = true,
    showOnReadyCheck = true,
    autoHideDelay    = 10,
    iconSize         = 40,
    point            = "CENTER",
    x                = 0,
    y                = 100,
    ecEnabled        = false,
    ecUseAllSpecs    = true,
    ecSpecRules      = {},
}

-- Character-Frame Slot-Namen für Highlighting
local SLOT_FRAME_NAMES = {
    [1]  = "CharacterHeadSlot",
    [2]  = "CharacterNeckSlot",
    [3]  = "CharacterShoulderSlot",
    [5]  = "CharacterChestSlot",
    [6]  = "CharacterWaistSlot",
    [7]  = "CharacterLegsSlot",
    [8]  = "CharacterFeetSlot",
    [9]  = "CharacterWristSlot",
    [10] = "CharacterHandsSlot",
    [11] = "CharacterFinger0Slot",
    [12] = "CharacterFinger1Slot",
    [13] = "CharacterTrinket0Slot",
    [14] = "CharacterTrinket1Slot",
    [15] = "CharacterBackSlot",
    [16] = "CharacterMainHandSlot",
    [17] = "CharacterSecondaryHandSlot",
}

local slotHighlights = {}  -- aktive Highlight-Overlays

local equipmentFrame  = nil
local itemButtons     = {}
local autoHideTimer   = nil
local issueLines      = {}

-- Forward-Deklarationen für gegenseitige Referenzen
local ApplySlotHighlights
local ClearSlotHighlights
local GetAllIssues

local function GetDB()
    AiB_GearCheckConfig = AiB_GearCheckConfig or {}
    for k, v in pairs(DEFAULTS) do
        if AiB_GearCheckConfig[k] == nil then
            AiB_GearCheckConfig[k] = type(v) == "table" and {} or v
        end
    end
    return AiB_GearCheckConfig
end

-------------------------
-- Enchant Helper (Item-Link)
-------------------------

local function GetEnchantFromLink(slotID)
    local link = GetInventoryItemLink("player", slotID)
    if not link then return nil, nil end
    if slotID == 17 then
        local equipLoc = select(9, C_Item.GetItemInfo(link))
        if equipLoc == "INVTYPE_SHIELD" or equipLoc == "INVTYPE_HOLDABLE" then
            return nil, nil
        end
    end
    local _, enchantID = link:match("item:(%d+):(%d+)")
    enchantID = tonumber(enchantID)
    if not enchantID or enchantID == 0 then return nil, nil end
    local info = C_Spell.GetSpellInfo(enchantID)
    return info and info.name or ("ID:" .. enchantID), enchantID
end

-------------------------
-- Alle Issues sammeln
-------------------------

GetAllIssues = function()
    local db = GetDB()
    if not db.ecEnabled then return nil end

    local issues = {}
    local function add(text, r, g, b, slotID, kind)
        table.insert(issues, { text=text, r=r, g=g, b=b, slotID=slotID, kind=kind })
    end
    local function err(text, slotID, kind)  add(text, 1, 0.35, 0.35, slotID, kind or "err")  end
    local function warn(text, slotID, kind) add(text, 1, 0.75, 0.1,  slotID, kind or "warn") end

    local enchOK, oilOK, gemOK = true, true, true

    -- 1. Verzauberungen
    for _, slot in ipairs(ENCHANTABLE_SLOTS) do
        if GetInventoryItemID("player", slot.id) then
            local enchName, enchID = GetEnchantFromLink(slot.id)
            if not enchName then
                err(slot.name .. ": Verzauberung fehlt", slot.id, "err")
                enchOK = false
            elseif not APPROVED_ENCHANTS[enchID] then
                err(slot.name .. ": Verzauberung nicht optimal", slot.id, "warn")
                enchOK = false
            end
        end
    end

    -- 2. Öl
    local hasMain, mainExp, _, mainEnchID, hasOff, offExp, _, offEnchID = GetWeaponEnchantInfo()
    if GetInventoryItemID("player", 16) then
        if not hasMain then
            err("Haupthand: Öl fehlt", 16, "err")
            oilOK = false
        elseif mainEnchID and not APPROVED_OILS[mainEnchID] then
            err("Haupthand: Öl nicht optimal", 16, "warn")
            oilOK = false
        elseif mainExp and mainExp > 0 and mainExp < OIL_WARN_MS then
            local m = math.floor(mainExp / 60000)
            local s = math.floor((mainExp % 60000) / 1000)
            warn("Haupthand Öl: noch " .. m .. "m " .. s .. "s", 16, "warn")
            oilOK = false
        end
    end
    if GetInventoryItemID("player", 17) then
        local link17   = GetInventoryItemLink("player", 17)
        local equipLoc = link17 and select(9, C_Item.GetItemInfo(link17))
        local canBeOiled = equipLoc ~= "INVTYPE_SHIELD" and equipLoc ~= "INVTYPE_HOLDABLE"
        if canBeOiled then
            if not hasOff then
                err("Nebenhand: Öl fehlt", 17, "err")
                oilOK = false
            elseif offEnchID and not APPROVED_OILS[offEnchID] then
                err("Nebenhand: Öl nicht optimal", 17, "warn")
                oilOK = false
            elseif offExp and offExp > 0 and offExp < OIL_WARN_MS then
                local m = math.floor(offExp / 60000)
                local s = math.floor((offExp % 60000) / 1000)
                warn("Nebenhand Öl: noch " .. m .. "m " .. s .. "s", 17, "warn")
                oilOK = false
            end
        end
    end

    -- 3. Sockel + Mainstat-Gem + Gem-Qualität
    local hasMainstatGem = false
    for _, slotID in ipairs(GEM_SLOTS) do
        local link = GetInventoryItemLink("player", slotID)
        if link then
            local itemString = link:match("item:[%-?%d:]+")
            if itemString then
                -- Socket-Anzahl via GetItemStats
                local stats = C_Item.GetItemStats(itemString)
                local totalSockets = 0
                if stats then
                    for key, num in pairs(stats) do
                        if key:find("EMPTY_SOCKET_") then
                            totalSockets = totalSockets + num
                        end
                    end
                end

                -- Gem-IDs via GetItemGem(fullLink, index) → 2. Rückgabewert ist der Gem-Link
                local filledGems = {}
                for i = 1, math.max(totalSockets, GEM_MANDATORY[slotID] and 1 or 0) do
                    local _, gemLink = C_Item.GetItemGem(link, i)
                    if gemLink then
                        local gemID = tonumber(gemLink:match("item:(%d+)"))
                        if gemID then
                            table.insert(filledGems, gemID)
                        end
                    end
                end

                -- Mainstat + Qualität prüfen
                for _, gemID in ipairs(filledGems) do
                    if MAINSTAT_GEM_IDS[gemID] then
                        hasMainstatGem = true
                    end
                    if not APPROVED_GEMS[gemID] then
                        err((ALL_SLOT_NAMES[slotID] or "Slot"..slotID) .. ": Gem nicht optimal", slotID, "warn")
                        gemOK = false
                    end
                end

                -- Leerer Sockel prüfen
                local filledCount = #filledGems
                if GEM_MANDATORY[slotID] then
                    if totalSockets == 0 or filledCount == 0 then
                        err((ALL_SLOT_NAMES[slotID] or "Slot"..slotID) .. ": Leerer Sockel", slotID, "err")
                        gemOK = false
                    end
                elseif totalSockets > 0 and filledCount == 0 then
                    err((ALL_SLOT_NAMES[slotID] or "Slot"..slotID) .. ": Leerer Sockel", slotID, "err")
                    gemOK = false
                end
            end
        end
    end
    if not hasMainstatGem then
        err("Mainstat-Gem fehlt", nil, "err")
        gemOK = false
    end

    -- 4. Embellishments
    local embCount = 0
    for _, slotID in ipairs({1,2,3,5,6,7,8,9,10,11,12,13,14,15,16,17}) do
        local link = GetInventoryItemLink("player", slotID)
        if link then
            local itemString = link:match("item:[%-?%d:]+")
            if itemString and string.find(itemString, EMBELL_BONUS_ID) then
                embCount = embCount + 1
            end
        end
    end
    if embCount < 2 then
        err("Embellishments: " .. embCount .. "/2", nil, "err")
    end

    -- OK-Zeilen für Kategorien ohne Fehler
    if enchOK then
        table.insert(issues, { text="VZ OK",   r=0.3, g=0.85, b=0.3, kind="ok" })
    end
    if oilOK then
        table.insert(issues, { text="Öle OK",  r=0.3, g=0.85, b=0.3, kind="ok" })
    end
    if gemOK then
        table.insert(issues, { text="Gems OK", r=0.3, g=0.85, b=0.3, kind="ok" })
    end

    return issues
end

-------------------------
-- Item Buttons
-------------------------

local function UpdateSlot(button, slotID)
    local texture = GetInventoryItemTexture("player", slotID)
    local quality = GetInventoryItemQuality("player", slotID)
    if texture then
        button.icon:SetTexture(texture)
        button.icon:SetTexCoord(0.08, 0.92, 0.08, 0.92)
        button.icon:Show()
        if quality and quality >= 0 then
            local r, g, b = C_Item.GetItemQualityColor(quality)
            button.border:SetVertexColor(r, g, b, 1)
            button.border:Show()
        else
            button.border:Hide()
        end
    else
        button.icon:SetTexture(0)
        button.icon:Hide()
        button.border:Hide()
    end
end

local function CreateItemButton(parent, slotID, slotName)
    local db   = GetDB()
    local size = db.iconSize or 40
    local btn  = CreateFrame("Button", nil, parent)
    btn:SetSize(size, size)
    btn.slotID   = slotID
    btn.slotName = slotName

    local icon = btn:CreateTexture(nil, "ARTWORK")
    icon:SetAllPoints()
    btn.icon = icon

    local borderSize = 2
    local borderTextures = {}
    local sides = {
        { p1="TOPLEFT",    p2="TOPRIGHT",    x1=-borderSize, y1=borderSize,  x2=borderSize,  y2=0          },
        { p1="BOTTOMLEFT", p2="BOTTOMRIGHT", x1=-borderSize, y1=0,           x2=borderSize,  y2=-borderSize },
        { p1="TOPLEFT",    p2="BOTTOMLEFT",  x1=-borderSize, y1=borderSize,  x2=0,           y2=-borderSize },
        { p1="TOPRIGHT",   p2="BOTTOMRIGHT", x1=0,           y1=borderSize,  x2=borderSize,  y2=-borderSize },
    }
    for i, s in ipairs(sides) do
        local t = btn:CreateTexture(nil, "OVERLAY")
        t:SetPoint(s.p1, btn, s.p1, s.x1, s.y1)
        t:SetPoint(s.p2, btn, s.p2, s.x2, s.y2)
        t:SetColorTexture(1, 1, 1, 1)
        borderTextures[i] = t
    end
    btn.border = {
        SetVertexColor = function(_, r, g, b, a) for _, t in ipairs(borderTextures) do t:SetVertexColor(r,g,b,a or 1) end end,
        Show = function() for _, t in ipairs(borderTextures) do t:Show() end end,
        Hide = function() for _, t in ipairs(borderTextures) do t:Hide() end end,
    }

    btn:SetScript("OnEnter", function(self)
        GameTooltip:SetOwner(self, "ANCHOR_BOTTOMRIGHT")
        if GetInventoryItemID("player", self.slotID) then
            GameTooltip:SetInventoryItem("player", self.slotID)
        else
            GameTooltip:SetText(self.slotName .. " - Leer")
        end
        GameTooltip:Show()
    end)
    btn:SetScript("OnLeave", function() GameTooltip:Hide() end)
    return btn
end

-------------------------
-- Issue Display (direkt im Frame)
-------------------------

local function UpdateIssueDisplay()
    if not equipmentFrame then return end
    local db = GetDB()

    -- Alte Zeilen entfernen
    for _, fs in ipairs(issueLines) do
        fs:Hide()
        fs:SetParent(nil)
    end
    issueLines = {}

    if not db.ecEnabled then
        -- Nur Header-Bereich anzeigen
        equipmentFrame:SetHeight(equipmentFrame._separator and
            (equipmentFrame._separator:GetBottom() and
             equipmentFrame:GetTop() - equipmentFrame._separator:GetBottom() + 8) or 90)
        return
    end

    local issues = GetAllIssues()
    if not issues or #issues == 0 then return end

    local lineH   = 18
    local padTop  = 6
    local padBot  = 8

    local anchor = equipmentFrame._separator  -- erste Zeile relativ zur Trennlinie

    for i, issue in ipairs(issues) do
        local fs = CreateFrame("Frame", nil, equipmentFrame)
        fs:SetHeight(lineH)
        fs:SetPoint("LEFT",  equipmentFrame, "LEFT",  8, 0)
        fs:SetPoint("RIGHT", equipmentFrame, "RIGHT", -8, 0)
        if i == 1 then
            fs:SetPoint("TOP", anchor, "BOTTOM", 0, -padTop)
        else
            fs:SetPoint("TOP", issueLines[i-1], "BOTTOM", 0, 0)
        end

        local text = fs:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
        text:SetAllPoints()
        text:SetJustifyH("LEFT")
        text:SetJustifyV("MIDDLE")
        text:SetText(issue.text)
        text:SetTextColor(issue.r, issue.g, issue.b)

        fs:Show()
        table.insert(issueLines, fs)
    end

    -- Frame-Höhe dynamisch anpassen
    C_Timer.After(0.05, function()
        if not equipmentFrame or not equipmentFrame:IsShown() then return end
        local lastLine = issueLines[#issueLines]
        if lastLine then
            local frameTop  = equipmentFrame:GetTop()
            local lineBot   = lastLine:GetBottom()
            if frameTop and lineBot then
                local needed = frameTop - lineBot + padBot
                equipmentFrame:SetHeight(math.max(needed, 80))
            end
        end
    end)

    -- Character-Slot-Highlights aktualisieren
    ApplySlotHighlights(issues)
end

-------------------------
-- Character Slot Highlighting
-------------------------

local highlightTimer = nil

ClearSlotHighlights = function()
    for _, hl in pairs(slotHighlights) do
        if hl.anim then hl.anim:Stop() end
        hl:Hide()
        hl:SetParent(nil)
    end
    slotHighlights = {}
    if highlightTimer then
        highlightTimer:Cancel()
        highlightTimer = nil
    end
end

ApplySlotHighlights = function(issues)
    ClearSlotHighlights()
    if not CharacterFrame or not CharacterFrame:IsShown() then return end

    -- Sammle Slot-Status: "err" hat Vorrang vor "warn"
    local slotStatus = {}
    for _, issue in ipairs(issues) do
        if issue.slotID and issue.kind ~= "ok" then
            local current = slotStatus[issue.slotID]
            if not current or (issue.kind == "err" and current == "warn") then
                slotStatus[issue.slotID] = issue.kind
            end
        end
    end

    for slotID, status in pairs(slotStatus) do
        local frameName = SLOT_FRAME_NAMES[slotID]
        local slotFrame = frameName and _G[frameName]
        if slotFrame then
            local hl = CreateFrame("Frame", nil, slotFrame)
            hl:SetAllPoints()
            hl:SetFrameLevel(slotFrame:GetFrameLevel() + 5)

            local tex = hl:CreateTexture(nil, "OVERLAY")
            tex:SetAllPoints()
            tex:SetTexture([[Interface\Buttons\WHITE8x8]])
            if status == "err" then
                tex:SetVertexColor(1, 0, 0, 1)
            else
                tex:SetVertexColor(1, 0.5, 0, 1)
            end
            hl.tex = tex

            -- Puls-Animation
            local ag = hl:CreateAnimationGroup()
            ag:SetLooping("REPEAT")
            local fadeIn = ag:CreateAnimation("Alpha")
            fadeIn:SetFromAlpha(0)
            fadeIn:SetToAlpha(0.55)
            fadeIn:SetDuration(0.6)
            fadeIn:SetOrder(1)
            local fadeOut = ag:CreateAnimation("Alpha")
            fadeOut:SetFromAlpha(0.55)
            fadeOut:SetToAlpha(0)
            fadeOut:SetDuration(0.6)
            fadeOut:SetOrder(2)
            ag:Play()
            hl.anim = ag

            hl:Show()
            slotHighlights[slotID] = hl
        end
    end
end

local function RefreshHighlights()
    local db = GetDB()
    if not db.ecEnabled or not CharacterFrame or not CharacterFrame:IsShown() then
        ClearSlotHighlights()
        return
    end
    local issues = GetAllIssues()
    if issues then ApplySlotHighlights(issues) end
end

local function CreateEquipmentFrame()
    if equipmentFrame then return equipmentFrame end
    local db = GetDB()

    local frame = CreateFrame("Frame", "AiB_GearCheckFrame", UIParent, "BackdropTemplate")
    frame:SetSize(260, 90)
    frame:SetPoint(db.point or "CENTER", UIParent, db.point or "CENTER", db.x or 0, db.y or 100)
    frame:SetFrameStrata("HIGH")
    frame:SetClampedToScreen(true)
    frame:EnableMouse(true)
    frame:SetMovable(true)
    frame:RegisterForDrag("LeftButton")
    frame:SetBackdrop({
        bgFile   = [[Interface\Buttons\WHITE8x8]],
        edgeFile = [[Interface\Buttons\WHITE8x8]],
        edgeSize = 1,
    })
    frame:SetBackdropColor(0.1, 0.1, 0.1, 0.95)
    frame:SetBackdropBorderColor(0.6, 0, 0, 1)

    -- Theme dynamisch anwenden falls verfügbar
    if AiB and AiB.Themes then
        AiB.Themes:ApplyToFrame(frame, "bg_primary", "border_accent")
    end

    -- Titel
    local title = frame:CreateFontString(nil, "OVERLAY", "GameFontNormal")
    title:SetPoint("TOP", frame, "TOP", 0, -8)
    title:SetText("|cFFFF0000Gear|r |cFFFFFFFFCheck|r")

    -- Schließen-Button
    local closeBtn = CreateFrame("Button", nil, frame)
    closeBtn:SetSize(16, 16)
    closeBtn:SetPoint("TOPRIGHT", frame, "TOPRIGHT", -4, -4)
    closeBtn:SetNormalTexture([[Interface\Buttons\UI-StopButton]])
    closeBtn:SetHighlightTexture([[Interface\Buttons\UI-StopButton]])
    closeBtn:GetHighlightTexture():SetVertexColor(1, 0.66, 0, 1)
    closeBtn:SetScript("OnClick", function()
        frame:Hide()
        if autoHideTimer then autoHideTimer:Cancel() ; autoHideTimer = nil end
    end)

    -- Item Icons
    local btnContainer = CreateFrame("Frame", nil, frame)
    btnContainer:SetPoint("TOP", title, "BOTTOM", 0, -6)
    btnContainer:SetSize(240, 50)

    local iconSize   = db.iconSize or 40
    local spacing    = 6
    local totalWidth = (#EQUIPMENT_SLOTS * iconSize) + ((#EQUIPMENT_SLOTS - 1) * spacing)
    local startX     = -totalWidth / 2 + iconSize / 2

    for i, slot in ipairs(EQUIPMENT_SLOTS) do
        local btn = CreateItemButton(btnContainer, slot.id, slot.name)
        btn:SetPoint("CENTER", btnContainer, "CENTER", startX + (i-1) * (iconSize + spacing), 0)
        itemButtons[i] = btn
    end

    -- Trennlinie — wird als Anker für die Issue-Zeilen gespeichert
    local sep = frame:CreateTexture(nil, "ARTWORK")
    sep:SetColorTexture(1, 0, 0, 0.4)
    sep:SetHeight(1)
    sep:SetPoint("TOPLEFT",  btnContainer, "BOTTOMLEFT",  -4, -4)
    sep:SetPoint("TOPRIGHT", btnContainer, "BOTTOMRIGHT",  4, -4)
    frame._separator = sep

    frame:SetScript("OnDragStart", function(self) self:StartMoving() end)
    frame:SetScript("OnDragStop", function(self)
        self:StopMovingOrSizing()
        local point, _, _, x, y = self:GetPoint()
        db.point = point
        db.x     = math.floor(x + 0.5)
        db.y     = math.floor(y + 0.5)
    end)

    frame:Hide()
    equipmentFrame = frame
    return frame
end

-------------------------
-- Public API
-------------------------

local function ShowFrame(force)
    local db = GetDB()
    if not force and not db.enabled then return end
    if InCombatLockdown() then return end

    local frame = CreateEquipmentFrame()
    for _, btn in ipairs(itemButtons) do UpdateSlot(btn, btn.slotID) end
    UpdateIssueDisplay()
    frame:Show()

    if autoHideTimer then autoHideTimer:Cancel() ; autoHideTimer = nil end
    local delay = db.autoHideDelay or 10
    if delay > 0 then
        autoHideTimer = C_Timer.NewTimer(delay, function()
            if frame and frame:IsShown() then frame:Hide() end
            autoHideTimer = nil
        end)
    end
end

local function HideFrame()
    if equipmentFrame then equipmentFrame:Hide() end
    if autoHideTimer then autoHideTimer:Cancel() ; autoHideTimer = nil end
end

local function ResetFrame()
    if equipmentFrame then
        equipmentFrame:Hide()
        equipmentFrame:SetParent(nil)
        equipmentFrame = nil
    end
    itemButtons = {}
    issueLines  = {}
end

-------------------------
-- Events
-------------------------

local loader = CreateFrame("Frame", "AiB_GearCheckLoader")
loader:RegisterEvent("PLAYER_LOGIN")
loader:RegisterEvent("PLAYER_ENTERING_WORLD")
loader:RegisterEvent("READY_CHECK")
loader:RegisterEvent("UNIT_INVENTORY_CHANGED")
loader:RegisterEvent("PLAYER_SPECIALIZATION_CHANGED")
loader:RegisterEvent("PLAYER_EQUIPMENT_CHANGED")

loader:SetScript("OnEvent", function(self, event, ...)
    if event == "PLAYER_LOGIN" then
        GetDB()

        -- Debug: Zeigt Gem-Info für alle Gem-Slots
        SLASH_AIBGCGEMS1 = "/gcgems"
        SlashCmdList["AIBGCGEMS"] = function()
            print("|cFFFF0000[AiB GearCheck]|r Gem-Debug:")
            for _, slotID in ipairs(GEM_SLOTS) do
                local link = GetInventoryItemLink("player", slotID)
                if link then
                    local itemString = link:match("item:[%-?%d:]+")
                    local slotName = ALL_SLOT_NAMES[slotID] or "Slot"..slotID
                    if itemString then
                        local stats = C_Item.GetItemStats(itemString)
                        local socketKeys = {}
                        if stats then
                            for k, v in pairs(stats) do
                                if k:find("EMPTY_SOCKET_") then
                                    table.insert(socketKeys, k.."="..v)
                                end
                            end
                        end
                        if #socketKeys > 0 then
                            print("  "..slotName..": Sockets: "..table.concat(socketKeys, ", "))
                            for i = 1, 4 do
                                local _, gemLink = C_Item.GetItemGem(link, i)
                                if gemLink then
                                    local gid = tonumber(gemLink:match("item:(%d+)"))
                                    print("    Gem "..i..": ID="..tostring(gid).." mainstat="..tostring(gid and MAINSTAT_GEM_IDS[gid]==true).." approved="..tostring(gid and APPROVED_GEMS[gid]==true))
                                end
                            end
                        else
                            print("  "..slotName..": Keine EMPTY_SOCKET_ keys in GetItemStats")
                            -- Rohe Felder 4-7 anzeigen
                            local fields = {}
                            for f in itemString:gmatch("[^:]+") do table.insert(fields, f) end
                            print("    Felder 4-7: "..tostring(fields[4])..","..tostring(fields[5])..","..tostring(fields[6])..","..tostring(fields[7]))
                        end
                    end
                end
            end
            -- CharacterFrame Slot-Verfügbarkeit
            print("|cFFFF0000[AiB GearCheck]|r CharFrame Slots:")
            for slotID, frameName in pairs(SLOT_FRAME_NAMES) do
                local f = _G[frameName]
                print("  "..frameName..": "..tostring(f ~= nil))
            end
        end
        SLASH_AIBGCDEBUG1 = "/gcenchants"
        SlashCmdList["AIBGCDEBUG"] = function()
            print("|cFFFF0000[AiB GearCheck]|r Enchant-IDs der aktuellen Ausrüstung:")
            for _, slot in ipairs(ENCHANTABLE_SLOTS) do
                local link = GetInventoryItemLink("player", slot.id)
                if link then
                    local _, enchantID = link:match("item:(%d+):(%d+)")
                    enchantID = tonumber(enchantID)
                    if enchantID and enchantID > 0 then
                        print("  " .. slot.name .. " (Slot " .. slot.id .. "): enchantID = |cFFFFFF00" .. enchantID .. "|r approved=" .. tostring(APPROVED_ENCHANTS[enchantID] == true))
                    else
                        print("  " .. slot.name .. " (Slot " .. slot.id .. "): |cFFFF4444keine Verzauberung|r")
                    end
                end
            end
            -- Öl-Info
            print("|cFFFF0000[AiB GearCheck]|r Öl-Info:")
            local hasMain, mainExp, mainCharges, mainEnchantID, hasOff, offExp, offCharges, offEnchantID = GetWeaponEnchantInfo()
            if GetInventoryItemID("player", 16) then
                if hasMain then
                    local m = math.floor((mainExp or 0) / 60000)
                    local s = math.floor(((mainExp or 0) % 60000) / 1000)
                    print("  Haupthand: Öl-SpellID = |cFFFFFF00" .. tostring(mainEnchantID) .. "|r  Restzeit: " .. m .. "m " .. s .. "s")
                else
                    print("  Haupthand: |cFFFF4444kein Öl|r")
                end
            end
            if GetInventoryItemID("player", 17) then
                local link17  = GetInventoryItemLink("player", 17)
                local equipLoc = link17 and select(9, C_Item.GetItemInfo(link17))
                if equipLoc == "INVTYPE_SHIELD" or equipLoc == "INVTYPE_HOLDABLE" then
                    print("  Nebenhand: Schild/Schildhand — kein Öl möglich (equipLoc=" .. tostring(equipLoc) .. ")")
                elseif hasOff then
                    local m = math.floor((offExp or 0) / 60000)
                    local s = math.floor(((offExp or 0) % 60000) / 1000)
                    print("  Nebenhand: Öl-SpellID = |cFFFFFF00" .. tostring(offEnchantID) .. "|r  Restzeit: " .. m .. "m " .. s .. "s")
                else
                    print("  Nebenhand: |cFFFF4444kein Öl|r")
                end
            end
        end

    elseif event == "PLAYER_ENTERING_WORLD" then
        local db = GetDB()
        if not db.enabled or not db.showOnInstance then return end
        local inInstance, instanceType = IsInInstance()
        if inInstance and (instanceType=="party" or instanceType=="raid" or instanceType=="scenario") then
            C_Timer.After(1, function()
                if not InCombatLockdown() then ShowFrame() end
            end)
        end

    elseif event == "READY_CHECK" then
        local db = GetDB()
        if not db.enabled or not db.showOnReadyCheck then return end
        C_Timer.After(0.2, function()
            if not InCombatLockdown() then ShowFrame() end
        end)

    elseif event == "UNIT_INVENTORY_CHANGED" then
        local unit = ...
        if unit == "player" and equipmentFrame and equipmentFrame:IsShown() then
            for _, btn in ipairs(itemButtons) do UpdateSlot(btn, btn.slotID) end
            UpdateIssueDisplay()
        end

    elseif event == "PLAYER_SPECIALIZATION_CHANGED" then
        local unit = ...
        if unit == "player" and equipmentFrame and equipmentFrame:IsShown() then
            UpdateIssueDisplay()
        end
        RefreshHighlights()

    elseif event == "PLAYER_EQUIPMENT_CHANGED" then
        if equipmentFrame and equipmentFrame:IsShown() then
            for _, btn in ipairs(itemButtons) do UpdateSlot(btn, btn.slotID) end
            UpdateIssueDisplay()
        end
        RefreshHighlights()
    end
end)

-- CharacterFrame Hook: Highlights + Toggle-Button
local gearCheckToggleBtn = nil

local function CreateToggleButton()
    if gearCheckToggleBtn then return end
    local trinket2 = _G["CharacterTrinket1Slot"]
    if not trinket2 then return end

    local btn = CreateFrame("Button", "AiB_GearCheckToggle", CharacterFrame, "BackdropTemplate")
    btn:SetSize(trinket2:GetWidth() * 2 + 4 + 15, 23)
    btn:SetPoint("TOP", trinket2, "BOTTOM", -trinket2:GetWidth() / 2 - 2, -4)
    btn:SetBackdrop({
        bgFile   = "Interface\\Buttons\\WHITE8x8",
        edgeFile = "Interface\\Buttons\\WHITE8x8",
        edgeSize = 1,
    })
    btn:SetBackdropColor(0.1, 0.1, 0.1, 0.95)
    btn:SetBackdropBorderColor(0.6, 0, 0, 1)
    if AiB and AiB.Themes then
        AiB.Themes:ApplyToFrame(btn, "bg_primary", "border_accent")
    end

    local label = btn:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
    label:SetPoint("CENTER")
    label:SetText("|cFFFF0000Gear|r |cFFFFFFFFCheck|r")
    btn.label = label

    btn:SetScript("OnClick", function()
        if equipmentFrame and equipmentFrame:IsShown() then
            HideFrame()
        else
            ShowFrame()
        end
    end)
    btn:SetScript("OnEnter", function(self)
        self:SetBackdropBorderColor(1, 0.5, 0, 1)
        if AiB and AiB.Animations then AiB.Animations:StartGlow(self) end
        GameTooltip:SetOwner(self, "ANCHOR_BOTTOM")
        GameTooltip:SetText("Gear Check öffnen/schließen", 1, 1, 1)
        GameTooltip:Show()
    end)
    btn:SetScript("OnLeave", function(self)
        self:SetBackdropBorderColor(0.6, 0, 0, 1)
        if AiB and AiB.Animations then AiB.Animations:StopGlow(self) end
        GameTooltip:Hide()
    end)

    gearCheckToggleBtn = btn
end

hooksecurefunc("ShowUIPanel", function(frame)
    if frame == CharacterFrame then
        C_Timer.After(0.1, function()
            CreateToggleButton()
            if gearCheckToggleBtn then gearCheckToggleBtn:Show() end
            RefreshHighlights()
        end)
    end
end)

hooksecurefunc("HideUIPanel", function(frame)
    if frame == CharacterFrame then
        if gearCheckToggleBtn then gearCheckToggleBtn:Hide() end
        ClearSlotHighlights()
    end
end)

-- Exportiere für Settings-Modul
AiB = AiB or {}
AiB.GearCheck = {
    ShowFrame          = ShowFrame,
    HideFrame          = HideFrame,
    ResetFrame         = ResetFrame,
    GetEnchantFromLink = GetEnchantFromLink,
    ENCHANTABLE_SLOTS  = ENCHANTABLE_SLOTS,
}
