local addonName, FN = ...

FN = FN or {}
FavoriteNeighborhood = FN

local L = FN.L or {}

local optionsPanel
local rows = {}
local emptyText
local scrollFrame
local content
local rowAnchor
local headers = {}

local HEADER_TEXT_COLOR = { 1.0, 0.82, 0.25 }
local ROW_HEIGHT = 34
local ICON_SIZE = 28
local COLUMN_START_X = 52
local ROW_RIGHT_PADDING = 10
local COLUMN_LAYOUT = {
    { key = "name",    title = L["Character"], width = 150, align = "LEFT"   },
    { key = "level",   title = L["Level"],     width = 60,  align = "CENTER" },
    { key = "faction", title = L["Faction"],   width = 110, align = "CENTER" },
    { key = "realm",   title = L["Realm"],     width = 110, align = "CENTER" },
    { key = "remove",  title = L["Remove"],    width = 115, align = "CENTER" },
}

local function CalculateRowWidth()
    local width = COLUMN_START_X + ROW_RIGHT_PADDING
    for _, column in ipairs(COLUMN_LAYOUT) do
        width = width + column.width
    end
    return width
end

local ROW_WIDTH = CalculateRowWidth()

local function GetColumnOffset(columnKey)
    local x = COLUMN_START_X
    for _, column in ipairs(COLUMN_LAYOUT) do
        if column.key == columnKey then
            return x, column.width
        end
        x = x + column.width
    end
    return COLUMN_START_X, 0
end

local function FormatCharacterName(char)
    return char and char.name or "Unknown"
end

local function GetClassColorForChar(char)
    local classFile = char and char.classFile
    if classFile and C_ClassColor and C_ClassColor.GetClassColor then
        local color = C_ClassColor.GetClassColor(classFile)
        if color then
            return color.r, color.g, color.b
        end
    end
    if classFile and RAID_CLASS_COLORS and RAID_CLASS_COLORS[classFile] then
        local color = RAID_CLASS_COLORS[classFile]
        return color.r, color.g, color.b
    end
    return 1.00, 0.86, 0.35
end

local function FormatLevel(char)
    local level = tonumber(char.level)
    if not level or level <= 0 then
        return "-"
    end
    return tostring(level)
end

local function GetFactionDisplayInfo(char)
    local faction = char and char.faction
    if faction == "Alliance" then
        return FACTION_ALLIANCE, 0.20, 0.42, 0.95
    elseif faction == "Horde" then
        return FACTION_HORDE, 0.82, 0.18, 0.18
    end
    return "-", 0.55, 0.55, 0.55
end

local function ApplyFactionIcon(texture, faction)
    if not texture then return end

    texture:SetTexCoord(0, 1, 0, 1)
    texture:SetVertexColor(1, 1, 1, 1)

    if faction == "Alliance" then
        texture:SetTexture("Interface\\AddOns\\FavoriteNeighborhood\\Images\\Faction\\AllianceCustom.tga")
        texture:Show()
    elseif faction == "Horde" then
        texture:SetTexture("Interface\\AddOns\\FavoriteNeighborhood\\Images\\Faction\\HordeCustom.tga")
        texture:Show()
    else
        texture:SetTexture("Interface\\Buttons\\WHITE8X8")
        texture:SetVertexColor(0.50, 0.50, 0.50, 0.50)
        texture:Show()
    end
end

local function GetRegisteredCharacters()
    if FN.GetRegisteredCharacters then
        return FN.GetRegisteredCharacters() or {}
    end
    return {}
end

local function HideAllRows()
    for _, row in ipairs(rows) do
        row:Hide()
    end
end

local function ConfirmRemoveCharacter(char)
    if not char or not char.key then return end

    StaticPopupDialogs["FAVORITENEIGHBORHOOD_REMOVE_CHARACTER"] = StaticPopupDialogs["FAVORITENEIGHBORHOOD_REMOVE_CHARACTER"] or {
        text = L["Remove %s from the registered list?"],
        button1 = YES,
        button2 = NO,
        OnAccept = function(self, data)
            if FN.RemoveRegisteredCharacter then
                FN.RemoveRegisteredCharacter(data)
            end
            if optionsPanel and optionsPanel:IsShown() and optionsPanel.RefreshCharacterTable then
                optionsPanel:RefreshCharacterTable()
            end
        end,
        timeout = 0,
        whileDead = true,
        hideOnEscape = true,
        preferredIndex = 3,
    }

    local pretty = string.format("%s - %s", char.name or "Unknown", char.realm or "Unknown")
    StaticPopup_Show("FAVORITENEIGHBORHOOD_REMOVE_CHARACTER", pretty, nil, char.key)
end

