-- Roll History

StefansLootTracker.loadedRollStartIndex = 1
StefansLootTracker.loadedRollEndIndex = StefansLootTracker.itemsRollPerLoad or 30
StefansLootTracker.itemsRollPerLoad = 30

StefansLootTracker.frameRollPool = {}
StefansLootTracker.visibleRollFrames = {}
StefansLootTracker.frameRollHeight = 15

function StefansLootTracker:matchRollMessage(msg)
    local rollPatterns = {
        "(.+) Need Roll .+",
        "(.+) Greed Roll .+",
        "(.+) passed on: .+",
        "(.+) has selected Greed for: .+",
        "(.+) have selected Greed for: .+",
        "(.+) has selected Need for: .+",
        "(.+) have selected Need for: .+",
        "(.+) won: .+"
    }

    for _, pattern in ipairs(rollPatterns) do
        if msg:match(pattern) then
            return true
        end
    end
    return false
end

function StefansLootTracker:HandleRollMessage(rollMessage)
    -- Debug: Log the received roll message
    if self.db.profile.qDebug then
        print("Debug: Received roll string: " .. rollMessage)
    end

    -- Remove the specific pattern |HlootHistory:<digit>|h[Loot]|h:
    rollMessage = rollMessage:gsub("|HlootHistory:%d+|h%[Loot%]|h: ", "")

    -- Replace "You" with the character's name
    local playerName = UnitName("player")
    rollMessage = rollMessage:gsub("You", playerName)

    -- Parse the loot message
    local rarity = self:getRarity(rollMessage)

    -- Debug: Log the parsed details
    if self.db.profile.qDebug then
        print("Debug: Parsed rarity: " .. (rarity or "Unknown"))
    end

    -- Check if the item meets the rarity filter
    if rarity < self.db.profile.rarityFilter then
        if self.db.profile.qDebug then 
            self:Print("ROLL DOESN'T MEET RARITY FILTER")
        end
        return
    end

    -- Get the current timestamp
    local timestamp = date("%Y-%m-%d %H:%M:%S")

    -- Update the data structure
    if not self.db.profile.rollhist then
        self.db.profile.rollhist = {}
    end

    -- Insert a new roll event with its timestamp and modified message
    table.insert(self.db.profile.rollhist, {
        message = rollMessage,
        timestamp = timestamp
    })

    -- Update the window only if it's open
    self:UpdateRollHistoryIfOpen()
end

function StefansLootTracker:ClearRollHistory()
    self.db.profile.result2 = {} -- Old Roll History Database
    self.db.profile.rollhist = {} -- Roll History Database
    self:Print("Roll History has been cleared.")
    if self.rollHistoryFrame and self.rollHistoryFrame:IsShown() then
        self:UpdateRollHistoryWindow()  -- Update the roll history window if it's open
    end
end

local searchRollDebounceTimer
function StefansLootTracker:RollDebouncedSearch(searchRollTerm)
    if searchRollDebounceTimer then
        searchRollDebounceTimer:Cancel()
    end
    searchRollDebounceTimer = C_Timer.After(0.5, function()
        self:UpdateRollHistoryWindow(searchRollTerm)
    end)
end

local loadRollMoreTimer
function StefansLootTracker:DebouncedRollLoadMoreResults()
    if loadRollMoreTimer then
        loadRollMoreTimer:Cancel()
    end
    loadRollMoreTimer = C_Timer.NewTimer(0.2, function()
        self:RollLoadMoreResults()
    end)
end

