GuildHelper = GuildHelper or {}

local addon = GuildHelper

addon.TableView = addon.TableView or {}

local function releaseChildren(frame)
    local children = { frame:GetChildren() }

    for _, child in ipairs(children) do
        child:Hide()
        child:SetParent(nil)
    end
end

local function getRowValues(rowData)
    if type(rowData) == "table" and type(rowData.values) == "table" then
        return rowData.values
    end

    return rowData
end

local function getRowColors(rowIndex, rowData)
    local isSelected = type(rowData) == "table" and rowData.selected
    local isInteractive = type(rowData) == "table" and type(rowData.onClick) == "function"
    local customBaseColor = type(rowData) == "table" and rowData.baseColor or nil
    local customBorderColor = type(rowData) == "table" and rowData.borderColor or nil
    local customSelectedBaseColor = type(rowData) == "table" and rowData.selectedBaseColor or nil
    local customSelectedBorderColor = type(rowData) == "table" and rowData.selectedBorderColor or nil

    if isSelected then
        return customSelectedBaseColor or customBaseColor or { 0.16, 0.2, 0.29, 0.98 }, customSelectedBorderColor or customBorderColor or { 0.82, 0.66, 0.24, 1 }
    end

    if customBaseColor or customBorderColor then
        return customBaseColor or { 0.06, 0.09, 0.13, 0.96 }, customBorderColor or { 0.3, 0.38, 0.48, 1 }
    end

    if rowIndex % 2 == 0 then
        return isInteractive and { 0.09, 0.12, 0.17, 0.96 } or { 0.08, 0.1, 0.14, 0.96 }, { 0.3, 0.38, 0.48, 1 }
    end

    return isInteractive and { 0.06, 0.09, 0.13, 0.96 } or { 0.05, 0.07, 0.1, 0.96 }, { 0.3, 0.38, 0.48, 1 }
end

