--## Author: Treran ## Version: 1.0.5 ## SavedVariables: BiSJournalDB
local BiSJournal = {}

local DB_KEY
local biSPanel
local itemButtons = {}
local isLocked = false
local manuallyOpened = false
local openedByMinimap = false
local openedBySlashCommmand = false

local GetItemInfoFunc = C_Item and C_Item.GetItemInfo or GetItemInfo
local GetItemInfoInstantFunc = C_Item and C_Item.GetItemInfoInstant or GetItemInfoInstant
local IsEquippableItemFunc = C_Item and C_Item.IsEquippableItem or IsEquippableItem
local GetItemIconFunc = C_Item and C_Item.GetItemIconByID or GetItemIcon
local GetItemQualityColorFunc = C_Item and C_Item.GetItemQualityColor or GetItemQualityColor
local RequestLoadItemDataByIDFunc = C_Item and C_Item.RequestLoadItemDataByID or RequestLoadItemDataByID

-- Database initialization
local function InitializeDB()
    BiSJournalDB.config.isLocked = BiSJournalDB.config.isLocked or false
    local specIndex = GetSpecialization()
    if not specIndex then return end
    
    local specID = GetSpecializationInfo(specIndex)
    local playerGUID = UnitGUID("player")
    
    DB_KEY = playerGUID.."-"..specID
    BiSJournalDB.lists[DB_KEY] = BiSJournalDB.lists[DB_KEY] or {}

    for slot, value in pairs(BiSJournalDB.lists[DB_KEY]) do
        if type(value) ~= "table" then
            BiSJournalDB.lists[DB_KEY][slot] = {value}
        end
    end
end

StaticPopupDialogs["BISJOURNAL_CHAT_SOURCE"] = {
    text = "Enter source information for %s\n(Format: \"Dungeon/Raid - Boss Name\")\n Exact location will allow click back to function",
    button1 = "Add to BiS Journal",
    button2 = CANCEL,
    hasEditBox = true,
    editBoxWidth = 250,
    timeout = 0,
    whileDead = true,
    hideOnEscape = true,
    preferredIndex = 3,
    OnShow = function(self, data)
        self.editBox:SetText("Delve - The War Within")
        self.editBox:HighlightText()
        self.editBox:SetFocus()
        self.data = data -- Store the itemID and name
    end,
    OnAccept = function(self)
        local source = self.editBox:GetText()
        if source == "" then
            source = "Unknown Source - Unknown Location"
        end
        AddToBiSList(self.data.itemID, source)
    end,
}

-- Item handling functions
local function GetItemSlotType(itemID)
    local _, _, _, _, _, _, _, _, itemEquipLoc = GetItemInfoFunc(itemID)
    -- If the item has no equipment location or empty location, it's not equippable
    if not itemEquipLoc or itemEquipLoc == "" or itemEquipLoc == "INVTYPE_NON_EQUIP_IGNORE" then
        return "Misc/Collectible"
    end
    
    return itemEquipLoc
end

local function FormatSlotText(slot)
    -- Handle our custom slot type
    if slot == "Misc/Collectible" then
        return "Misc/Collectible"
    end
    
    -- Remove the "INVTYPE_" prefix
    local formattedSlot = slot:gsub("^INVTYPE_", "")
    
    -- Capitalize the first letter (optional)
    formattedSlot = formattedSlot:sub(1, 1):upper() .. formattedSlot:sub(2):lower()
    
    -- Customize specific slot names if desired
    local customNames = {
        CHEST = "Chest Piece",
        HEAD = "Helmet",
        LEGS = "Leggings",
        FEET = "Boots",
        HANDS = "Gloves",
        FINGER = "Ring",
        TRINKET = "Trinket",
    }
    
    return customNames[formattedSlot] or formattedSlot
end

local function GenerateAcronym(name)
    return name:gsub("%w+", function(word) return word:sub(1,1) end):gsub("%s+", "")
end

local function GetCurrentAdventureGuideTab()
    if not EncounterJournal or not EncounterJournal:IsShown() then
        return nil, "Adventure Guide not open"
    end
    
    -- Check which tab is selected
    local tabIndex = PanelTemplates_GetSelectedTab(EncounterJournal)
    
    -- Map tab indices to names
    local tabNames = {
        [1] = "Traveler's Log",
        [2] = "Suggested Content",
        [3] = "Dungeons",
        [4] = "Raids",
        [5] = "Item Sets"
    }
    
    return tabIndex, tabNames[tabIndex] or "Unknown Tab"
end

function AddToBiSList(itemID, source)
    if not itemID or not DB_KEY then return end

    -- Wait for item info if needed
    if not GetItemInfoFunc(itemID) then
        C_Timer.After(0.5, function() AddToBiSList(itemID, source) end)
        return
    end

    local slot = GetItemSlotType(itemID)
    -- IMPORTANT: Force non-equippable items to use "Misc/Collectible" as the slot
    local _, _, _, _, _, _, _, _, itemEquipLoc = GetItemInfoFunc(itemID)
    if not itemEquipLoc or itemEquipLoc == "" then
        slot = "Misc/Collectible"
    end

    if not slot then return end

        -- Force non-equippable items to use "Misc/Collectible" instead of "non_equip_ignore"
    if slot == "non_equip_ignore" then
        slot = "Misc/Collectible"
    end

    BiSJournalDB.lists[DB_KEY][slot] = BiSJournalDB.lists[DB_KEY][slot] or {}

    local isDuplicate = false
    for _, existingItem in ipairs(BiSJournalDB.lists[DB_KEY][slot]) do
        if type(existingItem) == "table" and existingItem.id == itemID then
            isDuplicate = true
            break
        elseif existingItem == itemID then -- Handle legacy data format
            isDuplicate = true
            break
        end
    end

    if not isDuplicate then
        local instanceName, bossName = source:match("(.+) %- (.+)")
        local shortenedSource

        if instanceName and bossName then     
            shortenedSource = source
        else
            shortenedSource = source
        end

        -- Determine source type
        local sourceType = "unknown"
        local tabIndex, tabName = GetCurrentAdventureGuideTab()
        local isDungeon = false
        
        if MerchantFrame and MerchantFrame:IsShown() then
            sourceType = "vendor"
        elseif tabName == "Dungeons" then
            sourceType = "instance"
            isDungeon = true
        elseif tabName == "Raids" then
            sourceType = "instance"
            isDungeon = false
        elseif source:match("World Quest") then
            sourceType = "worldquest"
        elseif source:match("Delve") then
            sourceType = "delve"
        elseif source:match("PvP") then
            sourceType = "pvp"
        elseif source:match("Crafted") then
            sourceType = "crafted"
        elseif source:match("Manual") then
            sourceType = "manual"
        else
            sourceType = "other"
        end

        local currentExpansion = EJ_GetCurrentTier()

        -- Store as a table with id, source, and sourceType
        local itemData = {
            id = itemID,
            fullSource = source,
            source = shortenedSource or "Unknown source",
            sourceType = sourceType,
            expansion = currentExpansion,
            isDungeon = isDungeon
        }

        table.insert(BiSJournalDB.lists[DB_KEY][slot], itemData)

        local itemName, itemLink = GetItemInfoFunc(itemID)
        print("|cFF00FF00Added|r " .. itemLink .. " |cFF00FF00to BiS list for slot:|r " .. FormatSlotText(slot))
        RefreshBiSPanel()
    else
        local itemName, itemLink = GetItemInfo(itemID)
        print("|cFFFFFF00Item|r " .. itemLink .. " |cFFFFFF00is already in your BiS list.|r")
    end

    RefreshBiSPanel()
end

function RemoveFromBiSList(slot, index)
    if not DB_KEY then return end
    
    if BiSJournalDB.lists[DB_KEY][slot] and BiSJournalDB.lists[DB_KEY][slot][index] then
        local itemData = BiSJournalDB.lists[DB_KEY][slot][index]
        local itemID = type(itemData) == "table" and itemData.id or itemData
        local itemName, itemLink = GetItemInfoFunc(itemID)
        
        -- Remove the specific item at the index
        table.remove(BiSJournalDB.lists[DB_KEY][slot], index)
        
        -- If the slot is now empty, remove the slot entry
        if #BiSJournalDB.lists[DB_KEY][slot] == 0 then
            BiSJournalDB.lists[DB_KEY][slot] = nil
        end
        
        print("|cFFFF0000Removed|r " .. (itemLink or "item") .. " |cFFFF0000from BiS list.|r")
        RefreshBiSPanel()
    end
end

local function SafeCreateFontString(parent, layer, template)
    local fontString = parent:CreateFontString(nil, layer, template)
    if not fontString then
        -- Fallback to a basic font if the template is missing
        fontString = parent:CreateFontString(nil, layer)
        fontString:SetFont("Fonts\\FRIZQT__.TTF", 12) -- Default WoW font with size 12
    end
    return fontString
end

-- Create a minimap button
local minimapButton = CreateFrame("Button", "BiSJournalMinimapButton", Minimap)
minimapButton:SetSize(32, 32)
minimapButton:SetFrameStrata("MEDIUM")
minimapButton:SetFrameLevel(8)
minimapButton:SetPoint("CENTER", Minimap, "CENTER", -80, -20) -- Default position