function StefansLootTracker:CreateRollHistoryWindow()
    -- Check if the frame already exists to avoid creating duplicates
    if self.rollHistoryFrame then
        self.rollHistoryFrame:Show()
        return
    end

    local f = CreateFrame("Frame", "StefansLootTrackerRollHistoryFrame", UIParent, "BackdropTemplate")
    local pos = self.db.profile.rollHistorywindowPosition
    local size = self.db.profile.rollHistorywindowSize
    f:SetSize(size.width, size.height)
    f:SetPoint(pos.point, UIParent, pos.relativePoint, pos.x, pos.y)
    f:SetMovable(true)
    f:SetResizable(true)
    f:SetResizeBounds(300, 200) -- Set minimum size
    f:EnableMouse(true)
    f:RegisterForDrag("LeftButton")
    f:SetScript("OnDragStart", f.StartMoving)
    f:SetScript("OnDragStop", f.StopMovingOrSizing)
    f:SetHyperlinksEnabled(true)
    f:SetScript("OnHyperlinkClick", ChatFrame_OnHyperlinkShow)
    f:Hide()

    f:SetBackdrop({
        bgFile = "Interface\\DialogFrame\\UI-DialogBox-Background",
        edgeFile = "Interface\\DialogFrame\\UI-DialogBox-Border",
        tile = true,
        tileSize = 32,
        edgeSize = 32,
        insets = { left = 8, right = 8, top = 8, bottom = 8 }
    })

    -- Create the title frame
    local titleFrame = CreateFrame("Frame", nil, f)
    titleFrame:SetSize(f:GetWidth(), 30)
    titleFrame:SetPoint("TOP", f, "TOP", 0, 10)

    local titleText = titleFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlightLarge")
    titleText:SetPoint("CENTER", titleFrame, "CENTER")
    titleText:SetText("Roll History")

    -- Create the close button
    local closeButton = CreateFrame("Button", nil, f, "UIPanelCloseButton")
    closeButton:SetPoint("TOPRIGHT", f, "TOPRIGHT", -5, -5)
    closeButton:SetScript("OnClick", function()
        f:Hide()
        StefansLootTracker.isRollHistoryWindowOpen = false
        StefansLootTracker:ResetRollLazyLoading()
    end)

    -- Create the refresh button
    local refreshButton = self:CreateRefreshButton(f)
    refreshButton:SetScript("OnClick", function()
        self:UpdateRollHistoryWindow()
    end)

    -- Create search box
    local searchBox = CreateFrame("EditBox", nil, f, "InputBoxTemplate")
    searchBox:SetPoint("TOPLEFT", f, "TOPLEFT", 15, -50)
    searchBox:SetPoint("RIGHT", f, "RIGHT", -15, 0)
    searchBox:SetHeight(20)
    searchBox:SetFontObject("GameFontNormal")
    searchBox:SetAutoFocus(false)
    searchBox:SetScript("OnEscapePressed", function(self) self:ClearFocus() end)
    searchBox:SetTextInsets(22, 10, 2, 2)

    local bg = searchBox:CreateTexture(nil, "BACKGROUND")
    bg:SetAllPoints()
    bg:SetColorTexture(0, 0, 0, 0.1)

    local searchIcon = f:CreateTexture(nil, "ARTWORK")
    searchIcon:SetTexture("Interface\\Common\\UI-Searchbox-Icon")
    searchIcon:SetSize(14, 14)
    searchIcon:SetPoint("LEFT", searchBox, "LEFT", 6, 0)

    searchBox.placeholderText = searchBox:CreateFontString(nil, "ARTWORK", "GameFontNormalSmall")
    searchBox.placeholderText:SetPoint("LEFT", searchIcon, "RIGHT", 10, 0)
    searchBox.placeholderText:SetText("Search")
    searchBox.placeholderText:SetTextColor(0.6, 0.6, 0.6)

    searchBox:SetScript("OnTextChanged", function(self)
        local text = self:GetText()
        if text == "" then
            self.placeholderText:Show()
        else
            self.placeholderText:Hide()
        end
        StefansLootTracker:RollDebouncedSearch(text)
    end)

    searchBox:SetScript("OnEditFocusGained", function(self)
        self.placeholderText:Hide()
    end)

    searchBox:SetScript("OnEditFocusLost", function(self)
        if self:GetText() == "" then
            self.placeholderText:Show()
        end
    end)

    f.searchBox = searchBox

    -- Create the scroll frame
    local scrollFrame = CreateFrame("ScrollFrame", nil, f, "UIPanelScrollFrameTemplate")
    scrollFrame:SetPoint("TOPLEFT", f, "TOPLEFT", 10, -80)
    scrollFrame:SetPoint("BOTTOMRIGHT", f, "BOTTOMRIGHT", -30, 10)
    scrollFrame:SetScript("OnVerticalScroll", function(self, offset)
        self.ScrollBar:SetValue(offset)
        StefansLootTracker:UpdateRollHistoryDisplay()
    end)

    local scrollChild = CreateFrame("Frame", nil, scrollFrame)
    scrollChild:SetWidth(scrollFrame:GetWidth() - 16)  -- Subtract scrollbar width
    scrollFrame:SetScrollChild(scrollChild)
    f.scrollFrame = scrollFrame
    f.scrollChild = scrollChild

    f.noResultsText = f:CreateFontString(nil, "ARTWORK", "GameFontHighlight")
    f.noResultsText:SetPoint("CENTER", f.scrollChild, "CENTER")
    f.noResultsText:SetText("No results found")
    f.noResultsText:Hide()

    f.UpdateNoResults = function(self, noResults)
        if noResults then
            self.noResultsText:Show()
        else
            self.noResultsText:Hide()
        end
    end

    -- Create resize handle
    local resizeHandle = CreateFrame("Button", nil, f)
    resizeHandle:SetPoint("BOTTOMRIGHT")
    resizeHandle:SetSize(16, 16)
    resizeHandle:SetNormalTexture("Interface\\ChatFrame\\UI-ChatIM-SizeGrabber-Up")
    resizeHandle:SetHighlightTexture("Interface\\ChatFrame\\UI-ChatIM-SizeGrabber-Highlight")
    resizeHandle:SetPushedTexture("Interface\\ChatFrame\\UI-ChatIM-SizeGrabber-Down")
    
    resizeHandle:SetScript("OnMouseDown", function(self, button)
        f:StartSizing("BOTTOMRIGHT")
    end)
    
    resizeHandle:SetScript("OnMouseUp", function(self, button)
        f:StopMovingOrSizing()
        StefansLootTracker:UpdateRollHistoryLayout()
        -- Save the new size
        StefansLootTracker.db.profile.rollHistorywindowSize = { width = f:GetWidth(), height = f:GetHeight() }
    end)

    self.rollHistoryFrame = f

    self.frameRollPool = {}
    self.visibleRollFrames = {}

    self:UpdateRollHistoryWindow()