local function CreateRow(parent, index)
    local row = CreateFrame("Button", nil, parent)
    row:SetSize(ROW_WIDTH, ROW_HEIGHT)

    row.bg = row:CreateTexture(nil, "BACKGROUND")
    row.bg:SetAllPoints()
    row.bg:SetTexture("Interface\\Buttons\\WHITE8X8")

    row.topLine = row:CreateTexture(nil, "BORDER")
    row.topLine:SetTexture("Interface\\Buttons\\WHITE8X8")
    row.topLine:SetHeight(1)
    row.topLine:SetPoint("TOPLEFT")
    row.topLine:SetPoint("TOPRIGHT")
    row.topLine:SetVertexColor(0.25, 0.45, 0.85, 0.18)

    row.icon = row:CreateTexture(nil, "OVERLAY")
    row.icon:SetSize(ICON_SIZE, ICON_SIZE)
    row.icon:SetPoint("LEFT", row, "LEFT", 6, 0)

    row.currentGlow = row:CreateTexture(nil, "BORDER")
    row.currentGlow:SetTexture("Interface\\Buttons\\WHITE8X8")
    row.currentGlow:SetPoint("TOPLEFT", row, "TOPLEFT", 0, -1)
    row.currentGlow:SetPoint("BOTTOMLEFT", row, "BOTTOMLEFT", 0, 1)
    row.currentGlow:SetWidth(2)
    row.currentGlow:SetVertexColor(1.0, 0.82, 0.25, 0.95)
    row.currentGlow:Hide()

    row.cols = {}
    for _, column in ipairs(COLUMN_LAYOUT) do
        local fs = row:CreateFontString(nil, "ARTWORK", "GameFontHighlight")
        local x = GetColumnOffset(column.key)
        fs:SetPoint("LEFT", row, "LEFT", x, 0)
        fs:SetWidth(column.width)
        fs:SetJustifyH(column.align or "LEFT")
        fs:SetJustifyV("MIDDLE")
        row.cols[column.key] = fs
    end

    row.removeButton = CreateFrame("Button", nil, row, "UIPanelButtonTemplate")
    row.removeButton:SetSize(82, 20)
    do
        local removeX, removeWidth = GetColumnOffset("remove")
        row.removeButton:SetPoint("CENTER", row, "LEFT", removeX + (removeWidth / 2), 0)
    end
    row.removeButton:SetText(L["Remove"])
    row.removeButton:SetScript("OnClick", function(self)
        ConfirmRemoveCharacter(self:GetParent().charData)
    end)

    if index % 2 == 0 then
        row.bg:SetVertexColor(0.18, 0.30, 0.55, 0.08)
    else
        row.bg:SetVertexColor(0.16, 0.24, 0.42, 0.05)
    end

    return row
end