-- Set the button texture
local texture = minimapButton:CreateTexture(nil, "BACKGROUND")
texture:SetSize(18, 20)
texture:SetPoint("CENTER", minimapButton, "CENTER")
texture:SetTexture("Interface\\Icons\\INV_Misc_Book_09") -- You can choose a different icon
minimapButton.texture = texture

-- Add a border using a built-in template
local border = minimapButton:CreateTexture(nil, "OVERLAY")
border:SetTexture("Interface\\Minimap\\MiniMap-TrackingBorder")
border:SetWidth(54)
border:SetHeight(54)
border:SetPoint("TOPLEFT", minimapButton, "TOPLEFT")

-- Add a border when hovering
minimapButton:SetHighlightTexture("Interface\\Minimap\\UI-Minimap-ZoomButton-Highlight")

-- Make the button draggable around the minimap
minimapButton:RegisterForDrag("LeftButton")
minimapButton:SetScript("OnDragStart", minimapButton.StartMoving)
minimapButton:SetScript("OnDragStop", minimapButton.StopMovingOrSizing)

-- Set up the button's click behavior
minimapButton:SetScript("OnClick", function()
    if biSPanel:IsShown() then
        biSPanel:Hide()
        openedByMinimap = false
        openedBySlashCommmand = false
    else
        if BiSJournalDB.config.panelPosition then
            biSPanel:ClearAllPoints()
            biSPanel:SetPoint(
                BiSJournalDB.config.panelPosition.point,
                UIParent,
                BiSJournalDB.config.panelPosition.relativePoint,
                BiSJournalDB.config.panelPosition.xOfs,
                BiSJournalDB.config.panelPosition.yOfs
            )
        end
        biSPanel:Show()
        openedByMinimap = true
        openedBySlashCommmand = false
        C_Timer.After(0.2, RefreshBiSPanel)
    end
end)

-- Add tooltip
minimapButton:SetScript("OnEnter", function()
    GameTooltip:SetOwner(minimapButton, "ANCHOR_LEFT")
    GameTooltip:SetText("BiS Journal")
    GameTooltip:AddLine("Click to toggle the BiS Journal panel", 1, 1, 1)
    GameTooltip:Show()
end)
minimapButton:SetScript("OnLeave", function()
    GameTooltip:Hide()
end)


-- UI refresh function
function RefreshBiSPanel()
    if not biSPanel or not biSPanel.content or not DB_KEY then return end

    local panelWidth = biSPanel:GetWidth()
    local panelHeight = biSPanel:GetHeight()

    local instructions = biSPanel.instructions
    if instructions then
        instructions:SetWidth(panelWidth - 40)
    end

    local scrollFrame = biSPanel.content:GetParent()
    scrollFrame:SetSize(panelWidth - 30, panelHeight - 100)

    biSPanel.content:SetWidth(panelWidth - 50)

    -- Clear existing buttons
    for _, button in pairs(itemButtons) do
        button:Hide()
    end

    local content = biSPanel.content
    local yOffset = 5
    local index = 1
    local needsRefresh = false

    -- Sort slots for consistent display
    local slots = {}
    for slot in pairs(BiSJournalDB.lists[DB_KEY]) do
        table.insert(slots, slot)
    end
    table.sort(slots)

    for _, slot in ipairs(slots) do
        -- For each item in this slot
        for itemIndex, itemData in ipairs(BiSJournalDB.lists[DB_KEY][slot]) do
            local itemID = type(itemData) == "table" and itemData.id or itemData
            local source = type(itemData) == "table" and itemData.source or "Unknown source"
            
            local itemName = GetItemInfoFunc(itemID)
            if not itemName then
                needsRefresh = true
                C_Item.RequestLoadItemDataByID(itemID)
            else
                local button = itemButtons[index]
                if not button then
                    -- Create a new button if it doesn't exist
                    button = CreateFrame("Button", nil, content)
                    button:SetSize(250, 60)  -- Increase height to accommodate source text
                    
                    -- Icon
                    local icon = button:CreateTexture(nil, "ARTWORK")
                    icon:SetSize(45, 45)
                    icon:SetPoint("LEFT", 5, 0)
                    button.icon = icon
                    
                    -- Text (Main Item Name)
                    local text = SafeCreateFontString(button, "OVERLAY", "GameFontNormal")
                    text:SetPoint("TOPLEFT", icon, "TOPRIGHT", 5, -2)
                    text:SetWidth(180)
                    text:SetJustifyH("LEFT")
                    text:SetWordWrap(false)
                    text:SetHeight(12)
                    button.text = text
                    text:SetFont(text:GetFont(), 13)
                    -- Source Text - Position ABOVE the slot text
                    local sourceText = SafeCreateFontString(button, "OVERLAY", "GameFontHighlight")
                    sourceText:SetPoint("TOPLEFT", text, "BOTTOMLEFT", 0, -5)
                    sourceText:SetWidth(180)
                    sourceText:SetJustifyH("LEFT")
                    sourceText:SetHeight(10)
                    sourceText:SetWordWrap(false)
                    sourceText:SetTextColor(0, 0.8, 1)  -- Light blue color
                    if sourceText.SetNonSpaceWrap then -- Check if the method exists
                        sourceText:SetNonSpaceWrap(false)
                    end
                    button.sourceText = sourceText
                    
                    -- Slot Text (e.g., "Head" or "Chest") - Position BELOW the source text
                    local slotText = SafeCreateFontString(button, "OVERLAY", "GameFontNormal")
                    slotText:SetPoint("TOPLEFT", sourceText, "BOTTOMLEFT", 0, -2)
                    slotText:SetWidth(180)
                    slotText:SetJustifyH("LEFT")
                    slotText:SetTextColor(0.7, 0.7, 0.7)
                    button.slotText = slotText
                    
                    -- Remove Button (X Button)
                    local removeButton = CreateFrame("Button", nil, button, "UIPanelCloseButton")
                    removeButton:SetSize(20, 20)
                    removeButton:SetPoint("RIGHT", -5, 0)
                    button.removeButton = removeButton
                    
                    itemButtons[index] = button
                end

                -- Get item info and update UI elements
                local itemName, itemLink, itemRarity, _, _, _, _, _, _, itemTexture =
                    GetItemInfoFunc(itemID)

                if itemName then
                    local color = ITEM_QUALITY_COLORS[itemRarity]

                    button.icon:SetTexture(itemTexture)
                    button.text:SetText(itemLink or itemName)

                    -- Display source information
                    -- Display source information
                    if type(itemData) == "table" then
                        local sourceToUse = itemData.fullSource or itemData.source
                        local instanceName, bossName = sourceToUse:match("(.+) %- (.+)")
                        
                        if instanceName and bossName then
                            -- Set the full instance name
                            button.sourceText:SetText(instanceName)
                            
                            -- Create or update boss name text
                            if not button.bossText then
                                button.bossText = SafeCreateFontString(button, "OVERLAY", "GameFontHighlight")
                                button.bossText:SetPoint("TOPLEFT", button.sourceText, "BOTTOMLEFT", 0, -5)
                                button.bossText:SetWidth(180)
                                button.bossText:SetJustifyH("LEFT")
                                button.bossText:SetHeight(10)
                                button.bossText:SetWordWrap(false)
                                button.bossText:SetTextColor(1, 0.82, 0)  -- Gold color for boss name
                            end
                            button.bossText:SetText(bossName)
                            
                            -- Adjust slot text position to be below boss text
                            button.slotText:SetPoint("TOPLEFT", button.bossText, "BOTTOMLEFT", 0, -5)
                        else
                            button.sourceText:SetText(sourceToUse)
                            if button.bossText then
                                button.bossText:SetText("")
                            end
                        end
                    else
                        button.sourceText:SetText("Unknown source")
                        if button.bossText then
                            button.bossText:SetText("")
                        end
                    end

                    -- Show slot and item index for slots with multiple items
                    -- Get the actual slot type for this specific item
                    local actualSlotType = GetItemSlotType(itemID)
                    local slotDisplay = FormatSlotText(actualSlotType)

                    -- Show item index for slots with multiple items
                    if #BiSJournalDB.lists[DB_KEY][slot] > 1 then
                        slotDisplay = slotDisplay .. " #" .. itemIndex
                    end
                    button.slotText:SetText(slotDisplay)

                    -- Store slot and index for removal
                    button.slot = slot
                    button.itemIndex = itemIndex

                    -- Remove Button functionality
                    button.removeButton:SetScript("OnClick", function()
                        RemoveFromBiSList(button.slot, button.itemIndex)
                    end)

                    -- Tooltip functionality
                    button:SetScript("OnEnter", function()
                        GameTooltip:SetOwner(button, "ANCHOR_RIGHT")
                        GameTooltip:SetItemByID(itemID)
                        GameTooltip:Show()
                    end)

                    button:SetScript("OnClick", function(self)
                        local itemData = BiSJournalDB.lists[DB_KEY][slot][itemIndex]
                        if type(itemData) == "table" then
                            local sourceToUse = itemData.fullSource or itemData.source
                            local sourceType = itemData.sourceType or "unknown"
                            local expansion = itemData.expansion
                    
                            if sourceType == "vendor" then
                                -- Handle vendor items - keep existing behavior
                                local instanceName, vendorName = sourceToUse:match("(.+) %- (.+)")
                                if instanceName and vendorName then
                                    print("Visit " .. vendorName .. " in " .. instanceName .. " to purchase this item.")
                                else
                                    print("Vendor information incomplete for this item.")
                                end
                            elseif sourceType == "instance" then
                                -- Handle dungeon/raid items - open Adventure Guide
                                local instanceName, bossName = sourceToUse:match("(.+) %- (.+)")
                                if instanceName and bossName then
                                    OpenAdventureGuideToSource(instanceName, bossName, expansion, itemData.isDungeon)
                                else
                                    print("Instance information incomplete for this item.")
                                end
                            else
                                -- Fallback for older items without sourceType
                                local instanceName, bossName = sourceToUse:match("(.+) %- (.+)")
                                if instanceName and bossName then
                                    print("This item was added using an older version of BiSJournal or manually added. It drops from " .. bossName .. " in " .. instanceName .. ".")
                                else
                                    print("Source information incomplete for this item. Add this item again for Adventure Guide functionality.")
                                end
                            end
                        end
                    end)                                                                                                                     

                    button:SetScript("OnLeave", function()
                        GameTooltip:Hide()
                    end)

                    -- Position and show the button
                    button:SetPoint("TOPLEFT", content, "TOPLEFT", 10, -yOffset)
                    button:Show()

                    yOffset = yOffset + 65
                    index = index + 1
                else
                    print("Error: Item info not available for itemID:", itemID)
                end
            end
        end
    end
    
    -- Schedule another refresh if needed
    if needsRefresh then
        C_Timer.After(0.5, RefreshBiSPanel)
    end
    
    -- Update content height dynamically based on number of items displayed
    content:SetHeight(math.max(yOffset, 400))
    
    -- Show message if no items are added yet
    if index == 1 then
        local messageFrame = content.messageFrame or CreateFrame("Frame", nil, content)
        messageFrame:SetSize(250, 40)
        local text = messageFrame.text or SafeCreateFontString(messageFrame, "OVERLAY", "GameFontNormal")
        text:SetPoint("CENTER")
        text:SetText("No BiS items added yet.\nAlt+Click items in the journal to add them.")
        messageFrame.text = text
        messageFrame:SetPoint("TOPLEFT", content, "TOPLEFT", 10, -yOffset)
        messageFrame:Show()
        content.messageFrame = messageFrame -- Save reference to hide later when items are added.
    elseif content.messageFrame then -- Hide the message frame when items exist.
        content.messageFrame:Hide()
    end

    local contentHeight = math.max(yOffset, scrollFrame:GetHeight())
    biSPanel.content:SetHeight(contentHeight)

    local scrollbar = scrollFrame.ScrollBar
    if scrollbar then
        scrollbar:SetMinMaxValues(0, math.max(0, contentHeight - scrollFrame:GetHeight()))
    end