end

function StefansLootTracker:UpdateRollHistoryLayout()
    local f = self.rollHistoryFrame
    if not f then return end

    -- Update search box width
    f.searchBox:SetWidth(f:GetWidth() - 30)

    -- Update scroll frame size
    f.scrollFrame:SetPoint("BOTTOMRIGHT", f, "BOTTOMRIGHT", -30, 10)

    -- Update scroll child width
    f.scrollChild:SetWidth(f.scrollFrame:GetWidth() - 16)  -- Subtract scrollbar width

    -- Update visible frames width
    for _, frame in ipairs(self.visibleRollFrames) do
        frame:SetWidth(f.scrollChild:GetWidth() - 10)
        frame.messageButton:SetPoint("RIGHT", frame, "RIGHT", 0, 0)
    end

    -- Update the display
    self:UpdateRollHistoryDisplay()
end

function StefansLootTracker:UpdateRollHistoryWindow(searchRollTerm)
    local frame = self.rollHistoryFrame
    if not frame then return end

    searchRollTerm = searchRollTerm or ""

    if searchRollTerm ~= self.lastsearchRollTerm then
        self:ResetRollLazyLoading()
        self.lastsearchRollTerm = searchRollTerm
    end

    -- Initialize FilteredRollIndices
    self.FilteredRollIndices = {}
    for i = #self.db.profile.rollhist, 1, -1 do
        local entry = self.db.profile.rollhist[i]
        if searchRollTerm == "" or entry.message:lower():find(searchRollTerm:lower(), 1, true) then
            table.insert(self.FilteredRollIndices, i)
        end
    end

    local totalFilteredRollItems = #self.FilteredRollIndices
    local displayedHeight = totalFilteredRollItems * self.frameRollHeight
    frame.scrollChild:SetHeight(displayedHeight)

    self:UpdateRollHistoryLayout()
    self:UpdateRollHistoryDisplay()

    frame:UpdateNoResults(totalFilteredRollItems == 0)
end

function StefansLootTracker:UpdateRollHistoryDisplay()
    local frame = self.rollHistoryFrame
    local scrollFrame = frame.scrollFrame
    local scrollOffset = scrollFrame:GetVerticalScroll()
    local visibleHeight = scrollFrame:GetHeight()
    
    if not self.FilteredRollIndices then
        self:UpdateRollHistoryWindow()
    end

    local totalItems = #self.FilteredRollIndices
    local itemsPerPage = math.floor(visibleHeight / self.frameRollHeight)
    
    local startIndex = math.floor(scrollOffset / self.frameRollHeight) + 1
    local endIndex = math.min(startIndex + itemsPerPage - 1, totalItems)

    for i = 1, itemsPerPage do
        local dataIndex = startIndex + i - 1
        local entryFrame = self.visibleRollFrames[i] or self:CreateRollEntryFrame(frame.scrollChild)
        
        if dataIndex <= totalItems then
            local entry = self.db.profile.rollhist[self.FilteredRollIndices[dataIndex]]
            
            entryFrame:SetPoint("TOPLEFT", frame.scrollChild, "TOPLEFT", 5, -((dataIndex-1) * self.frameRollHeight))
            entryFrame:SetPoint("RIGHT", frame.scrollChild, "RIGHT", -5, 0)
            entryFrame:SetHeight(self.frameRollHeight)

            entryFrame.timestampText:SetText(string.format("[%s]", entry.timestamp))
            entryFrame.messageButton.text:SetText(entry.message)

            entryFrame:Show()
            self.visibleRollFrames[i] = entryFrame
        else
            entryFrame:Hide()
        end
    end

    -- Hide any extra frames
    for i = itemsPerPage + 1, #self.visibleRollFrames do
        self.visibleRollFrames[i]:Hide()
    end

    -- Update scroll child height
    local newHeight = totalItems * self.frameRollHeight
    if frame.scrollChild:GetHeight() ~= newHeight then
        frame.scrollChild:SetHeight(newHeight)
        scrollFrame.ScrollBar:SetMinMaxValues(0, max(newHeight - scrollFrame:GetHeight(), 0))
    end
