-- ============================================================================
-- Chat Management
-- ============================================================================
AIOS_CopyBox_ChatManager = {
    currentChatFrame = 1,
    availableChannels = {},
    lastViewedChannel = 1,
    isMouseOverChannel = false,
    hookedChats = {},
    lastProcessedMessages = {},
    editBox = nil,
    pendingOpen = nil
}

function AIOS_CopyBox_ChatManager:Initialize()
    self:UpdateAvailableChannels()

    local f = CreateFrame("Frame")
    f:RegisterEvent("PLAYER_REGEN_ENABLED")
    f:SetScript("OnEvent", function()
        if self.pendingOpen then
            local chatFrameId, maxLines = unpack(self.pendingOpen)
            self.pendingOpen = nil
            self:PerformOpenCopyBox(chatFrameId, maxLines)
        end
    end)
    self.combatFrame = f

    self:HookChatFramesForLiveUpdates()

    if AIOS_CopyBox_Logger then
        AIOS_CopyBox_Logger:Debug("Chat manager initialized", "Chat")
    end
end

function AIOS_CopyBox_ChatManager:SetEditBox(editBox)
    self.editBox = editBox
end

function AIOS_CopyBox_ChatManager:GetChannelName(chatFrameId)
    local cf = _G["ChatFrame" .. chatFrameId]
    if not cf then return nil end

    local success, name, _, _, _, _, shown, _, docked = pcall(FCF_GetChatWindowInfo, chatFrameId)
    if not success or not name or name == "" then return nil end

    if name:lower():find("voice") then
        return nil
    end

    if shown or docked then
        return name
    end

    return nil
end