end

local function IsCollectible(itemID)
    local _, _, _, _, _, itemType, itemSubType = GetItemInfoFunc(itemID)
    -- Check for toys, mounts, pets, etc.
    if itemType == "Miscellaneous" and (
       itemSubType == "Companion Pets" or
       itemSubType == "Mount" or
       itemSubType == "Toy") then
        return true
    end
    return false
end

local function HandleJournalClick(button)
    if IsModifiedClick("ALT") and button.itemID then -- Check for Alt key press and valid item ID.
        local source = "Unknown source" 

        if EncounterJournal and EncounterJournal.encounterID then
            local encounterName = EJ_GetEncounterInfo(EncounterJournal.encounterID)
            local instanceName = EJ_GetInstanceInfo()

            if encounterName and instanceName then
                source = instanceName .. " - " .. encounterName
            elseif instanceName then
                source = instanceName
            end
        end
        AddToBiSList(button.itemID, source) -- Add the clicked loot to the BiS list.
    end
end

-- For Merchant items
local function HandleVendorClick(button, merchantItemIndex)
    if IsModifiedClick("ALT") then
        -- Calculate the actual index based on the current page
        local currentPage = MerchantFrame.page
        local actualIndex = ((currentPage - 1) * MERCHANT_ITEMS_PER_PAGE) + merchantItemIndex
        
        local itemLink = GetMerchantItemLink(actualIndex)
        if itemLink then
            local itemID = tonumber(itemLink:match("item:(%d+)"))
            if itemID then
                local vendorName = UnitName("npc")
                local zoneName = GetZoneText()
                local source = zoneName .. " - " .. vendorName
                AddToBiSList(itemID, source)
            end
        end
    end
end

local function MigrateShortNames()
    if not BiSJournalDB or not BiSJournalDB.lists then return end
    
    for key, list in pairs(BiSJournalDB.lists) do
        for slot, items in pairs(list) do
            if type(items) == "table" then
                for i, item in ipairs(items) do
                    if type(item) == "table" and item.fullSource then
                        -- If we have the full source, use it for the shortened source too
                        item.source = item.fullSource
                    end
                end
            end
        end
    end
    
    -- Update version
    BiSJournalDB.config.version = 1.2
end

local function MigrateDatabase()
    if not BiSJournalDB or not BiSJournalDB.lists then return end
    
    for key, list in pairs(BiSJournalDB.lists) do
        for slot, items in pairs(list) do
            if type(items) == "table" then
                for i, item in ipairs(items) do
                    if type(item) ~= "table" then
                        -- Convert to new format
                        items[i] = {
                            id = item,
                            source = "Unknown source"
                        }
                    end
                end
            end
        end
    end
    
    -- Add migration for shortened names
    MigrateShortNames()
    
    -- Update version
    BiSJournalDB.config.version = 1.2
end

local function HookJournalButtons()
    if not EncounterJournal or not EncounterJournal.encounter then
        C_Timer.After(1, HookJournalButtons) -- Retry until Encounter Journal is loaded.
        return
    end
    
    -- Access the correct path to the loot container
    local lootContainer = EncounterJournal.encounter.info.LootContainer
    if not lootContainer then
        print("BiSJournal: LootContainer not found")
        C_Timer.After(1, HookJournalButtons)
        return
    end
    
    local scrollBox = lootContainer.ScrollBox
    if not scrollBox then
        print("BiSJournal: ScrollBox not found")
        C_Timer.After(1, HookJournalButtons)
        return
    end
    
    -- Try to hook both the ScrollBox frames and any child frames
    if scrollBox.ScrollTarget then
        -- Hook the scroll target's children (the actual item buttons)
        for i, child in ipairs({scrollBox.ScrollTarget:GetChildren()}) do
            if child and not child.HookedBiS then
                
                -- Use OnMouseDown instead of PreClick
                child:HookScript("OnMouseDown", function(self, button)
                    if IsModifiedClick("ALT") and self.itemID then
                        -- Store the itemID before UI changes
                        local itemID = self.itemID
                        
                        -- Get source information immediately
                        local source = "Unknown source"
                        local instanceName = EJ_GetInstanceInfo()
                        local bossName = nil
                        
                        if self.encounterID then
                            bossName = EJ_GetEncounterInfo(self.encounterID)
                        elseif self.link and self.link:match("encounterID:(%d+)") then
                            local encounterID = self.link:match("encounterID:(%d+)")
                            bossName = EJ_GetEncounterInfo(tonumber(encounterID))
                        end
                        
                        if instanceName then
                            if bossName then
                                source = instanceName .. " - " .. bossName
                            else
                                source = instanceName .. " - Unknown Boss"
                            end
                        end
                        
                        -- Use a slight delay to ensure the click completes first
                        C_Timer.After(0.1, function()
                            AddToBiSList(itemID, source)
                        end)
                    end
                end)
                
                child.HookedBiS = true
            end
        end
    else
        print("BiSJournal: ScrollTarget not found")
    end
    
    -- Also try the old method as a fallback
    scrollBox:ForEachFrame(function(button)
        if button and not button.HookedBiS then
            
            -- Use OnMouseDown instead of PreClick
            button:HookScript("OnMouseDown", function(self, button)
                if IsModifiedClick("ALT") and self.itemID then
                    -- Same code as above
                    local itemID = self.itemID
                    local source = "Unknown source"
                    local instanceName = EJ_GetInstanceInfo()
                    local bossName = nil
                    
                    if self.encounterID then
                        bossName = EJ_GetEncounterInfo(self.encounterID)
                    elseif self.link and self.link:match("encounterID:(%d+)") then
                        local encounterID = self.link:match("encounterID:(%d+)")
                        bossName = EJ_GetEncounterInfo(tonumber(encounterID))
                    end
                    
                    if instanceName then
                        if bossName then
                            source = instanceName .. " - " .. bossName
                        else
                            source = instanceName .. " - Unknown Boss"
                        end
                    end
                    
                    C_Timer.After(0.1, function()
                        AddToBiSList(itemID, source)
                    end)
                end
            end)
            
            button.HookedBiS = true
        end
    end)
    
    -- Schedule another check to catch any new buttons
    C_Timer.After(5, HookJournalButtons)
end