local function buildColumnWidths(totalWidth, headers, configuredWidths)
    local widths = {}
    local remainingWidth = totalWidth
    local remainingColumns = math.max(#headers, 1)

    for index = 1, #headers do
        local requestedWidth = type(configuredWidths) == "table" and tonumber(configuredWidths[index]) or nil
        local width = requestedWidth and math.max(math.floor(requestedWidth), 24) or math.max(math.floor(remainingWidth / remainingColumns), 24)

        if index == #headers then
            width = math.max(remainingWidth, 24)
        elseif width > remainingWidth - ((remainingColumns - 1) * 24) then
            width = math.max(remainingWidth - ((remainingColumns - 1) * 24), 24)
        end

        widths[index] = width
        remainingWidth = remainingWidth - width
        remainingColumns = remainingColumns - 1
    end

    return widths
end

function addon.TableView:Render(parent, config)
    releaseChildren(parent)

    if config.headerParent and config.headerParent ~= parent then
        releaseChildren(config.headerParent)
    end

    local headers = config.headers or {}
    local rows = config.rows or {}
    local width = parent:GetWidth()
    local headerParent = config.headerParent or parent
    local headerHeight = config.headerHeight or 24
    local rowHeight = config.rowHeight or 22
    local columnWidths = buildColumnWidths(width, headers, config.columnWidths)
    local rowTopOffset = config.headerParent and config.headerParent ~= parent and 0 or headerHeight

    local headerFrame = CreateFrame("Frame", nil, headerParent)
    headerFrame:SetSize(width, headerHeight)
    headerFrame:SetPoint("TOPLEFT", headerParent, "TOPLEFT", 0, 0)

    local columnOffset = 0
    for index, title in ipairs(headers) do
        local columnWidth = columnWidths[index] or math.floor(width / math.max(#headers, 1))
        local label = headerFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
        label:SetWidth(columnWidth - 6)
        label:SetJustifyH("LEFT")
        label:SetPoint("TOPLEFT", headerFrame, "TOPLEFT", columnOffset + 4, -4)
        label:SetText(title)
        label:SetTextColor(0.88, 0.78, 0.56, 1)
        label:SetShadowOffset(1, -1)
        columnOffset = columnOffset + columnWidth
    end

    for rowIndex, rowData in ipairs(rows) do
        local rowValues = getRowValues(rowData)
        local rowFrame = CreateFrame("Frame", nil, parent, "BackdropTemplate")
        rowFrame:SetSize(width, rowHeight)
        rowFrame:SetPoint("TOPLEFT", parent, "TOPLEFT", 0, -(rowTopOffset + ((rowIndex - 1) * rowHeight)))
        rowFrame:SetBackdrop({
            bgFile = "Interface\\Buttons\\WHITE8X8",
            edgeFile = "Interface\\Buttons\\WHITE8X8",
            edgeSize = 1,
            insets = { left = 1, right = 1, top = 1, bottom = 1 },
        })

        local baseColor, borderColor = getRowColors(rowIndex, rowData)
        rowFrame:SetBackdropColor(unpack(baseColor))
        rowFrame:SetBackdropBorderColor(unpack(borderColor))

        if type(rowData) == "table" and type(rowData.onClick) == "function" then
            rowFrame:EnableMouse(true)
            rowFrame:SetScript("OnMouseUp", function()
                rowData.onClick(rowData)
            end)
            rowFrame:SetScript("OnEnter", function(frame)
                if not rowData.selected then
                    frame:SetBackdropColor(0.12, 0.16, 0.22, 0.98)
                    frame:SetBackdropBorderColor(0.72, 0.58, 0.22, 1)
                end

                if (type(rowData.tooltipText) == "string" and rowData.tooltipText ~= "") or (type(rowData.tooltipLines) == "table" and #rowData.tooltipLines > 0) then
                    GameTooltip:SetOwner(frame, "ANCHOR_RIGHT")

                    if type(rowData.tooltipTitle) == "string" and rowData.tooltipTitle ~= "" then
                        GameTooltip:SetText(rowData.tooltipTitle, 0.93, 0.84, 0.63, 1, true)
                    end

                    if type(rowData.tooltipText) == "string" and rowData.tooltipText ~= "" then
                        GameTooltip:AddLine(rowData.tooltipText, 0.82, 0.82, 0.82, true)
                    end

                    for _, line in ipairs(rowData.tooltipLines or {}) do
                        if tostring(line or "") ~= "" then
                            GameTooltip:AddLine(tostring(line), 0.82, 0.82, 0.82, true)
                        end
                    end

                    GameTooltip:Show()
                end
            end)
            rowFrame:SetScript("OnLeave", function(frame)
                local leaveBaseColor, leaveBorderColor = getRowColors(rowIndex, rowData)
                frame:SetBackdropColor(unpack(leaveBaseColor))
                frame:SetBackdropBorderColor(unpack(leaveBorderColor))
                GameTooltip:Hide()
            end)
        end

        local rowColumnOffset = 0

        for columnIndex, value in ipairs(rowValues) do
            local columnWidth = columnWidths[columnIndex] or math.floor(width / math.max(#headers, 1))
            local text = rowFrame:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
            text:SetWidth(columnWidth - 8)
            text:SetHeight(math.max(rowHeight - 8, 10))
            text:SetJustifyH("LEFT")
            if text.SetWordWrap then
                text:SetWordWrap(config.wordWrap == true)
            end
            if text.SetNonSpaceWrap then
                text:SetNonSpaceWrap(config.wordWrap == true)
            end
            if text.SetMaxLines and config.wordWrap ~= true then
                text:SetMaxLines(1)
            end
            text:SetPoint("TOPLEFT", rowFrame, "TOPLEFT", rowColumnOffset + 4, -4)
            text:SetText(tostring(value))
            if type(rowData) == "table" and rowData.selected then
                local selectedTextColor = rowData.selectedTextColor or rowData.textColor
                if type(selectedTextColor) == "table" then
                    text:SetTextColor(unpack(selectedTextColor))
                else
                    text:SetTextColor(0.98, 0.9, 0.72, 1)
                end
            else
                if type(rowData) == "table" and type(rowData.textColor) == "table" then
                    text:SetTextColor(unpack(rowData.textColor))
                else
                    text:SetTextColor(0.8, 0.79, 0.74, 1)
                end
            end
            text:SetShadowOffset(1, -1)
            rowColumnOffset = rowColumnOffset + columnWidth
        end
    end
end