function AIOS_CopyBox_ChatManager:UpdateAvailableChannels()
    self.availableChannels = {}

    local maxFrames = NUM_CHAT_WINDOWS or 10
    local seenNames = {}

    for i = 1, maxFrames do
        local name = self:GetChannelName(i)
        if name then
            local displayName = name
            if seenNames[name] then
                displayName = name .. " (" .. i .. ")"
            else
                seenNames[name] = true
            end
            table.insert(self.availableChannels, { id = i, name = displayName })
        end
    end

    table.sort(self.availableChannels, function(a, b) return a.id < b.id end)

    if AIOS_CopyBox_Logger then
        AIOS_CopyBox_Logger:Debug("Updated available channels: " .. #self.availableChannels, "Chat")
    end
end

function AIOS_CopyBox_ChatManager:UpdateChannelDisplay()
    if not AIOS_CopyBox_MainFrame then return end

    local channelName = self:GetChannelName(self.currentChatFrame) or "General"
    if AIOS_CopyBox_MainFrame.channelText and channelName then
        local colors = AIOS_CopyBox_Config.colors
        if self.isMouseOverChannel then
            AIOS_CopyBox_MainFrame.channelText:SetText(colors.hoverText .. "Channel:|r " .. colors.channelText .. channelName .. "|r")
        else
            AIOS_CopyBox_MainFrame.channelText:SetText(colors.normalText .. "Channel:|r " .. colors.channelText .. channelName .. "|r")
        end
    end
end

function AIOS_CopyBox_ChatManager:GetChatMessages(chatFrameId, maxLines)
    local cf = _G["ChatFrame" .. chatFrameId]
    if not cf then
        if AIOS_CopyBox_Logger then
            AIOS_CopyBox_Logger:Error("ChatFrame" .. chatFrameId .. " not found", "Chat")
        end
        return {}
    end

    -- Safety: ensure maxLines is valid
    local configMax = AIOS_CopyBox_Config and AIOS_CopyBox_Config.chat and AIOS_CopyBox_Config.chat.maxLines
    maxLines = math.min(maxLines or configMax or 500, 1000)

    local lines = {}

    -- Method 1: Modern historyBuffer (Retail / newer clients)
    if cf.historyBuffer and cf.historyBuffer.GetNumElements then
        local hb = cf.historyBuffer
        local numElements = hb:GetNumElements() or 0

        if numElements > 0 then
            local startIdx = math.max(1, numElements - maxLines + 1)

            for i = startIdx, numElements do
                local entry = hb:GetEntryAtIndex(i)
                if entry and type(entry) == "table" then
                    local msg = entry.message or entry.text
                    local r = entry.r or 1
                    local g = entry.g or 1
                    local b = entry.b or 1
                    local chatType = entry.chatType or entry.type

                    if msg and #tostring(msg) > 0 then
                        local processed = self:ProcessMessage(tostring(msg), r, g, b, chatType)
                        if processed and #processed > 0 then
                            table.insert(lines, processed)
                        end
                    end
                elseif entry and type(entry) == "string" and #entry > 0 then
                    table.insert(lines, entry)
                end
            end
        end
    end

    -- Method 2: Legacy GetMessageInfo (Classic / fallback)
    if #lines == 0 then
        local success, totalLines = pcall(function() return cf:GetNumMessages() end)
        if success and totalLines and totalLines > 0 then
            local startLine = math.max(1, totalLines - maxLines + 1)

            for i = startLine, totalLines do
                local success2, msg, r, g, b, chatType = pcall(function()
                    return cf:GetMessageInfo(i)
                end)

                if success2 and msg then
                    local msgStr = tostring(msg)
                    if #msgStr > 0 then
                        local processed = self:ProcessMessage(msgStr, r, g, b, chatType)
                        if processed and #processed > 0 then
                            table.insert(lines, processed)
                        end
                    end
                end
            end
        end
    end

    return lines
end

function AIOS_CopyBox_ChatManager:ProcessMessage(msg, r, g, b, chatType)
    if not msg then return nil end

    local currentMsg = tostring(msg)
    if #currentMsg == 0 then return nil end

    if currentMsg:find("CopyBox DEBUG:", 1, true) then
        return nil
    end

    local function containsWord(text, word)
        local wordLen = #word
        local textLen = #text
        if wordLen > textLen then return false end

        for i = 1, textLen - wordLen + 1 do
            local match = true
            for j = 1, wordLen do
                if text:sub(i + j - 1, i + j - 1) ~= word:sub(j, j) then
                    match = false
                    break
                end
            end
            if match then return true end
        end
        return false
    end

    if containsWord(currentMsg, "AIOS") or 
       containsWord(currentMsg, "codec") or 
       containsWord(currentMsg, "DEBUG") then
        return currentMsg
    end

    local hasColor = false
    if #currentMsg >= 10 and currentMsg:sub(1, 2) == "|c" then
        hasColor = true
        for i = 3, 10 do
            local char = currentMsg:sub(i, i)
            local byte = string.byte(char)
            local isHex = (byte >= 48 and byte <= 57) or
                          (byte >= 65 and byte <= 70) or
                          (byte >= 97 and byte <= 102)
            if not isHex then
                hasColor = false
                break
            end
        end
    end

    if not hasColor then
        local colorCode = AIOS_CopyBox_Config.colors.normalText
        if r and g and b then
            local rr = math.max(0, math.min(1, tonumber(r) or 1))
            local gg = math.max(0, math.min(1, tonumber(g) or 1))
            local bb = math.max(0, math.min(1, tonumber(b) or 1))
            colorCode = string.format("|cff%02x%02x%02x", rr * 255, gg * 255, bb * 255)
        end
        return colorCode .. currentMsg .. "|r"
    end

    return currentMsg
end

function AIOS_CopyBox_ChatManager:SwitchToChannel(channelId)
    self.currentChatFrame = channelId
    self.lastViewedChannel = channelId

    if AIOS_CopyBoxDB then
        AIOS_CopyBoxDB.lastChannel = channelId
    end

    self:UpdateChannelDisplay()
    self.lastProcessedMessages = {}

    local channelName = self:GetChannelName(channelId)
    local lines = self:GetChatMessages(channelId, AIOS_CopyBox_Config.chat.maxLines)

    if self.editBox then
        if #lines > 0 then
            local text = table.concat(lines, "\n")
            self.editBox:SetText(text)
            self.editBox:SetCursorPosition(0)
        else
            self.editBox:SetText(string.format(AIOS_CopyBox_Config.messages.noMessages, channelName or "this chat"))
        end
    end

    if AIOS_CopyBox_Logger then
        AIOS_CopyBox_Logger:Debug("Switched to channel: " .. (channelName or channelId), "Chat")
    end
end

function AIOS_CopyBox_ChatManager:CycleChannels(forward)
    self:UpdateAvailableChannels()
    if #self.availableChannels == 0 then
        if AIOS_CopyBox_Logger then
            AIOS_CopyBox_Logger:Warn("No available channels to cycle", "Chat")
        end
        return
    end

    local currentIndex = 1
    for i, channel in ipairs(self.availableChannels) do
        if channel.id == self.currentChatFrame then
            currentIndex = i
            break
        end
    end

    local nextIndex
    if forward then
        nextIndex = currentIndex + 1
        if nextIndex > #self.availableChannels then
            nextIndex = 1
        end
    else
        nextIndex = currentIndex - 1
        if nextIndex < 1 then
            nextIndex = #self.availableChannels
        end
    end

    local nextChannel = self.availableChannels[nextIndex]
    if nextChannel then
        self:SwitchToChannel(nextChannel.id)

        if AIOS_CopyBox_Logger then
            AIOS_CopyBox_Logger:Debug("Cycled to channel: " .. nextChannel.name, "Chat")
        end
    end
end

function AIOS_CopyBox_ChatManager:GetSelectedChatFrameId()
    if SELECTED_CHAT_FRAME then
        local name = SELECTED_CHAT_FRAME:GetName()
        if name then
            local id = tonumber(name:match("ChatFrame(%d+)"))
            if id and id > 0 then
                return id
            end
        end
    end
    return 1
end

function AIOS_CopyBox_ChatManager:OpenCopyBox(chatFrameId, maxLines)
    if InCombatLockdown() then
        self.pendingOpen = {chatFrameId or self.lastViewedChannel, maxLines or AIOS_CopyBox_Config.chat.maxLines}
        if AIOS_CopyBox_Logger then
            AIOS_CopyBox_Logger:Info("Combat active - deferring copy box open", "Chat")
        end
        print("|cffffaa00[CopyBox]|r Combat detected. Opening when combat ends...")
        return
    end

    self:PerformOpenCopyBox(chatFrameId, maxLines)
end

function AIOS_CopyBox_ChatManager:PerformOpenCopyBox(chatFrameId, maxLines)
    if not AIOS_CopyBox_MainFrame then
        if AIOS_CopyBox_Logger then
            AIOS_CopyBox_Logger:Error("Main frame not available", "Chat")
        end
        return
    end

    if not chatFrameId then
        chatFrameId = self:GetSelectedChatFrameId()
    end

    chatFrameId = chatFrameId or 1
    maxLines = maxLines or AIOS_CopyBox_Config.chat.maxLines

    self:UpdateAvailableChannels()

    local validFrame = false
    for _, ch in ipairs(self.availableChannels) do
        if ch.id == chatFrameId then
            validFrame = true
            break
        end
    end

    if not validFrame then
        chatFrameId = self.availableChannels[1] and self.availableChannels[1].id or 1
    end

    self.currentChatFrame = chatFrameId
    self.lastViewedChannel = chatFrameId
    self.lastProcessedMessages = {}

    self:UpdateChannelDisplay()
    self:SwitchToChannel(chatFrameId)

    AIOS_CopyBox_MainFrame:Open()
end

-- ============================================================================
-- Live Update System
-- ============================================================================

function AIOS_CopyBox_ChatManager:HookChatFramesForLiveUpdates()
    local enabled = AIOS_CopyBoxDB and AIOS_CopyBoxDB.enableLiveUpdates
    if enabled == nil then
        enabled = AIOS_CopyBox_Config.behavior.enableLiveUpdates
    end
    if not enabled then return end

    for i = 1, NUM_CHAT_WINDOWS or 10 do
        local cf = _G["ChatFrame" .. i]
        if cf and not self.hookedChats[i] then
            hooksecurefunc(cf, "AddMessage", function(_, text, r, g, b)
                if AIOS_CopyBox_ChatManager and AIOS_CopyBox_MainFrame and
                   AIOS_CopyBox_MainFrame.frame and AIOS_CopyBox_MainFrame.frame:IsShown() and
                   AIOS_CopyBox_ChatManager.currentChatFrame == i then
                    AIOS_CopyBox_ChatManager:AppendLiveMessage(text, r, g, b)
                end
            end)
            self.hookedChats[i] = true
        end
    end
end

function AIOS_CopyBox_ChatManager:AppendLiveMessage(msg, r, g, b)
    if not self.editBox then return end
    if not msg or #msg == 0 then return end

    if msg:find("CopyBox DEBUG:", 1, true) then return end

    local processed = self:ProcessMessage(msg, r, g, b)
    if not processed then return end

    -- Timestamp
    if AIOS_CopyBoxDB and AIOS_CopyBoxDB.showTimestamps then
        local timestamp = date("%H:%M:%S")
        processed = "|cff888888[" .. timestamp .. "]|r " .. processed
    end

    local currentText = self.editBox:GetText() or ""

    local isPlaceholder = currentText == "-- Chat messages will appear here --" or
                          currentText:find("No recent messages", 1, true) or
                          currentText == ""

    if isPlaceholder then
        self.editBox:SetText(processed)
    else
        local lines = {}
        for line in currentText:gmatch("[^\r\n]+") do
            table.insert(lines, line)
        end
        table.insert(lines, processed)

        local maxLines = AIOS_CopyBox_Config.chat.maxLines
        while #lines > maxLines do
            table.remove(lines, 1)
        end

        self.editBox:SetText(table.concat(lines, "\n"))
    end

    -- Auto-scroll only if NOT locked
    if AIOS_CopyBoxDB and AIOS_CopyBoxDB.lockScroll then
        return
    end

    if AIOS_CopyBox_MainFrame and AIOS_CopyBox_MainFrame.scrollFrame then
        C_Timer.After(0, function()
            if AIOS_CopyBox_MainFrame and AIOS_CopyBox_MainFrame.scrollFrame then
                AIOS_CopyBox_MainFrame.scrollFrame:SetVerticalScroll(
                    AIOS_CopyBox_MainFrame.scrollFrame:GetVerticalScrollRange()
                )
            end
        end)
    end
end