local function HookMerchantButtons()
    -- Check if merchant frame exists
    if not MerchantFrame then
        C_Timer.After(1, HookMerchantButtons) -- Retry until loaded
        return
    end
    
    -- Hook the merchant update function to handle page changes
    if not MerchantFrame.HookedBiSUpdate then
        hooksecurefunc("MerchantFrame_UpdateMerchantInfo", function()
            -- This runs whenever the merchant page changes
            for i = 1, MERCHANT_ITEMS_PER_PAGE do
                local button = _G["MerchantItem"..i.."ItemButton"]
                if button and not button.HookedBiS then
                    button:HookScript("OnClick", function(self, mouseButton)
                        if mouseButton == "LeftButton" then
                            local merchantItemIndex = i -- Use the loop index directly
                            HandleVendorClick(self, merchantItemIndex)
                        end
                    end)
                    button.HookedBiS = true
                end
            end
        end)
        MerchantFrame.HookedBiSUpdate = true
    end
    
    -- Initial hook for the first page
    for i = 1, MERCHANT_ITEMS_PER_PAGE do
        local button = _G["MerchantItem"..i.."ItemButton"]
        if button and not button.HookedBiS then
            button:HookScript("OnClick", function(self, mouseButton)
                if mouseButton == "LeftButton" then
                    local merchantItemIndex = i -- Use the loop index directly
                    HandleVendorClick(self, merchantItemIndex)
                end
            end)
            button.HookedBiS = true
        end
    end
end

-- Set the default position
local function SetDefaultPosition()
    if biSPanel and EncounterJournal and EncounterJournal:IsShown() then
        biSPanel:ClearAllPoints()
        biSPanel:SetPoint("TOPLEFT", EncounterJournal, "TOPRIGHT", 20, 0)
    else
        -- Default position when Adventure Guide isn't open
        biSPanel:ClearAllPoints()
        biSPanel:SetPoint("CENTER", UIParent, "CENTER", 0, 0)
    end
end

-- Initialize state
local isLocked = false

-- Create the main panel
local function CreateBiSPanel()
    -- Main panel - no longer parented to EncounterJournal
    biSPanel = CreateFrame("Frame", "BiSJournalPanel", UIParent, "BackdropTemplate,ResizeLayoutFrame")
    biSPanel:SetSize(BiSJournalDB.config.width or 300, BiSJournalDB.config.height or 500)
    biSPanel:SetPoint("CENTER", UIParent, "CENTER", 0, 0) -- Center it on screen initially
    biSPanel:SetBackdrop({
        bgFile = "Interface\\Buttons\\WHITE8x8",
        edgeFile = "Interface\\DialogFrame\\UI-DialogBox-Border",
        tile = true,
        tileSize = 32,
        edgeSize = 32,
        insets = { left = 8, right = 8, top = 8, bottom = 2 }
    })
    
    -- Apply initial color
    local colorOption = BiSJournalDB.config.colorOption or 1
    if BiSJournal.colorOptions and BiSJournal.colorOptions[colorOption] then
        local colorValue = BiSJournal.colorOptions[colorOption].value
        
        biSPanel:SetBackdropColor(0, 0, 0, BiSJournalDB.config.opacity or 1.0)
    end

    biSPanel:SetMovable(true)
    biSPanel:EnableMouse(true)
    biSPanel:RegisterForDrag("LeftButton")
    biSPanel:SetScript("OnDragStart", biSPanel.StartMoving)
    biSPanel:SetScript("OnDragStop", function(self)
        self:StopMovingOrSizing()
        local point, _, relativePoint, xOfs, yOfs = self:GetPoint()
        BiSJournalDB.config.panelPosition = {
            point = point,
            relativePoint = relativePoint,
            xOfs = xOfs,
            yOfs = yOfs
        }
    end)

    local resizeButton = CreateFrame("Button", nil, biSPanel)
    resizeButton:SetSize(16, 16)
    resizeButton:SetPoint("BOTTOMRIGHT", -2, 2)
    resizeButton:SetNormalTexture("Interface\\ChatFrame\\UI-ChatIM-SizeGrabber-Up")
    resizeButton:SetHighlightTexture("Interface\\ChatFrame\\UI-ChatIM-SizeGrabber-Highlight")
    resizeButton:SetPushedTexture("Interface\\ChatFrame\\UI-ChatIM-SizeGrabber-Down")

    biSPanel:SetResizable(true)
    biSPanel:SetResizeBounds(300, 200, 300, 900)

    if isLocked then
        resizeButton:Hide()
    else
        resizeButton:Show()
    end

    -- Add this after your resize button creation
    resizeButton:SetScript("OnMouseDown", function(self, button)
        if button == "LeftButton" then
            biSPanel:StartSizing("BOTTOMRIGHT")
            self.isSizing = true
            self:SetScript("OnUpdate", function()
                -- Update content during resize
                local scrollFrame = biSPanel.content:GetParent()
                local panelWidth = biSPanel:GetWidth()
                local panelHeight = biSPanel:GetHeight()
                
                -- Adjust scrollFrame size
                scrollFrame:SetSize(panelWidth - 30, panelHeight - 100)
                
                -- Adjust content width
                biSPanel.content:SetWidth(panelWidth - 50)
            end)
        end
    end)

    resizeButton:SetScript("OnMouseUp", function(self, button)
        biSPanel:StopMovingOrSizing()
        self.isSizing = false
        self:SetScript("OnUpdate", nil)
        
        -- Save the new size
        BiSJournalDB.config.width = biSPanel:GetWidth()
        BiSJournalDB.config.height = biSPanel:GetHeight()
        
        -- Refresh the panel content
        RefreshBiSPanel()
    end)
   
    -- Title
    local title = biSPanel:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
    title:SetText("BiS Journal")
    title:SetPoint("TOP", 0, -15)

    -- Instructions
    local instructions = biSPanel:CreateFontString(nil, "OVERLAY", "GameFontNormal")
    instructions:SetText("Alt+Click items in the Adventure Guide/Vendor/Chat to add them")
    instructions:SetPoint("TOP", title, "BOTTOM", 0, -10)
    biSPanel.instructions = instructions  -- Add this line here

    -- Scrollframe for items
    local scrollFrame = CreateFrame("ScrollFrame", nil, biSPanel, "UIPanelScrollFrameTemplate")
    scrollFrame:SetSize(270, 400)
    scrollFrame:SetPoint("TOP", instructions, "BOTTOM", 0, -10)
    biSPanel.scrollFrame = scrollFrame  -- Add this line here

    local content = CreateFrame("Frame", nil, scrollFrame)
    content:SetSize(270, 1) -- Height will be adjusted dynamically
    scrollFrame:SetScrollChild(content)
    biSPanel.content = content

    -- Close button
    local closeButton = CreateFrame("Button", nil, biSPanel, "UIPanelCloseButton")
    closeButton:SetPoint("TOPRIGHT", -5, -5)

    closeButton:SetScript("OnClick", function()
        openedByMinimap = false
        openedBySlashCommmand = false
        biSPanel:Hide()
    end)    

    -- Lock button (add this code)
    local lockButton = CreateFrame("Button", "BiSJournalLockButton", biSPanel)
    lockButton:SetSize(24, 24)
    lockButton:SetPoint("TOPRIGHT", closeButton, "TOPLEFT", -5, 0)

    lockButton.lockedTexture = lockButton:CreateTexture(nil, "ARTWORK")
    lockButton.lockedTexture:SetAllPoints()
    lockButton.lockedTexture:SetTexture("Interface\\Buttons\\LockButton-Locked-Up")
    lockButton.lockedTexture:Hide() -- Initially unlocked

    lockButton.unlockedTexture = lockButton:CreateTexture(nil, "ARTWORK")
    lockButton.unlockedTexture:SetAllPoints()
    lockButton.unlockedTexture:SetTexture("Interface\\Buttons\\LockButton-Unlocked-Up")
    lockButton.unlockedTexture:Show() -- Initially unlocked

    -- Inside CreateBiSPanel() function
    isLocked = BiSJournalDB.config.isLocked

    if isLocked then
        lockButton.lockedTexture:Show()
        lockButton.unlockedTexture:Hide()
    else
        lockButton.lockedTexture:Hide()
        lockButton.unlockedTexture:Show()
    end

    lockButton:SetScript("OnClick", function()
        isLocked = not isLocked
        BiSJournalDB.config.isLocked = isLocked
        if isLocked then
            lockButton.lockedTexture:Show()
            lockButton.unlockedTexture:Hide()
            resizeButton:Hide()
        else
            lockButton.lockedTexture:Hide()
            lockButton.unlockedTexture:Show()
            resizeButton:Show()
        end
        -- Play sound for feedback
        PlaySound(isLocked and SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_ON or SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_OFF)
    end) 

    lockButton:SetScript("OnEnter", function(self)
        GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
        if isLocked then
            GameTooltip:SetText("Unlock BiS Journal (Currently Locked)")
            GameTooltip:AddLine("Journal will stay in place and won't snap to other windows", 1, 1, 1)
            GameTooltip:AddLine("Resizing is disabled while locked", 1, 0.5, 0.5)
        else
            GameTooltip:SetText("Lock BiS Journal (Currently Unlocked)")
            GameTooltip:AddLine("Journal will snap to Adventure Guide and vendor windows", 1, 1, 1)
            GameTooltip:AddLine("Resizing is enabled while unlocked", 0.5, 1, 0.5)
        end
        GameTooltip:Show()
    end)

    lockButton:SetScript("OnLeave", function()
        GameTooltip:Hide()
    end)

    biSPanel.CheckVisibility = function(self)
        if EncounterJournal and EncounterJournal:IsShown() then
            self:Show()
            SetDefaultPosition()
        end
    end
    
    -- Add to OnShow script
    biSPanel:SetScript("OnShow", function()
        local opacity = BiSJournalDB.config.opacity or 1.0
        local colorOption = BiSJournalDB.config.colorOption or 1
        local colorValue = BiSJournal.colorOptions[colorOption].value
        BiSJournal:UpdatePanelColor(colorValue)
        C_Timer.After(0.2, RefreshBiSPanel)
        -- Save the state if manually shown
        BiSJournalDB.config.manuallyShown = true
    end)
    
    -- Add to OnHide script
    biSPanel:SetScript("OnHide", function()
        -- Save the state if manually hidden
        BiSJournalDB.config.manuallyShown = false
    end)
    
    -- Hide initially
    biSPanel:Hide()
    RefreshBiSPanel()