local function EnsureRows(count)
    while #rows < count do
        local row = CreateRow(content, #rows + 1)
        if #rows == 0 then
            row:SetPoint("TOPLEFT", rowAnchor, "BOTTOMLEFT", 0, -2)
            row:SetPoint("TOPRIGHT", content, "TOPLEFT", ROW_WIDTH, 0)
        else
            row:SetPoint("TOPLEFT", rows[#rows], "BOTTOMLEFT", 0, -1)
            row:SetPoint("TOPRIGHT", rows[#rows], "BOTTOMRIGHT", 0, -1)
        end
        rows[#rows + 1] = row
    end
end

local function RefreshCharacterTable()
    if not optionsPanel or not content then return end

    local chars = GetRegisteredCharacters()
    local playerKey = FN.PlayerKey and FN.PlayerKey() or nil
    HideAllRows()

    if #chars == 0 then
        emptyText:Show()
        content:SetHeight(48)
        return
    end

    emptyText:Hide()
    EnsureRows(#chars)

    for i, char in ipairs(chars) do
        local row = rows[i]
        local factionText, fr, fg, fb = GetFactionDisplayInfo(char)
        local isCurrent = playerKey and char.key == playerKey

        row.charData = char
        local nr, ng, nb = GetClassColorForChar(char)
        row.cols.name:SetText(FormatCharacterName(char))
        row.cols.name:SetTextColor(nr, ng, nb)
        row.cols.level:SetText(FormatLevel(char))
        row.cols.faction:SetText(factionText)
        row.cols.faction:SetTextColor(fr, fg, fb)
        row.cols.realm:SetText(char.realm or "Unknown")
        row.cols.level:SetTextColor(0.95, 0.95, 0.95)
        row.cols.realm:SetTextColor(0.95, 0.95, 0.95)
        row.cols.remove:SetText("")

        if isCurrent then
            row.currentGlow:Show()
            row.bg:SetVertexColor(fr, fg, fb, 0.22)
        else
            row.currentGlow:Hide()
            if char.faction == "Alliance" then
                row.bg:SetVertexColor(0.20, 0.38, 0.90, i % 2 == 0 and 0.15 or 0.11)
            elseif char.faction == "Horde" then
                row.bg:SetVertexColor(0.80, 0.18, 0.18, i % 2 == 0 and 0.15 or 0.11)
            else
                row.bg:SetVertexColor(1, 1, 1, i % 2 == 0 and 0.035 or 0.018)
            end
        end

        ApplyFactionIcon(row.icon, char.faction)
        row:Show()
    end

    local height = 28 + (#chars * (ROW_HEIGHT + 1))
    content:SetHeight(math.max(height, 48))
end

local function CreateHeaders(parent, anchor)
    for _, column in ipairs(COLUMN_LAYOUT) do
        local fs = parent:CreateFontString(nil, "ARTWORK", "GameFontNormal")
        local x = GetColumnOffset(column.key)
        fs:SetPoint("TOPLEFT", anchor, "BOTTOMLEFT", x, -2)
        fs:SetWidth(column.width)
        fs:SetJustifyH(column.align or "LEFT")
        fs:SetText(column.title)
        fs:SetTextColor(unpack(HEADER_TEXT_COLOR))
        headers[#headers + 1] = fs
    end
end

local function CreateOptionsPanel()
    if optionsPanel then return end

    optionsPanel = CreateFrame("Frame")
    optionsPanel.name = L["FavoriteNeighborhood"]

    local logo = optionsPanel:CreateTexture(nil, "ARTWORK")
    logo:SetTexture("Interface\\AddOns\\FavoriteNeighborhood\\Images\\Logo\\FN_Logo.tga")
    logo:SetSize(440, 152)
    logo:SetPoint("TOP", optionsPanel, "TOP", -40, 10)

    local subtitle = optionsPanel:CreateFontString(nil, "ARTWORK", "GameFontHighlight")
    subtitle:SetPoint("TOPLEFT", optionsPanel, "TOPLEFT", 16, -110)
    subtitle:SetText(L["Registered Characters"])

    local info = optionsPanel:CreateFontString(nil, "ARTWORK", "GameFontDisableSmall")
    info:SetPoint("TOPLEFT", subtitle, "BOTTOMLEFT", 0, -6)
    info:SetWidth(ROW_WIDTH - 20)
    info:SetJustifyH("LEFT")
    info:SetWordWrap(true)
    info:SetText(L["Saved characters that logged into the addon. The current character stays at the top, followed by the most recently played ones."])

    local divider = optionsPanel:CreateTexture(nil, "BORDER")
    divider:SetTexture("Interface\\Buttons\\WHITE8X8")
    divider:SetPoint("TOPLEFT", info, "BOTTOMLEFT", 0, -10)
    divider:SetWidth(ROW_WIDTH)
    divider:SetHeight(1)
    divider:SetVertexColor(0.20, 0.45, 0.90, 0.40)

    CreateHeaders(optionsPanel, divider)

    local headerDivider = optionsPanel:CreateTexture(nil, "BORDER")
    headerDivider:SetTexture("Interface\\Buttons\\WHITE8X8")
    headerDivider:SetPoint("TOPLEFT", divider, "BOTTOMLEFT", 0, -22)
    headerDivider:SetWidth(ROW_WIDTH)
    headerDivider:SetHeight(1)
    headerDivider:SetVertexColor(0.20, 0.45, 0.90, 0.28)

    scrollFrame = CreateFrame("ScrollFrame", nil, optionsPanel, "UIPanelScrollFrameTemplate")
    scrollFrame:SetPoint("TOPLEFT", headerDivider, "BOTTOMLEFT", 0, -4)
    scrollFrame:SetWidth(ROW_WIDTH + 18)
    scrollFrame:SetPoint("BOTTOMLEFT", optionsPanel, "BOTTOMLEFT", 16, 20)

    content = CreateFrame("Frame", nil, scrollFrame)
    content:SetSize(ROW_WIDTH, 48)
    scrollFrame:SetScrollChild(content)

    rowAnchor = CreateFrame("Frame", nil, content)
    rowAnchor:SetPoint("TOPLEFT", content, "TOPLEFT", 0, 0)
    rowAnchor:SetSize(1, 1)

    emptyText = content:CreateFontString(nil, "ARTWORK", "GameFontDisable")
    emptyText:SetPoint("TOPLEFT", content, "TOPLEFT", 10, -10)
    emptyText:SetJustifyH("LEFT")
    emptyText:SetText("No registered characters yet.")

    optionsPanel.RefreshCharacterTable = RefreshCharacterTable
    optionsPanel:SetScript("OnShow", RefreshCharacterTable)

    if Settings and Settings.RegisterCanvasLayoutCategory then
        local category = Settings.RegisterCanvasLayoutCategory(optionsPanel, L["FavoriteNeighborhood"])
        Settings.RegisterAddOnCategory(category)
    elseif InterfaceOptions_AddCategory then
        InterfaceOptions_AddCategory(optionsPanel)
    end
end

local frame = CreateFrame("Frame")
frame:RegisterEvent("PLAYER_LOGIN")
frame:RegisterEvent("PLAYER_ENTERING_WORLD")
frame:SetScript("OnEvent", function(self, event)
    if event == "PLAYER_LOGIN" then
        if FN.EnsureDB then FN.EnsureDB() end
        if FN.ScanKnownCharacters then FN.ScanKnownCharacters() end
        CreateOptionsPanel()
    else
        if FN.ScanKnownCharacters then FN.ScanKnownCharacters() end
        if optionsPanel and optionsPanel.RefreshCharacterTable then
            optionsPanel:RefreshCharacterTable()
        end
    end
end)