end

function StefansLootTracker:CreateRollEntryFrame(parent)
    local frame = CreateFrame("Frame", nil, parent)
    frame:SetSize(parent:GetWidth() - 10, self.frameRollHeight)

    frame.timestampText = frame:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
    frame.timestampText:SetPoint("LEFT", frame, "LEFT", 0, 0)

    -- Create a Button instead of a FontString for the message
    frame.messageButton = CreateFrame("Button", nil, frame)
    frame.messageButton:SetPoint("LEFT", frame.timestampText, "RIGHT", 5, 0)
    frame.messageButton:SetPoint("RIGHT", frame, "RIGHT", 0, 0)
    frame.messageButton:SetHeight(self.frameRollHeight)
    
    frame.messageButton.text = frame.messageButton:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
    frame.messageButton.text:SetAllPoints()
    frame.messageButton.text:SetJustifyH("LEFT")

    -- Enable hyperlinks on the button
    frame.messageButton:SetHyperlinksEnabled(true)
    frame.messageButton:SetScript("OnHyperlinkClick", ChatFrame_OnHyperlinkShow)
    frame.messageButton:SetScript("OnHyperlinkEnter", function(self, link, text)
        GameTooltip:SetOwner(self, "ANCHOR_CURSOR")
        GameTooltip:SetHyperlink(link)
        GameTooltip:Show()
    end)
    frame.messageButton:SetScript("OnHyperlinkLeave", function(self)
        GameTooltip:Hide()
    end)

    return frame
end

function StefansLootTracker:ToggleRollHistoryWindow()
    if not self.rollHistoryFrame then
        self:CreateRollHistoryWindow()
    end

    if self.isRollHistoryWindowOpen then
        self.rollHistoryFrame:Hide()
        self.isRollHistoryWindowOpen = false
        self:ResetRollLazyLoading()
    else
        -- Reset the lazy loading and search box
        if self.rollHistoryFrame.searchBox then
            self.rollHistoryFrame.searchBox:SetText("")
            self.rollHistoryFrame.searchBox.placeholderText:Show()
        end

        self:ResetRollLazyLoading()

        -- Update the layout and window, then show it
        self:UpdateRollHistoryLayout()
        self:UpdateRollHistoryWindow()
        self.rollHistoryFrame:Show()
        self.isRollHistoryWindowOpen = true

        -- Ensure the scroll is at the top
        C_Timer.After(0, function()
            self.rollHistoryFrame.scrollFrame:SetVerticalScroll(0)
            self:UpdateRollHistoryDisplay()
        end)
    end
end

function StefansLootTracker:UpdateRollHistoryIfOpen()
    if self.isRollHistoryWindowOpen then
        self:UpdateRollHistoryWindow()
    end
end

function StefansLootTracker:RollOnScroll()
    local frame = self.rollHistoryFrame
    local scrollFrame = frame.scrollFrame
    local scrollOffset = scrollFrame:GetVerticalScroll()
    local scrollHeight = scrollFrame:GetHeight()
    local childHeight = frame.scrollChild:GetHeight()

    -- Check if we're near the bottom of the scroll frame
    if (scrollOffset + scrollHeight) >= (childHeight - 20) then
        -- Prevent multiple triggers
        if self.loadingRollMore then return end
        self.loadingRollMore = true

        -- Load more results
        self:RollLoadMoreResults()
    end
end

function StefansLootTracker:RollLoadMoreResults()
    if self.loadingRollMore then return end
    self.loadingRollMore = true

    -- Increase the loaded roll range for the next batch
    self.loadedRollStartIndex = math.max(self.loadedRollStartIndex - self.itemsRollPerLoad, 1)

    -- Update the window with the current search term
    self:UpdateRollHistoryWindow(self.lastsearchRollTerm)
    
    self.loadingRollMore = false
end

function StefansLootTracker:ResetRollLazyLoading()
    self.loadedRollStartIndex = 1
    self.loadedRollEndIndex = math.min(self.itemsRollPerLoad, #self.db.profile.rollhist)
    self.FilteredRollIndices = nil  -- Reset FilteredRollIndices
    self.lastsearchRollTerm = nil
end