end

local function UpdateLockButtonState()
    if lockButton then
        if isLocked then
            lockButton.lockedTexture:Show()
            lockButton.unlockedTexture:Hide()
            if resizeButton then
                resizeButton:Hide()
            end
        else
            lockButton.lockedTexture:Hide()
            lockButton.unlockedTexture:Show()
            if resizeButton then
                resizeButton:Show()
            end
        end
    end
end   

local function AddBiSTooltipInfo(tooltip, itemID)
    if not itemID or not DB_KEY or not biSPanel then return end

    for slot, items in pairs(BiSJournalDB.lists[DB_KEY]) do
        for _, itemData in ipairs(items) do
            local storedItemID = type(itemData) == "table" and itemData.id or itemData
            if storedItemID == itemID then
                local colorIndex = BiSJournalDB.config.tooltipColorOption or 1
                local colorOption = BiSJournal.tooltipColorOptions and BiSJournal.tooltipColorOptions[colorIndex]
                local colorHex

                if colorOption and colorOption.value == "class" then
                    -- Dynamically get the player's class color
                    local _, class = UnitClass("player")
                    local classColor = RAID_CLASS_COLORS[class]
                    if classColor then
                        colorHex = string.format("FF%02X%02X%02X", classColor.r * 255, classColor.g * 255, classColor.b * 255)
                    else
                        colorHex = "FFFFFFFF" -- fallback to white
                    end
                else
                    colorHex = colorOption and colorOption.hex or "FF00FF00"
                end

                tooltip:AddLine("|c" .. colorHex .. "This is in your BiS Journal!|r")
                return
            end
        end
    end
end

local function HookTooltips()
    -- Modern tooltip handling using TooltipDataProcessor
    local function OnTooltipSetItem(tooltip, data)
        if data.id then  -- Check if we have valid item data
            AddBiSTooltipInfo(tooltip, data.id)
        end
    end

    TooltipDataProcessor.AddTooltipPostCall(Enum.TooltipDataType.Item, OnTooltipSetItem)
end

local function HookChatItemLinks()
    -- Store the original SetItemRef function
    local originalSetItemRef = SetItemRef
    
    -- Replace with our custom function
    SetItemRef = function(link, text, button, chatFrame)
        -- Call the original function first to maintain normal functionality
        originalSetItemRef(link, text, button, chatFrame)
        
        -- Check if it's an item link and Alt is being held down
        local linkType, itemID = link:match("^(%a+):(%d+)")
        
        if linkType == "item" and IsAltKeyDown() then
            -- Convert to number
            itemID = tonumber(itemID)
            
            -- Request item data to ensure it's loaded
            C_Item.RequestLoadItemDataByID(itemID)
            
            -- Use a slight delay to allow item data to load
            C_Timer.After(0.2, function()
                local itemName, itemLink = C_Item.GetItemInfo(itemID)
                if itemName then
                    -- Show the popup dialog with the item name
                    StaticPopup_Show("BISJOURNAL_CHAT_SOURCE", itemName, nil, {itemID = itemID, name = itemName})
                else
                    print("|cFFFF0000BiS Journal:|r Unable to retrieve item information. Try again.")
                end
            end)
        end
    end
end

local function HookAdventureGuide()
    -- Hook into the Adventure Guide's OnShow event
    if EncounterJournal then
        -- Optionally hide when Adventure Guide is closed
        EncounterJournal:HookScript("OnHide", function()
            if biSPanel and biSPanel:IsShown() and not openedByMinimap and not openedBySlashCommmand and BiSJournalDB.config.autoHide then
                biSPanel:Hide()
            end
        end)
        EncounterJournal:HookScript("OnShow", function()
            if biSPanel then
                biSPanel:Show()
                if not isLocked then
                    biSPanel:ClearAllPoints()
                    biSPanel:SetPoint("TOPLEFT", EncounterJournal, "TOPRIGHT", 20, 0)
                end
                RefreshBiSPanel()
            end
        end)
    else
        -- If EncounterJournal isn't loaded yet, try again later
        C_Timer.After(1, HookAdventureGuide)
    end
end

-- In BiSJournal.lua (REPLACE the old function with this EXACT code)
function BiSJournal:UpdatePanelOpacity(value)
    if biSPanel then
        -- Retrieve the currently saved background color
        -- Use default black (0,0,0) if the saved color isn't fully defined yet
        local r = (BiSJournalDB.config.backgroundColor and BiSJournalDB.config.backgroundColor.r) or 0
        local g = (BiSJournalDB.config.backgroundColor and BiSJournalDB.config.backgroundColor.g) or 0
        local b = (BiSJournalDB.config.backgroundColor and BiSJournalDB.config.backgroundColor.b) or 0
        
        -- Apply the SAVED color (r,g,b) with the NEW opacity (value)
        biSPanel:SetBackdropColor(r, g, b, value) 
        
        -- Also update the stored opacity value in the database
        BiSJournalDB.config.opacity = value 
    end
end

-- Add this function to BiSJournal.lua
function BiSJournal:UpdatePanelScale(value)
    if biSPanel then
        biSPanel:SetScale(value)
        -- Save the scale value to the database
        BiSJournalDB.config.scale = value
    end
end

function GetCurrentExpansionFromUI()
    -- Check which expansion is selected in the dropdown
    local dropdown = EncounterJournal.tierDropDown
    if dropdown then
        return dropdown.selectedID
    end
    return nil
end

function OpenAdventureGuideToSource(instanceName, bossName, expansion)
    if not EncounterJournal_OpenJournal then return end
    
    -- First open the journal
    EncounterJournal_OpenJournal()
    
    -- Set the expansion tier if provided
    if expansion then
        C_Timer.After(0.1, function()
            -- Select the proper expansion in the dropdown
            EJ_SelectTier(expansion)
            
            -- Continue with the search after selecting expansion
            C_Timer.After(0.1, function()
                -- Try both Dungeons and Raids tabs
                if not SearchInTab(true, instanceName, bossName) then
                    -- If not found, try Raids tab
                    C_Timer.After(0.3, function()
                        if not SearchInTab(false, instanceName, bossName) then
                            -- If still not found, try a more flexible search
                            C_Timer.After(0.3, function()
                                if not FlexibleSearchInTabs(instanceName, bossName) then
                                    print("Could not find " .. bossName .. " in " .. instanceName)
                                end
                            end)
                        end
                    end)
                end
            end)
        end)
    else
        -- Original search logic without setting expansion
        C_Timer.After(0.1, function()
            -- Try both Dungeons and Raids tabs
            if not SearchInTab(true, instanceName, bossName) then
                -- If not found, try Raids tab
                C_Timer.After(0.3, function()
                    if not SearchInTab(false, instanceName, bossName) then
                        -- If still not found, try a more flexible search
                        C_Timer.After(0.3, function()
                            if not FlexibleSearchInTabs(instanceName, bossName) then
                                print("Could not find " .. bossName .. " in " .. instanceName)
                            end
                        end)
                    end
                end)
            end
        end)
    end
end

function BiSJournal:UpdatePanelColor(colorValue)
    if not biSPanel then
        print("Error: biSPanel not found")
        return
    end
    
    local r, g, b = 0, 0, 0 -- Default black
    local opacity = BiSJournalDB.config.opacity or 1.0
    
    if colorValue == "black" then
        r, g, b = 0, 0, 0
    elseif colorValue == "class" then
        -- Get class color
        local _, className = UnitClass("player")
        local classColor = RAID_CLASS_COLORS[className]
        r, g, b = classColor.r, classColor.g, classColor.b
    elseif colorValue == "red" then
        r, g, b = 0.8, 0, 0
    elseif colorValue == "green" then
        r, g, b = 0, 0.8, 0
    elseif colorValue == "blue" then
        r, g, b = 0, 0, 0.8
    elseif colorValue == "purple" then
        r, g, b = 0.7, 0, 0.7
    elseif colorValue == "gold" then
        r, g, b = 1, 0.8, 0
    end
    
    -- Store the color values
    BiSJournalDB.config.backgroundColor = {r = r, g = g, b = b}

    -- Apply the color with current opacity
    biSPanel:SetBackdropColor(r, g, b, opacity)
end

-- Export the current BiS list for this character/spec as a custom string
local function ExportCurrentBiSList()
    local t = {}
    for slot, items in pairs(BiSJournalDB.lists[DB_KEY]) do
        for _, item in ipairs(items) do
            table.insert(t, table.concat({
                slot,
                item.id,
                item.source,
                item.instanceID or "",
                item.encounterID or "",
                item.difficultyID or "",
                item.instanceName or "",
                item.bossName or "",
                item.expansion or "",
                item.isDungeon == true and "1" or "0",
                item.sourceType or "instance"
            }, ":"))
        end
    end
    return table.concat(t, ";")
end

local function ImportBiSList(importString)
    if not DB_KEY then return end
    
    local newList = {}
    
    for entry in string.gmatch(importString, "([^;]+)") do
        -- Split into components (allow empty fields)
        local slot, itemID, source, instanceID, encounterID, difficultyID, instanceName, bossName, expansion, isDungeonStr, sourceType =
            entry:match("([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*)")
        
        if slot ~= "" and itemID ~= "" then
            -- Unescape colons in source
            source = (source or ""):gsub("%%3A", ":")
            
            -- Convert numeric fields
            local itemTable = {
                id = tonumber(itemID),
                source = source,
                fullSource = source,
                sourceType = sourceType ~= "" and sourceType or "instance"  -- Default to instance type
            }
            
            -- Add expansion information
            if expansion ~= "" then 
                itemTable.expansion = tonumber(expansion) 
            end
            
            -- Add isDungeon flag
            if isDungeonStr ~= "" then
                itemTable.isDungeon = (isDungeonStr == "1")
            end
            
            -- Add other optional fields if they exist
            if encounterID ~= "" then itemTable.encounterID = tonumber(encounterID) end
            if instanceID ~= "" then itemTable.instanceID = tonumber(instanceID) end
            if difficultyID ~= "" then itemTable.difficultyID = tonumber(difficultyID) end
            if instanceName ~= "" then itemTable.instanceName = instanceName end
            if bossName ~= "" then itemTable.bossName = bossName end
            
            newList[slot] = newList[slot] or {}
            table.insert(newList[slot], itemTable)
        end
    end
    
    BiSJournalDB.lists[DB_KEY] = newList
    RefreshBiSPanel()
end

BiSJournal.ExportCurrentBiSList = ExportCurrentBiSList
BiSJournal.ImportBiSList = ImportBiSList

function SearchInTab(isDungeon, instanceName, bossName)
    local tabIndex = isDungeon and 3 or 4
    PanelTemplates_SetTab(EncounterJournal, tabIndex)
    EJ_ContentTab_Select(tabIndex - 1)
    
    -- Search through all instances
    for i = 1, 100 do
        local id, name = EJ_GetInstanceByIndex(i, not isDungeon)
        if not id then break end
        
        if name == instanceName then
            NavBar_Reset(EncounterJournal.navBar)
            EncounterJournal_DisplayInstance(id)
            
            -- Find the boss
            C_Timer.After(0.2, function()
                for j = 1, 20 do
                    local name, _, encounterID = EJ_GetEncounterInfoByIndex(j)
                    if not name then break end
                    
                    if name == bossName then
                        EncounterJournal_DisplayEncounter(encounterID)
                        
                        -- Switch to the Loot tab
                        C_Timer.After(0.1, function()
                            if EncounterJournal.encounter and EncounterJournal.encounter.info then
                                EncounterJournal.encounter.info.lootTab:Click()
                            end
                        end)
                        return true
                    end
                end
            end)
            return true
        end
    end
    return false
end

function FlexibleSearchInTabs(instanceName, bossName)
    -- Try both tabs with more flexible matching
    for i = 1, 2 do -- Changed to numeric loop
        local isDungeon = (i == 1) -- true first iteration, false second
        local tabIndex = isDungeon and 3 or 4
        PanelTemplates_SetTab(EncounterJournal, tabIndex)
        EJ_ContentTab_Select(tabIndex - 1)

        -- Rest of existing code remains unchanged...
        for i = 1, 100 do
            local id, name = EJ_GetInstanceByIndex(i, not isDungeon)
            if not id then break end
            -- ... existing logic ...
        end
    end
    return false
end

-- Event handling
local eventFrame = CreateFrame("Frame")
eventFrame:RegisterEvent("ADDON_LOADED")
eventFrame:RegisterEvent("PLAYER_LOGIN")
eventFrame:RegisterEvent("PLAYER_SPECIALIZATION_CHANGED")
eventFrame:RegisterEvent("MERCHANT_SHOW")
eventFrame:RegisterEvent("MERCHANT_CLOSED")


eventFrame:SetScript("OnEvent", function(self, event, ...)
    if event == "ADDON_LOADED" and ... == "OrzUI" then
        BiSJournalDB = BiSJournalDB or {
            lists = {},
            config = {
                version = 1.0,
                minimapPos = nil,
                width = 300,
                height = 500,
            },
        }

        BiSJournalDB.config = BiSJournalDB.config or {}
        BiSJournalDB.config.manuallyOpened = BiSJournalDB.config.manuallyOpened or false
        BiSJournalDB.config.opacity = BiSJournalDB.config.opacity or 1.0
        BiSJournalDB.config.colorOption = BiSJournalDB.config.colorOption or 1
        BiSJournalDB.config.backgroundColor = BiSJournalDB.config.backgroundColor or {r = 0, g = 0, b = 0}
        BiSJournalDB.config.scale = BiSJournalDB.config.scale or 1.0

        openedByMinimap = BiSJournalDB.config.manuallyOpened
        openedBySlashCommmand = false

        if BiSJournalDB.config.isLocked ~= nil then
            isLocked = BiSJournalDB.config.isLocked
        end

        if BiSJournalDB.config.version <1.1 then
            MigrateDatabase()
        end

        HookAdventureGuide()
        BiSJournalDB.config.autoHide = BiSJournalDB.config.autoHide or true
        BiSJournal:InitializeOptions()

    elseif event == "PLAYER_LOGIN" then
        InitializeDB()
        CreateBiSPanel()
        HookJournalButtons()
        HookMerchantButtons()
        HookChatItemLinks()
        UpdateLockButtonState()

        if BiSJournalDB.config.colorOption then
            local selectedIndex = BiSJournalDB.config.colorOption
            local selectedColorValue = BiSJournal.colorOptions[selectedIndex].value
            BiSJournal:UpdatePanelColor(selectedColorValue)
        end
        

        if BiSJournalDB.config.panelPosition then
            biSPanel:ClearAllPoints()
            biSPanel:SetPoint(
                BiSJournalDB.config.panelPosition.point,
                UIParent,
                BiSJournalDB.config.panelPosition.relativePoint,
                BiSJournalDB.config.panelPosition.xOfs,
                BiSJournalDB.config.panelPosition.yOfs
            )
        end

        if BiSJournalDB.config.scale then
            biSPanel:SetScale(BiSJournalDB.config.scale)
        end

        HookTooltips()

        C_Timer.After(1, function()
            RefreshBiSPanel()
            -- Check if Adventure Guide is already open
            if EncounterJournal and EncounterJournal:IsShown() and biSPanel then
                biSPanel:Show()
                biSPanel:ClearAllPoints()
                biSPanel:SetPoint("TOPLEFT", EncounterJournal, "TOPRIGHT", 20, 0)
            end
        end)
    
    elseif event == "MERCHANT_SHOW" then
        HookMerchantButtons()
        C_Timer.After(0.1, function()
            if biSPanel then
                biSPanel:Show()
                if not isLocked then
                    biSPanel:ClearAllPoints()
                    biSPanel:SetPoint("TOPLEFT", MerchantFrame, "TOPRIGHT", 20.0)
                end
            end
            RefreshBiSPanel()
        end)

    elseif event == "MERCHANT_CLOSED" then
        if biSPanel and biSPanel:IsShown() and not openedByMinimap and not openedBySlashCommmand and BiSJournalDB.config.autoHide then
            biSPanel:Hide()
        end

    elseif event == "PLAYER_SPECIALIZATION_CHANGED" then
        InitializeDB()
        RefreshBiSPanel()
        UpdateLockButtonState()
    end
end)

-- Slash command
SLASH_BISJOURNAL1, SLASH_BISJOURNAL2 = "/bj", "/bisjournal"
SlashCmdList["BISJOURNAL"] = function(msg)
    if msg == "config" or msg == "options" then
        Settings.OpenToCategory("BiS Journal")
    else
        biSPanel:Show()
        openedBySlashCommmand = true
        openedByMinimap = false
        RefreshBiSPanel()
    end
end

-- Add these FIRST before anything else
StaticPopupDialogs["BISJOURNAL_EXPORT"] = {
    text = "Copy the string below (Ctrl+C):",
    button1 = OKAY,
    hasEditBox = true,
    editBoxWidth = 350,
    timeout = 0,
    whileDead = true,
    hideOnEscape = true,
    preferredIndex = 3,
    OnShow = function(self, data)
        self.editBox:SetText(data or "")
        self.editBox:HighlightText()
        self.editBox:SetFocus()
    end,
}

StaticPopupDialogs["BISJOURNAL_IMPORT"] = {
    text = "Paste your import string below:",
    button1 = "Import",
    button2 = CANCEL,
    hasEditBox = true,
    editBoxWidth = 350,
    timeout = 0,
    whileDead = true,
    hideOnEscape = true,
    preferredIndex = 3,
    OnShow = function(self)
        self.editBox:SetText("")
        self.editBox:SetFocus()
    end,
    OnAccept = function(self)
        BiSJournal.ImportBiSList(self.editBox:GetText())
    end,
}

BiSJournal.colorOptions = {
    { text = "Black", value = "black" },
    { text = "Class Color", value = "class" },
    -- Add more color options
    { text = "Red", value = "red" },
    { text = "Green", value = "green" },
    { text = "Blue", value = "blue" },
    { text = "Purple", value = "purple" },
    { text = "Gold", value = "gold" }
}

BiSJournal.tooltipColorOptions = {
    { text = "Green", value = "green", hex = "FF00FF00" },
    { text = "Class Color", value = "class" },
    { text = "Gold", value = "gold", hex = "FFFFD700" },
    { text = "Red", value = "red", hex = "FFFF3030" },
    { text = "Blue", value = "blue", hex = "FF3399FF" },
    { text = "Purple", value = "purple", hex = "FFAA00FF" },
    { text = "White", value = "white", hex = "FFFFFFFF" },
}

local function CreateOptionsPanel()
    local panel = CreateFrame("Frame")
    panel.name = "BiS Journal"

    local scrollFrame = CreateFrame("ScrollFrame", "BiSJournalOptionsScrollFrame", panel, "UIPanelScrollFrameTemplate")
    scrollFrame:SetPoint("TOPLEFT", 3, -4)
    scrollFrame:SetPoint("BOTTOMRIGHT", -27, 16)

    -- Create the scroll child frame that will contain all your options
    local scrollChild = CreateFrame("Frame", "BiSJournalOptionsScrollChild")
    scrollChild:SetWidth(scrollFrame:GetWidth() - 20)
    scrollChild:SetHeight(800)-- Set this to a height that accommodates all your options

    scrollFrame:SetScrollChild(scrollChild)
    
    local title = scrollChild:CreateFontString(nil, "ARTWORK", "GameFontNormalLarge")
    title:SetPoint("TOPLEFT", 26, -16)
    title:SetText("BiS Journal Options")
    
    local autoHideCheckbox = CreateFrame("CheckButton", nil, scrollChild, "InterfaceOptionsCheckButtonTemplate")
    autoHideCheckbox:SetPoint("TOPLEFT", title, "BOTTOMLEFT", 10, -16)
    autoHideCheckbox.Text:SetText("Auto-hide when Adventure Guide or Vendor is closed")
    autoHideCheckbox:SetChecked(BiSJournalDB.config.autoHide)
    autoHideCheckbox:SetScript("OnClick", function(self)
        BiSJournalDB.config.autoHide = self:GetChecked()
    end)
    
    local category = Settings.RegisterCanvasLayoutCategory(panel, "BiS Journal")
    Settings.RegisterAddOnCategory(category)

    local opacitySlider = CreateFrame("Slider", "BiSJournalOpacitySlider", scrollChild, "OptionsSliderTemplate")
    opacitySlider:SetPoint("TOPLEFT", autoHideCheckbox, "BOTTOMLEFT", 10, -30)
    opacitySlider:SetMinMaxValues(0, 100)
    opacitySlider:SetValueStep(10)
    opacitySlider:SetValue((BiSJournalDB.config.opacity or 1.0) * 100)
    opacitySlider.High:SetText("100%")
    opacitySlider.Low:SetText("0%")
    opacitySlider.Text:SetText("Background Opacity")
    
    opacitySlider:SetScript("OnValueChanged", function(self, value)
        local opacity = value / 100
        BiSJournalDB.config.opacity = opacity
        BiSJournal:UpdatePanelOpacity(opacity)
    end)

    -- Add this after your opacity slider in BiSJournalOptions.lua
    local scaleSlider = CreateFrame("Slider", "BiSJournalScaleSlider", scrollChild, "OptionsSliderTemplate")
    scaleSlider:SetPoint("TOPLEFT", opacitySlider, "TOPRIGHT", 50, 0)
    scaleSlider:SetMinMaxValues(50, 200)
    scaleSlider:SetValueStep(10)
    scaleSlider:SetValue((BiSJournalDB.config.scale or 1.0) * 100)
    scaleSlider:SetWidth(150)
    scaleSlider.High:SetText("200%")
    scaleSlider.Low:SetText("50%")
    scaleSlider.Text:SetText("Panel Scale")

    scaleSlider:SetScript("OnValueChanged", function(self, value)
        local scale = value / 100
        BiSJournalDB.config.scale = scale
        BiSJournal:UpdatePanelScale(scale)
    end)

        -- Add after your opacity slider
    local colorDropdown = CreateFrame("Frame", "BiSJournalColorDropdown", scrollChild, "UIDropDownMenuTemplate")
    colorDropdown:SetPoint("TOPLEFT", opacitySlider, "BOTTOMLEFT", -5, -40)
    colorDropdown.colorOptions = BiSJournal.colorOptions
    local colorDropdownText = scrollChild:CreateFontString(nil, "ARTWORK", "GameFontNormal")
    colorDropdownText:SetPoint("BOTTOMLEFT", colorDropdown, "TOPLEFT", 20, 5)
    colorDropdownText:SetText("Background Color:")

    UIDropDownMenu_SetWidth(colorDropdown, 120)
    UIDropDownMenu_SetText(colorDropdown, BiSJournal.colorOptions[BiSJournalDB.config.colorOption or 1].text)

    UIDropDownMenu_Initialize(colorDropdown, function(self, level)
        for i, option in ipairs(colorDropdown.colorOptions) do
            local info = UIDropDownMenu_CreateInfo()
            info.text = option.text
            info.value = option.value
            info.func = function()
                BiSJournalDB.config.colorOption = i
                UIDropDownMenu_SetText(colorDropdown, option.text)

                local selectedColorValue = BiSJournal.colorOptions[i].value
                BiSJournal:UpdatePanelColor(selectedColorValue)
            end
            UIDropDownMenu_AddButton(info, level)
        end
    end)

    -- Tooltip Color Dropdown
    local tooltipColorDropdown = CreateFrame("Frame", "BiSJournalTooltipColorDropdown", scrollChild, "UIDropDownMenuTemplate")
    tooltipColorDropdown:SetPoint("TOPLEFT", colorDropdown, "TOPRIGHT", 50, 0)
    tooltipColorDropdown.colorOptions = BiSJournal.tooltipColorOptions

    local tooltipColorDropdownText = scrollChild:CreateFontString(nil, "ARTWORK", "GameFontNormal")
    tooltipColorDropdownText:SetPoint("BOTTOMLEFT", tooltipColorDropdown, "TOPLEFT", 20, 5)
    tooltipColorDropdownText:SetText("Tooltip Color:")

    UIDropDownMenu_SetWidth(tooltipColorDropdown, 120)
    UIDropDownMenu_SetText(tooltipColorDropdown, BiSJournal.tooltipColorOptions[BiSJournalDB.config.tooltipColorOption or 1].text)

    UIDropDownMenu_Initialize(tooltipColorDropdown, function(self, level)
        for i, option in ipairs(tooltipColorDropdown.colorOptions) do
            local info = UIDropDownMenu_CreateInfo()
            info.text = option.text
            info.value = option.value
            info.func = function()
                BiSJournalDB.config.tooltipColorOption = i
                UIDropDownMenu_SetText(tooltipColorDropdown, option.text)
            end
            UIDropDownMenu_AddButton(info, level)
        end
    end)

    -- Export Label
    local exportLabel = scrollChild:CreateFontString(nil, "ARTWORK", "GameFontNormal")
    exportLabel:SetPoint("TOPLEFT", colorDropdown, "BOTTOMLEFT", 10, -30)
    exportLabel:SetText("Export String:")

    -- Export Button
    local exportButton = CreateFrame("Button", nil, scrollChild, "UIPanelButtonTemplate")
    exportButton:SetText("Export BiS List")
    exportButton:SetSize(120, 22)
    exportButton:SetPoint("TOPLEFT", exportLabel, "BOTTOMLEFT", 0, -5)
    exportButton:SetScript("OnClick", function()
        local exportString = BiSJournal.ExportCurrentBiSList()
        StaticPopup_Show("BISJOURNAL_EXPORT", nil, nil, exportString)
    end)

    -- Import Label
    local importLabel = scrollChild:CreateFontString(nil, "ARTWORK", "GameFontNormal")
    importLabel:SetPoint("TOPLEFT", exportLabel, "TOPRIGHT", 150, 0)
    importLabel:SetText("Import String:")

    -- Import Button
    local importButton = CreateFrame("Button", nil, scrollChild, "UIPanelButtonTemplate")
    importButton:SetText("Import BiS List")
    importButton:SetSize(120, 22)
    importButton:SetPoint("TOPLEFT", importLabel, "BOTTOMLEFT", 0, -5)
    importButton:SetScript("OnClick", function()
        StaticPopup_Show("BISJOURNAL_IMPORT")
    end)

    -- Add a divider before the Manual Item Addition section
    local divider = scrollChild:CreateTexture(nil, "ARTWORK")
    divider:SetAtlas("Options_HorizontalDivider", true)
    divider:SetPoint("TOPLEFT", exportButton, "BOTTOMLEFT", -15, -20)
    divider:SetWidth(scrollFrame:GetWidth() - 40)

    -- Manual Item Addition Section Header
    local manualAddHeader = scrollChild:CreateFontString(nil, "ARTWORK", "GameFontNormalLarge")
    manualAddHeader:SetPoint("TOPLEFT", divider, "BOTTOMLEFT", 40, -15)
    manualAddHeader:SetText("Add Items Manually")

    -- Instructions
    local manualAddInstructions = scrollChild:CreateFontString(nil, "ARTWORK", "GameFontNormal")
    manualAddInstructions:SetPoint("TOPLEFT", manualAddHeader, "BOTTOMLEFT", 10, -10)
    manualAddInstructions:SetText("Enter an item ID to add items not found in the Adventure Guide or from vendors.")

    -- Item ID Label
    local itemIDLabel = scrollChild:CreateFontString(nil, "ARTWORK", "GameFontHighlight")
    itemIDLabel:SetPoint("TOPLEFT", manualAddInstructions, "BOTTOMLEFT", 10, -15)
    itemIDLabel:SetText("Item ID:")

    -- Item ID Input Box
    local itemIDBox = CreateFrame("EditBox", "BiSJournalItemIDInput", scrollChild, "InputBoxTemplate")
    itemIDBox:SetSize(150, 24)
    itemIDBox:SetPoint("TOPLEFT", itemIDLabel, "BOTTOMLEFT", 0, -5)
    itemIDBox:SetAutoFocus(false)
    itemIDBox:SetNumeric(true)
    itemIDBox:SetMaxLetters(10)

    -- Add placeholder text functionality
    itemIDBox.placeholderText = "Enter an item ID"
    itemIDBox:SetText(itemIDBox.placeholderText)
    itemIDBox:SetTextColor(0.5, 0.5, 0.5) -- Gray color for placeholder
    itemIDBox:SetScript("OnEditFocusGained", function(self)
        if self:GetText() == self.placeholderText then
            self:SetText("")
            self:SetTextColor(1, 1, 1) -- White color for actual input
        end
    end)
    itemIDBox:SetScript("OnEditFocusLost", function(self)
        if self:GetText() == "" then
            self:SetText(self.placeholderText)
            self:SetTextColor(0.5, 0.5, 0.5) -- Gray color for placeholder
        end
    end)

    -- Preview Frame
    local previewFrame = CreateFrame("Frame", nil, scrollChild)
    previewFrame:SetSize(40, 40)
    previewFrame:SetPoint("LEFT", itemIDBox, "RIGHT", 25, 0)

    local previewIcon = previewFrame:CreateTexture(nil, "ARTWORK")
    previewIcon:SetAllPoints()
    previewIcon:SetTexture("Interface\\Icons\\INV_Misc_QuestionMark")

    local previewName = scrollChild:CreateFontString(nil, "ARTWORK", "GameFontHighlight")
    previewName:SetPoint("LEFT", previewFrame, "RIGHT", 10, 0)

    -- Source Label
    local sourceLabel = scrollChild:CreateFontString(nil, "ARTWORK", "GameFontHighlight")
    sourceLabel:SetPoint("TOPLEFT", itemIDBox, "BOTTOMLEFT", 0, -15)
    sourceLabel:SetText("Source (e.g., \"World Quest - Expansion Name\" Source - Location):")

    -- Source Input Box
    local sourceBox = CreateFrame("EditBox", "BiSJournalSourceInput", scrollChild, "InputBoxTemplate")
    sourceBox:SetSize(300, 24)
    sourceBox:SetPoint("TOPLEFT", sourceLabel, "BOTTOMLEFT", 0, -5)
    sourceBox:SetAutoFocus(false)
    sourceBox:SetMaxLetters(100)

    -- Quick Templates text
    local sourceTemplateDropdownText = scrollChild:CreateFontString(nil, "ARTWORK", "GameFontHighlight")
    sourceTemplateDropdownText:SetPoint("TOPLEFT", sourceBox, "BOTTOMLEFT", 0, -15)
    sourceTemplateDropdownText:SetText("Quick Templates:")

    -- Source Template Dropdown
    local sourceTemplateDropdown = CreateFrame("Frame", "BiSJournalSourceTemplateDropdown", scrollChild, "UIDropDownMenuTemplate")
    sourceTemplateDropdown:SetPoint("TOPLEFT", sourceTemplateDropdownText, "BOTTOMLEFT", -5, -5)

    -- Add Button
    local addButton = CreateFrame("Button", nil, scrollChild, "UIPanelButtonTemplate")
    addButton:SetSize(100, 22)
    addButton:SetPoint("TOPLEFT", sourceTemplateDropdown, "BOTTOMLEFT", 15, -15)
    addButton:SetText("Add Item")

    -- Configure the dropdown
    UIDropDownMenu_SetWidth(sourceTemplateDropdown, 150)
    UIDropDownMenu_SetText(sourceTemplateDropdown, "Select Source")

    local sourceTemplates = {
        { text = "World Quest", value = "World Quest - (Type Expansion Here)" },
        { text = "Delve", value = "Delve - The War Within" },
        { text = "PvP Reward", value = "PvP Reward - (Type Expansion Here)" },
        { text = "Crafted", value = "Crafted Item - (Type Expansion Here)" },
        { text = "Trading Post", value = "Trading Post" },
        { text = "World Drop", value = "World Drop - (Type Zone Here)" }
    }

    UIDropDownMenu_Initialize(sourceTemplateDropdown, function(self, level)
        for i, template in ipairs(sourceTemplates) do
            local info = UIDropDownMenu_CreateInfo()
            info.text = template.text
            info.value = template.value
            info.func = function()
                sourceBox:SetText(template.value)
                UIDropDownMenu_SetText(sourceTemplateDropdown, template.text)
            end
            UIDropDownMenu_AddButton(info, level)
        end
    end)

    -- Update preview when item ID changes
    itemIDBox:SetScript("OnTextChanged", function(self)
        local itemID = tonumber(self:GetText())
        if not itemID or itemID == 0 then
            previewIcon:SetTexture("Interface\\Icons\\INV_Misc_QuestionMark")
            previewName:SetText("Enter an item ID")
            return
        end
        
        RequestLoadItemDataByIDFunc(itemID)
        C_Timer.After(0.2, function()
            local itemName, itemLink, itemRarity, _, _, _, _, _, _, itemTexture = C_Item.GetItemInfoFunc(itemID)
            if itemName then
                previewIcon:SetTexture(itemTexture)
                previewName:SetText(itemLink or itemName)
            else
                previewIcon:SetTexture("Interface\\Icons\\INV_Misc_QuestionMark")
                previewName:SetText("Item not found")
            end
        end)
    end)

    -- Add Button functionality
    addButton:SetScript("OnClick", function()
        local itemID = tonumber(itemIDBox:GetText())
        local source = sourceBox:GetText()
        
        if not itemID or itemID == 0 then
            print("|cFFFF0000BiS Journal:|r Please enter a valid item ID.")
            return
        end
        
        if not source or source == "" then
            source = "Manual Addition"
        end
        
        -- Request item data to ensure it exists
        C_Item.RequestLoadItemDataByID(itemID)
        
        -- Use a slight delay to allow item data to load
        C_Timer.After(0.5, function()
            local itemName = C_Item.GetItemInfo(itemID)
            if not itemName then
                print("|cFFFF0000BiS Journal:|r Invalid item ID or item data not available.")
                return
            end
            
            -- Call your AddToBiSList function
            AddToBiSList(itemID, source)
            
            -- Clear the input boxes
            itemIDBox:SetText("")
            sourceBox:SetText("")
        end)
    end)

    -- Update preview when item ID changes
    itemIDBox:SetScript("OnTextChanged", function(self)
        local itemID = tonumber(self:GetText())
        if not itemID or itemID == 0 then
            previewIcon:SetTexture("Interface\\Icons\\INV_Misc_QuestionMark")
            previewName:SetText("Enter an item ID")
            return
        end
        
        C_Item.RequestLoadItemDataByID(itemID)
        C_Timer.After(0.2, function()
            local itemName, itemLink, itemRarity, _, _, _, _, _, _, itemTexture = C_Item.GetItemInfo(itemID)
            if itemName then
                previewIcon:SetTexture(itemTexture)
                previewName:SetText(itemLink or itemName)
            else
                previewIcon:SetTexture("Interface\\Icons\\INV_Misc_QuestionMark")
                previewName:SetText("Item not found")
            end
        end)
    end)


end
    

function BiSJournal:InitializeOptions()
    CreateOptionsPanel()
end