local addonName, RF = ...
local T

-- State
local selectedTeamID = nil
local teamSearchText = ""
local assignSearchText = ""
local assignClassFilter = nil
local assignRoleDefault = nil  -- initialized from settings on tab init

-------------------------------------------------------------------------------
-- Role icon atlas names (LFG icons)
-------------------------------------------------------------------------------
local ROLE_ICONS = {
    TANK   = "roleicon-tank",
    HEALER = "roleicon-healer",
    DPS    = "roleicon-dps",
    FLEX   = "roleicon-dps",
}

local ROLE_ORDER = { TANK = 1, HEALER = 2, DPS = 3, FLEX = 4 }

-------------------------------------------------------------------------------
-- Infer team role from a player's assigned tags
-------------------------------------------------------------------------------
local TAG_TO_ROLE = {
    tank = "TANK",
    healer = "HEALER",
    heals = "HEALER",
    healing = "HEALER",
    dps = "DPS",
    damage = "DPS",
    flex = "FLEX",
}

local function InferRoleFromTags(memberName)
    local guildDB = RF:GetGuildDB()
    if not guildDB or not guildDB.tags or not guildDB.tags[memberName] then return nil end

    for _, tag in ipairs(guildDB.tags[memberName]) do
        local match = TAG_TO_ROLE[tag.label:lower()]
        if match then return match end
    end
    return nil
end

local function GetRoleForMember(memberName)
    return InferRoleFromTags(memberName) or assignRoleDefault or "DPS"
end

-------------------------------------------------------------------------------
-- Create Team Dialog
-------------------------------------------------------------------------------
local function ShowCreateTeamDialog()
    local dialog = RF:CreateStyledFrame("RosterForgeCreateTeam", UIParent, 320, 240, {
        title = "Create Team",
        closable = true,
        strata = "DIALOG",
    })
    dialog:SetPoint("CENTER")
    dialog:SetFrameLevel(100)
    dialog:Show()

    -- Name
    local nameLabel = RF:CreateLabel(dialog, "Team Name:", RF.FONT_SIZES.normal, "textSecondary")
    nameLabel:SetPoint("TOPLEFT", 16, -40)

    local nameEB = CreateFrame("EditBox", nil, dialog, "BackdropTemplate")
    nameEB:SetPoint("TOPLEFT", 16, -56)
    nameEB:SetPoint("RIGHT", -16, 0)
    nameEB:SetHeight(26)
    nameEB:SetFontObject("ChatFontNormal")
    nameEB:SetFont(nameEB:GetFont(), RF.FONT_SIZES.normal, "")
    nameEB:SetTextColor(unpack(T.textPrimary))
    nameEB:SetAutoFocus(true)
    nameEB:SetBackdrop({ bgFile = "Interface\\Buttons\\WHITE8x8", edgeFile = "Interface\\Buttons\\WHITE8x8", edgeSize = 1 })
    nameEB:SetBackdropColor(0.10, 0.10, 0.12, 1)
    nameEB:SetBackdropBorderColor(unpack(T.border))
    nameEB:SetTextInsets(6, 6, 0, 0)

    -- Type dropdown
    local typeLabel = RF:CreateLabel(dialog, "Team Type:", RF.FONT_SIZES.normal, "textSecondary")
    typeLabel:SetPoint("TOPLEFT", 16, -90)

    -- Custom type name (shown when "Custom" selected)
    local customTypeLabel = RF:CreateLabel(dialog, "Custom Type Name:", RF.FONT_SIZES.normal, "textSecondary")
    customTypeLabel:SetPoint("TOPLEFT", 16, -130)
    customTypeLabel:Hide()

    local customTypeEB = CreateFrame("EditBox", nil, dialog, "BackdropTemplate")
    customTypeEB:SetPoint("TOPLEFT", 16, -146)
    customTypeEB:SetPoint("RIGHT", -16, 0)
    customTypeEB:SetHeight(26)
    customTypeEB:SetFontObject("ChatFontNormal")
    customTypeEB:SetFont(customTypeEB:GetFont(), RF.FONT_SIZES.normal, "")
    customTypeEB:SetTextColor(unpack(T.textPrimary))
    customTypeEB:SetAutoFocus(false)
    customTypeEB:SetMaxLetters(30)
    customTypeEB:SetBackdrop({ bgFile = "Interface\\Buttons\\WHITE8x8", edgeFile = "Interface\\Buttons\\WHITE8x8", edgeSize = 1 })
    customTypeEB:SetBackdropColor(0.10, 0.10, 0.12, 1)
    customTypeEB:SetBackdropBorderColor(unpack(T.border))
    customTypeEB:SetTextInsets(6, 6, 0, 0)
    customTypeEB:Hide()

    -- Max Size editbox
    local sizeLabel = RF:CreateLabel(dialog, "Max Players:", RF.FONT_SIZES.normal, "textSecondary")
    sizeLabel:SetPoint("TOPLEFT", 16, -130)

    local sizeEB = CreateFrame("EditBox", nil, dialog, "BackdropTemplate")
    sizeEB:SetPoint("TOPLEFT", 16, -146)
    sizeEB:SetSize(60, 26)
    sizeEB:SetFontObject("ChatFontNormal")
    sizeEB:SetFont(sizeEB:GetFont(), RF.FONT_SIZES.normal, "")
    sizeEB:SetTextColor(unpack(T.textPrimary))
    sizeEB:SetAutoFocus(false)
    sizeEB:SetNumeric(true)
    sizeEB:SetMaxLetters(3)
    sizeEB:SetBackdrop({ bgFile = "Interface\\Buttons\\WHITE8x8", edgeFile = "Interface\\Buttons\\WHITE8x8", edgeSize = 1 })
    sizeEB:SetBackdropColor(0.10, 0.10, 0.12, 1)
    sizeEB:SetBackdropBorderColor(unpack(T.border))
    sizeEB:SetTextInsets(6, 6, 0, 0)
    sizeEB:SetText("20")

    local function UpdateCustomVisibility(value)
        if value == "custom" then
            customTypeLabel:Show()
            customTypeEB:Show()
            sizeLabel:SetPoint("TOPLEFT", 16, -176)
            sizeEB:SetPoint("TOPLEFT", 16, -192)
            dialog:SetHeight(286)
        else
            customTypeLabel:Hide()
            customTypeEB:Hide()
            sizeLabel:SetPoint("TOPLEFT", 16, -130)
            sizeEB:SetPoint("TOPLEFT", 16, -146)
            dialog:SetHeight(240)
        end
    end

    local typeItems = {}
    for _, tt in ipairs(RF.TEAM_TYPES) do
        tinsert(typeItems, { label = tt.label .. " (" .. tt.maxSize .. ")", value = tt.key })
    end
    local defType = RF.charDB and RF.charDB.teamDefaultType or "raid"
    local defTypeLabel = "Mythic Raid (20)"
    local defMaxSize = 20
    for _, tt in ipairs(RF.TEAM_TYPES) do
        if tt.key == defType then
            defTypeLabel = tt.label .. " (" .. tt.maxSize .. ")"
            defMaxSize = tt.maxSize
            break
        end
    end
    sizeEB:SetText(tostring(defMaxSize))
    UpdateCustomVisibility(defType)
    local typeDropdown = RF:CreateDropdown(dialog, {
        width = 200,
        defaultText = defTypeLabel,
        defaultValue = defType,
        items = typeItems,
        onChanged = function(value)
            UpdateCustomVisibility(value)
            -- Auto-fill max size from type
            for _, tt in ipairs(RF.TEAM_TYPES) do
                if tt.key == value then
                    sizeEB:SetText(tostring(tt.maxSize))
                    break
                end
            end
        end,
    })
    typeDropdown:SetPoint("TOPLEFT", 16, -106)

    -- Buttons
    local createBtn = RF:CreateButton(dialog, "Create", 100, 28, "accent")
    createBtn:SetPoint("BOTTOMRIGHT", -16, 12)
    createBtn:SetScript("OnClick", function()
        local name = nameEB:GetText():trim()
        if name == "" then return end
        local teamType = typeDropdown:GetValue() or "raid"
        local maxSize = tonumber(sizeEB:GetText()) or 25
        if maxSize < 1 then maxSize = 1 end
        if maxSize > 100 then maxSize = 100 end
        local teamID = RF:CreateTeam(name, teamType)
        if teamID then
            local team = RF:GetTeam(teamID)
            if team then
                team.maxSize = maxSize
                -- Store custom type label
                if teamType == "custom" then
                    local customName = customTypeEB:GetText():trim()
                    if customName ~= "" then
                        team.customTypeLabel = customName
                    end
                end
            end
            selectedTeamID = teamID
            RF:FireCallbacks("TEAMS_CHANGED")
        end
        dialog:Hide()
    end)

    local cancelBtn = RF:CreateButton(dialog, "Cancel", 80, 28)
    cancelBtn:SetPoint("RIGHT", createBtn, "LEFT", -8, 0)
    cancelBtn:SetScript("OnClick", function() dialog:Hide() end)

    nameEB:SetScript("OnEnterPressed", function() createBtn:Click() end)
    nameEB:SetScript("OnEscapePressed", function() dialog:Hide() end)
    sizeEB:SetScript("OnEnterPressed", function() createBtn:Click() end)
    sizeEB:SetScript("OnEscapePressed", function() dialog:Hide() end)
end

-------------------------------------------------------------------------------
-- Rename Dialog
-------------------------------------------------------------------------------
local function ShowRenameDialog(teamID)
    local team = RF:GetTeam(teamID)
    if not team then return end

    local dialog = RF:CreateStyledFrame("RosterForgeRenameTeam", UIParent, 300, 130, {
        title = "Rename Team",
        closable = true,
        strata = "DIALOG",
    })
    dialog:SetPoint("CENTER")
    dialog:SetFrameLevel(100)
    dialog:Show()

    local nameEB = CreateFrame("EditBox", nil, dialog, "BackdropTemplate")
    nameEB:SetPoint("TOPLEFT", 16, -40)
    nameEB:SetPoint("RIGHT", -16, 0)
    nameEB:SetHeight(26)
    nameEB:SetFontObject("ChatFontNormal")
    nameEB:SetFont(nameEB:GetFont(), RF.FONT_SIZES.normal, "")
    nameEB:SetTextColor(unpack(T.textPrimary))
    nameEB:SetAutoFocus(true)
    nameEB:SetText(team.name)
    nameEB:HighlightText()
    nameEB:SetBackdrop({ bgFile = "Interface\\Buttons\\WHITE8x8", edgeFile = "Interface\\Buttons\\WHITE8x8", edgeSize = 1 })
    nameEB:SetBackdropColor(0.10, 0.10, 0.12, 1)
    nameEB:SetBackdropBorderColor(unpack(T.border))
    nameEB:SetTextInsets(6, 6, 0, 0)

    local saveBtn = RF:CreateButton(dialog, "Save", 80, 28, "accent")
    saveBtn:SetPoint("BOTTOMRIGHT", -16, 12)
    saveBtn:SetScript("OnClick", function()
        local name = nameEB:GetText():trim()
        if name ~= "" then
            RF:RenameTeam(teamID, name)
        end
        dialog:Hide()
    end)

    nameEB:SetScript("OnEnterPressed", function() saveBtn:Click() end)
    nameEB:SetScript("OnEscapePressed", function() dialog:Hide() end)
end

-------------------------------------------------------------------------------
-- Max Size Dialog
-------------------------------------------------------------------------------
local function ShowMaxSizeDialog(teamID)
    local team = RF:GetTeam(teamID)
    if not team then return end

    local dialog = RF:CreateStyledFrame("RosterForgeMaxSize", UIParent, 260, 130, {
        title = "Max Players",
        closable = true,
        strata = "DIALOG",
    })
    dialog:SetPoint("CENTER")
    dialog:SetFrameLevel(100)
    dialog:Show()

    local sizeEB = CreateFrame("EditBox", nil, dialog, "BackdropTemplate")
    sizeEB:SetPoint("TOPLEFT", 16, -40)
    sizeEB:SetSize(60, 26)
    sizeEB:SetFontObject("ChatFontNormal")
    sizeEB:SetFont(sizeEB:GetFont(), RF.FONT_SIZES.normal, "")
    sizeEB:SetTextColor(unpack(T.textPrimary))
    sizeEB:SetAutoFocus(true)
    sizeEB:SetNumeric(true)
    sizeEB:SetMaxLetters(3)
    sizeEB:SetText(tostring(team.maxSize))
    sizeEB:HighlightText()
    sizeEB:SetBackdrop({ bgFile = "Interface\\Buttons\\WHITE8x8", edgeFile = "Interface\\Buttons\\WHITE8x8", edgeSize = 1 })
    sizeEB:SetBackdropColor(0.10, 0.10, 0.12, 1)
    sizeEB:SetBackdropBorderColor(unpack(T.border))
    sizeEB:SetTextInsets(6, 6, 0, 0)

    local hint = RF:CreateLabel(dialog, "players (1-100)", RF.FONT_SIZES.small, "textMuted")
    hint:SetPoint("LEFT", sizeEB, "RIGHT", 8, 0)

    local saveBtn = RF:CreateButton(dialog, "Save", 80, 28, "accent")
    saveBtn:SetPoint("BOTTOMRIGHT", -16, 12)
    saveBtn:SetScript("OnClick", function()
        local val = tonumber(sizeEB:GetText()) or team.maxSize
        if val < 1 then val = 1 end
        if val > 100 then val = 100 end
        team.maxSize = val
        team.updatedAt = time()
        local guildDB = RF:GetGuildDB()
        if guildDB then guildDB.teamTimestamps[teamID] = team.updatedAt end
        RF:FireCallbacks("TEAMS_CHANGED")
        dialog:Hide()
    end)

    sizeEB:SetScript("OnEnterPressed", function() saveBtn:Click() end)
    sizeEB:SetScript("OnEscapePressed", function() dialog:Hide() end)
end

-------------------------------------------------------------------------------
-- Composition Bar
-------------------------------------------------------------------------------
local function CreateCompositionBar(parent)
    local bar = CreateFrame("Frame", nil, parent, "BackdropTemplate")
    bar:SetHeight(18)
    bar:SetBackdrop({ bgFile = "Interface\\Buttons\\WHITE8x8" })
    bar:SetBackdropColor(0.15, 0.15, 0.17, 1)

    bar.segments = {}
    local roles = { "TANK", "HEALER", "DPS", "FLEX" }
    for _, role in ipairs(roles) do
        local seg = bar:CreateTexture(nil, "ARTWORK")
        seg:SetHeight(18)
        seg:SetColorTexture(unpack(RF.TEAM_ROLE_COLORS[role]))
        seg:Hide()
        bar.segments[role] = seg
    end

    -- Pills below
    bar.pills = {}
    local pillFrame = CreateFrame("Frame", nil, parent)
    pillFrame:SetHeight(16)
    bar.pillFrame = pillFrame

    for i, role in ipairs(roles) do
        local pill = RF:CreateLabel(pillFrame, "", RF.FONT_SIZES.small)
        pill:SetTextColor(unpack(RF.TEAM_ROLE_COLORS[role]))
        if i == 1 then
            pill:SetPoint("LEFT", 0, 0)
        else
            pill:SetPoint("LEFT", bar.pills[roles[i-1]], "RIGHT", 12, 0)
        end
        bar.pills[role] = pill
    end

    function bar:Update(comp)
        if not comp or comp.maxSize == 0 then return end
        local barWidth = bar:GetWidth()
        if barWidth < 10 then barWidth = 200 end

        local roles = { "TANK", "HEALER", "DPS", "FLEX" }
        local divisor = math.max(comp.maxSize, comp.total)
        local x = 0
        for _, role in ipairs(roles) do
            local count = comp[role] or 0
            local seg = bar.segments[role]
            if count > 0 then
                local w = math.max(2, (count / divisor) * barWidth)
                seg:ClearAllPoints()
                seg:SetPoint("LEFT", bar, "LEFT", x, 0)
                seg:SetWidth(w)
                seg:Show()
                x = x + w
            else
                seg:Hide()
            end
            bar.pills[role]:SetText(role:sub(1,1) .. ": " .. count)
        end
    end

    return bar
end

-------------------------------------------------------------------------------
-- Init Teams Tab
-------------------------------------------------------------------------------
function RF:InitTeamsTab(parent)
    T = RF.Theme
    assignRoleDefault = RF.charDB and RF.charDB.teamDefaultRole or "DPS"

    ---------------------------------------------------------------------------
    -- Left Panel — Team List (220px)
    ---------------------------------------------------------------------------
    local leftPanel = CreateFrame("Frame", nil, parent, "BackdropTemplate")
    leftPanel:SetWidth(220)
    leftPanel:SetPoint("TOPLEFT", 0, 0)
    leftPanel:SetPoint("BOTTOMLEFT", 0, 2)
    leftPanel:SetBackdrop({ bgFile = "Interface\\Buttons\\WHITE8x8", edgeFile = "Interface\\Buttons\\WHITE8x8", edgeSize = 1 })
    leftPanel:SetBackdropColor(unpack(T.bgSecondary))
    leftPanel:SetBackdropBorderColor(unpack(T.border))

    -- New Team button
    local newTeamBtn = RF:CreateButton(leftPanel, "+ New Team", 196, 26, "accent")
    newTeamBtn:SetPoint("TOPLEFT", 12, -8)
    newTeamBtn:SetScript("OnClick", function() ShowCreateTeamDialog() end)

    -- Team search
    local teamSearch = RF:CreateSearchBar(leftPanel, {
        width = 196,
        placeholder = "Search teams...",
        onTextChanged = function(text)
            teamSearchText = text
            RF:FireCallbacks("TEAMS_CHANGED")
        end,
    })
    teamSearch:SetPoint("TOPLEFT", 12, -40)

    -- Team list
    local teamList = RF:CreateScrollList(leftPanel, {
        rowHeight = 36,
        createRow = function(p, i)
            local row = CreateFrame("Button", nil, p)
            row:SetHeight(36)

            row.bg = row:CreateTexture(nil, "BACKGROUND")
            row.bg:SetAllPoints()

            -- Color accent bar on left
            row.accent = row:CreateTexture(nil, "ARTWORK")
            row.accent:SetWidth(3)
            row.accent:SetPoint("TOPLEFT", 0, 0)
            row.accent:SetPoint("BOTTOMLEFT", 0, 0)
            row.accent:SetColorTexture(unpack(T.accent))
            row.accent:Hide()

            row.lockIcon = row:CreateTexture(nil, "OVERLAY")
            row.lockIcon:SetSize(12, 12)
            row.lockIcon:SetPoint("TOPLEFT", 10, -6)
            row.lockIcon:SetAtlas("GM-ratingIcon-lock")
            row.lockIcon:Hide()

            row.nameText = row:CreateFontString(nil, "OVERLAY", "GameFontNormal")
            row.nameText:SetFont(row.nameText:GetFont(), RF.FONT_SIZES.normal, "")
            row.nameText:SetPoint("TOPLEFT", 10, -4)
            row.nameText:SetPoint("RIGHT", -8, 0)
            row.nameText:SetJustifyH("LEFT")
            row.nameText:SetTextColor(unpack(T.textPrimary))

            row.infoText = row:CreateFontString(nil, "OVERLAY", "GameFontNormal")
            row.infoText:SetFont(row.infoText:GetFont(), RF.FONT_SIZES.small, "")
            row.infoText:SetPoint("BOTTOMLEFT", 10, 4)
            row.infoText:SetPoint("RIGHT", -8, 0)
            row.infoText:SetJustifyH("LEFT")
            row.infoText:SetTextColor(unpack(T.textMuted))

            return row
        end,
        updateRow = function(row, data)
            if not data then return end
            local isLocked = data.team.officerOnly
            row.lockIcon:SetShown(isLocked)
            local nameOffset = isLocked and 24 or 10
            row.nameText:SetPoint("TOPLEFT", nameOffset, -4)
            row.nameText:SetText(data.team.name)
            row.infoText:SetPoint("BOTTOMLEFT", nameOffset, 4)
            local comp = RF:GetTeamComposition(data.id)
            local typeLabel = data.team.customTypeLabel or data.team.teamType
            if not data.team.customTypeLabel then
                for _, tt in ipairs(RF.TEAM_TYPES) do
                    if tt.key == data.team.teamType then typeLabel = tt.label; break end
                end
            end
            row.infoText:SetText(format("%s  |cFF4ADE80%d|r/%d", typeLabel, comp.online, comp.total))

            local isSelected = data.id == selectedTeamID
            row.accent:SetShown(isSelected)
            if isSelected then
                row.bg:SetColorTexture(T.accent[1], T.accent[2], T.accent[3], 0.15)
            else
                row.bg:SetColorTexture(0, 0, 0, 0)
            end
        end,
        onRowClick = function(row, data, button)
            if not data then return end
            if button == "RightButton" then
                local canEdit = RF:CanEditTeam(data.id)
                local isOfficer = RF:IsOfficer()
                local menuItems = {
                    { text = data.team.name, isTitle = true },
                }
                if canEdit then
                    tinsert(menuItems, { text = "Rename", func = function()
                        C_Timer.After(0, function() ShowRenameDialog(data.id) end)
                    end })
                    tinsert(menuItems, { text = "Max Players (" .. data.team.maxSize .. ")", func = function()
                        C_Timer.After(0, function() ShowMaxSizeDialog(data.id) end)
                    end })
                end
                tinsert(menuItems, { text = "Duplicate", func = function()
                    C_Timer.After(0, function()
                        local newID = RF:DuplicateTeam(data.id)
                        if newID then selectedTeamID = newID end
                    end)
                end })
                tinsert(menuItems, { text = "Export Roster", func = function()
                    C_Timer.After(0, function()
                        local text = RF:ExportTeamRoster(data.id)
                        RF:ShowCopyPopup(text)
                    end)
                end })
                if isOfficer then
                    tinsert(menuItems, { separator = true })
                    local lockLabel = data.team.officerOnly and "Unlock (Remove Officer Only)" or "Lock (Officer Only)"
                    tinsert(menuItems, { text = lockLabel, func = function()
                        C_Timer.After(0, function()
                            RF:SetTeamOfficerOnly(data.id, not data.team.officerOnly)
                        end)
                    end })
                end
                if canEdit then
                    tinsert(menuItems, { separator = true })
                    tinsert(menuItems, { text = "Delete", color = T.danger, func = function()
                        C_Timer.After(0, function()
                            RF:ShowConfirmDialog("Delete Team",
                                "Are you sure you want to delete \"" .. data.team.name .. "\"?",
                                function()
                                    RF:DeleteTeam(data.id)
                                    if selectedTeamID == data.id then selectedTeamID = nil end
                                end)
                        end)
                    end })
                end
                RF:ShowContextMenu(row, menuItems)
                return
            end
            selectedTeamID = data.id
            RF:FireCallbacks("TEAMS_CHANGED")
        end,
        onRowEnter = function(row, data)
            if not data then return end
            if data.id ~= selectedTeamID then
                row.bg:SetColorTexture(1, 1, 1, 0.04)
            end
        end,
        onRowLeave = function(row, data)
            if not data then return end
            if data.id ~= selectedTeamID then
                row.bg:SetColorTexture(0, 0, 0, 0)
            end
        end,
    })
    teamList:SetPoint("TOPLEFT", teamSearch, "BOTTOMLEFT", -12, -6)
    teamList:SetPoint("BOTTOMRIGHT", leftPanel, "BOTTOMRIGHT", 0, 0)

    ---------------------------------------------------------------------------
    -- Right Panel — Assignment Panel (260px)
    ---------------------------------------------------------------------------
    local rightPanel = CreateFrame("Frame", nil, parent, "BackdropTemplate")
    rightPanel:SetWidth(260)
    rightPanel:SetPoint("TOPRIGHT", 0, 0)
    rightPanel:SetPoint("BOTTOMRIGHT", 0, 2)
    rightPanel:SetBackdrop({ bgFile = "Interface\\Buttons\\WHITE8x8", edgeFile = "Interface\\Buttons\\WHITE8x8", edgeSize = 1 })
    rightPanel:SetBackdropColor(unpack(T.bgSecondary))
    rightPanel:SetBackdropBorderColor(unpack(T.border))

    local assignHeader = RF:CreateLabel(rightPanel, "Add Members", RF.FONT_SIZES.medium, "textPrimary")
    assignHeader:SetPoint("TOPLEFT", 12, -8)

    local assignLocked = RF:CreateLabel(rightPanel, "Officer-only team (view only)", RF.FONT_SIZES.small, "textMuted")
    assignLocked:SetPoint("CENTER", 0, 0)
    assignLocked:SetJustifyH("CENTER")
    assignLocked:Hide()

    local assignSearch = RF:CreateSearchBar(rightPanel, {
        width = 236,
        placeholder = "Search roster...",
        onTextChanged = function(text)
            assignSearchText = text
            RF:FireCallbacks("TEAMS_CHANGED")
        end,
    })
    assignSearch:SetPoint("TOPLEFT", 12, -28)

    -- Class filter
    local classItems = { { label = "All Classes", value = nil } }
    for _, cls in ipairs(RF.ALL_CLASSES) do
        local cc = RF:GetClassColor(cls)
        tinsert(classItems, { label = format("|cFF%02x%02x%02x%s|r", cc.r*255, cc.g*255, cc.b*255, cls:sub(1,1) .. cls:sub(2):lower()), value = cls })
    end
    local classDropdown = RF:CreateDropdown(rightPanel, {
        width = 130,
        defaultText = "All Classes",
        items = classItems,
        onChanged = function(value)
            assignClassFilter = value
            RF:FireCallbacks("TEAMS_CHANGED")
        end,
    })
    classDropdown:SetPoint("TOPLEFT", 12, -60)

    -- Role default dropdown
    local roleItems = {}
    for _, r in ipairs(RF.TEAM_ROLES) do
        tinsert(roleItems, { label = r.label, value = r.key })
    end
    local defRoleLabel = "DPS"
    for _, r in ipairs(RF.TEAM_ROLES) do
        if r.key == assignRoleDefault then defRoleLabel = r.label; break end
    end
    local roleDropdown = RF:CreateDropdown(rightPanel, {
        width = 95,
        defaultText = defRoleLabel,
        defaultValue = assignRoleDefault,
        items = roleItems,
        onChanged = function(value)
            assignRoleDefault = value or "DPS"
        end,
    })
    roleDropdown:SetPoint("LEFT", classDropdown, "RIGHT", 6, 0)

    -- Unassigned members list
    local assignList = RF:CreateScrollList(rightPanel, {
        rowHeight = 24,
        createRow = function(p, i)
            local row = CreateFrame("Button", nil, p)
            row:SetHeight(24)

            row.bg = row:CreateTexture(nil, "BACKGROUND")
            row.bg:SetAllPoints()

            row.nameText = row:CreateFontString(nil, "OVERLAY", "GameFontNormal")
            row.nameText:SetFont(row.nameText:GetFont(), RF.FONT_SIZES.small, "")
            row.nameText:SetPoint("LEFT", 8, 0)
            row.nameText:SetPoint("RIGHT", -32, 0)
            row.nameText:SetJustifyH("LEFT")

            -- Online dot
            row.onlineDot = row:CreateTexture(nil, "OVERLAY")
            row.onlineDot:SetSize(6, 6)
            row.onlineDot:SetPoint("LEFT", 2, 0)
            row.onlineDot:SetColorTexture(0.3, 0.9, 0.3)

            -- Add button
            row.addBtn = CreateFrame("Button", nil, row)
            row.addBtn:SetSize(20, 20)
            row.addBtn:SetPoint("RIGHT", -4, 0)
            row.addBtn.label = row.addBtn:CreateFontString(nil, "OVERLAY", "GameFontNormal")
            row.addBtn.label:SetAllPoints()
            row.addBtn.label:SetText("|cFF4ADE80+|r")
            row.addBtn.label:SetFont(row.addBtn.label:GetFont(), RF.FONT_SIZES.medium, "")

            return row
        end,
        updateRow = function(row, data)
            if not data then return end
            row.nameText:SetText(RF:GetClassColoredName(data.name, data.classFile))
            row.onlineDot:SetShown(data.isOnline)
            row.nameText:SetPoint("LEFT", data.isOnline and 12 or 8, 0)
            row.bg:SetColorTexture(0, 0, 0, 0)

            row.addBtn:SetScript("OnClick", function()
                if selectedTeamID and RF:CanEditTeam(selectedTeamID) then
                    RF:AddTeamMember(selectedTeamID, data.name, GetRoleForMember(data.name))
                end
            end)
        end,
        onRowClick = function(row, data, button)
            -- Double-click add
            if not data or not selectedTeamID then return end
            if not RF:CanEditTeam(selectedTeamID) then return end
            RF:AddTeamMember(selectedTeamID, data.name, GetRoleForMember(data.name))
        end,
        onRowEnter = function(row, data)
            if not data then return end
            row.bg:SetColorTexture(1, 1, 1, 0.04)
            GameTooltip:SetOwner(row, "ANCHOR_LEFT")
            GameTooltip:AddLine(data.name, 1, 1, 1)
            if data.classDisplayName then GameTooltip:AddLine(format("Level %d %s", data.level or 0, data.classDisplayName), 0.7, 0.7, 0.7) end
            local teams = RF:GetMemberTeams(data.name)
            if #teams > 0 then
                GameTooltip:AddLine(" ")
                GameTooltip:AddLine("Teams:", 1, 0.82, 0)
                for _, t in ipairs(teams) do
                    GameTooltip:AddLine("  " .. t.teamName .. " (" .. t.role .. ")", 0.7, 0.7, 0.7)
                end
            end
            GameTooltip:Show()
        end,
        onRowLeave = function(row)
            if row then row.bg:SetColorTexture(0, 0, 0, 0) end
            GameTooltip:Hide()
        end,
    })
    assignList:SetPoint("TOPLEFT", rightPanel, "TOPLEFT", 0, -88)
    assignList:SetPoint("BOTTOMRIGHT", rightPanel, "BOTTOMRIGHT", 0, 0)

    -- Empty state for right panel
    local assignEmpty = RF:CreateLabel(rightPanel, "Select a team to\nadd members", RF.FONT_SIZES.normal, "textMuted")
    assignEmpty:SetPoint("CENTER", 0, 0)
    assignEmpty:SetJustifyH("CENTER")

    ---------------------------------------------------------------------------
    -- Center Panel — Team Roster (flexible width)
    ---------------------------------------------------------------------------
    local centerPanel = CreateFrame("Frame", nil, parent)
    centerPanel:SetPoint("TOPLEFT", leftPanel, "TOPRIGHT", 0, 0)
    centerPanel:SetPoint("BOTTOMRIGHT", rightPanel, "BOTTOMLEFT", 0, 0)

    -- Team header
    local teamNameLabel = centerPanel:CreateFontString(nil, "OVERLAY", "GameFontNormal")
    teamNameLabel:SetFont(teamNameLabel:GetFont(), RF.FONT_SIZES.large, "")
    teamNameLabel:SetPoint("TOPLEFT", 12, -8)
    teamNameLabel:SetTextColor(unpack(T.textPrimary))

    local teamSubLabel = centerPanel:CreateFontString(nil, "OVERLAY", "GameFontNormal")
    teamSubLabel:SetFont(teamSubLabel:GetFont(), RF.FONT_SIZES.small, "")
    teamSubLabel:SetPoint("TOPLEFT", teamNameLabel, "BOTTOMLEFT", 0, -2)
    teamSubLabel:SetTextColor(unpack(T.textSecondary))

    local warningLabel = centerPanel:CreateFontString(nil, "OVERLAY", "GameFontNormal")
    warningLabel:SetFont(warningLabel:GetFont(), RF.FONT_SIZES.small, "")
    warningLabel:SetPoint("TOPLEFT", teamSubLabel, "BOTTOMLEFT", 0, -2)
    warningLabel:SetTextColor(unpack(T.warning))

    -- Composition bar
    local compBar = CreateCompositionBar(centerPanel)
    compBar:SetPoint("TOPLEFT", 12, -56)
    compBar:SetPoint("RIGHT", -12, 0)

    compBar.pillFrame:SetPoint("TOPLEFT", compBar, "BOTTOMLEFT", 0, -2)
    compBar.pillFrame:SetPoint("RIGHT", -12, 0)

    -- Member list
    local memberList = RF:CreateScrollList(centerPanel, {
        rowHeight = 26,
        createRow = function(p, i)
            local row = CreateFrame("Button", nil, p)
            row:SetHeight(26)

            row.bg = row:CreateTexture(nil, "BACKGROUND")
            row.bg:SetAllPoints()

            -- Role icon
            row.roleIcon = row:CreateTexture(nil, "ARTWORK")
            row.roleIcon:SetSize(14, 14)
            row.roleIcon:SetPoint("LEFT", 8, 0)

            row.nameText = row:CreateFontString(nil, "OVERLAY", "GameFontNormal")
            row.nameText:SetFont(row.nameText:GetFont(), RF.FONT_SIZES.normal, "")
            row.nameText:SetPoint("LEFT", 26, 0)
            row.nameText:SetWidth(160)
            row.nameText:SetJustifyH("LEFT")

            row.classText = row:CreateFontString(nil, "OVERLAY", "GameFontNormal")
            row.classText:SetFont(row.classText:GetFont(), RF.FONT_SIZES.small, "")
            row.classText:SetPoint("LEFT", row.nameText, "RIGHT", 4, 0)
            row.classText:SetWidth(80)
            row.classText:SetJustifyH("LEFT")
            row.classText:SetTextColor(unpack(T.textMuted))

            row.roleText = row:CreateFontString(nil, "OVERLAY", "GameFontNormal")
            row.roleText:SetFont(row.roleText:GetFont(), RF.FONT_SIZES.small, "")
            row.roleText:SetPoint("RIGHT", -8, 0)
            row.roleText:SetJustifyH("RIGHT")

            -- Online dot
            row.onlineDot = row:CreateTexture(nil, "OVERLAY")
            row.onlineDot:SetSize(6, 6)
            row.onlineDot:SetPoint("RIGHT", row.roleText, "LEFT", -6, 0)
            row.onlineDot:SetColorTexture(0.3, 0.9, 0.3)

            return row
        end,
        updateRow = function(row, data)
            if not data then return end

            -- Role icon
            local atlas = ROLE_ICONS[data.role]
            if atlas then
                row.roleIcon:SetAtlas(atlas)
                row.roleIcon:Show()
            else
                row.roleIcon:Hide()
            end

            -- Name (class-colored)
            row.nameText:SetText(RF:GetClassColoredName(data.name, data.classFile))

            -- Class
            row.classText:SetText(data.classDisplayName or "")

            -- Role label
            local rc = RF.TEAM_ROLE_COLORS[data.role] or T.textMuted
            row.roleText:SetText(data.role)
            row.roleText:SetTextColor(rc[1], rc[2], rc[3])

            -- Online dot
            row.onlineDot:SetShown(data.isOnline)

            row.bg:SetColorTexture(0, 0, 0, 0)
        end,
        onRowClick = function(row, data, button)
            if not data or not selectedTeamID then return end
            if button == "RightButton" then
                local canEdit = RF:CanEditTeam(selectedTeamID)
                local menuItems = {
                    { text = data.name, isTitle = true },
                }
                if canEdit then
                    local roleSubmenu = {}
                    for _, r in ipairs(RF.TEAM_ROLES) do
                        tinsert(roleSubmenu, {
                            text = (data.role == r.key and "|TInterface\\RAIDFRAME\\ReadyCheck-Ready:14|t " or "      ") .. r.label,
                            func = function()
                                C_Timer.After(0, function()
                                    RF:SetTeamMemberRole(selectedTeamID, data.name, r.key)
                                end)
                            end,
                        })
                    end
                    tinsert(menuItems, { text = "Change Role", submenu = roleSubmenu })
                end
                tinsert(menuItems, { text = "Whisper", func = function()
                    C_Timer.After(0, function() ChatFrame_OpenChat("/w " .. (data.fullName or data.name) .. " ") end)
                end })
                tinsert(menuItems, { text = "Copy Name", func = function()
                    C_Timer.After(0, function() RF:ShowCopyPopup(data.name) end)
                end })
                if canEdit then
                    tinsert(menuItems, { separator = true })
                    tinsert(menuItems, { text = "Remove from Team", color = T.danger, func = function()
                        C_Timer.After(0, function()
                            RF:RemoveTeamMember(selectedTeamID, data.name)
                        end)
                    end })
                end
                RF:ShowContextMenu(row, menuItems)
            end
        end,
        onRowEnter = function(row, data)
            if not data then return end
            row.bg:SetColorTexture(1, 1, 1, 0.04)
            GameTooltip:SetOwner(row, "ANCHOR_RIGHT")
            GameTooltip:AddLine(data.name, 1, 1, 1)
            if data.classDisplayName then
                GameTooltip:AddLine(format("Level %d %s", data.level or 0, data.classDisplayName), 0.7, 0.7, 0.7)
            end
            if data.rankName then
                GameTooltip:AddLine("Rank: " .. data.rankName, 0.7, 0.7, 0.7)
            end
            local otherTeams = RF:GetMemberTeams(data.name)
            if #otherTeams > 1 then
                GameTooltip:AddLine(" ")
                GameTooltip:AddLine("Also on:", 1, 0.82, 0)
                for _, t in ipairs(otherTeams) do
                    if t.teamID ~= selectedTeamID then
                        GameTooltip:AddLine("  " .. t.teamName, 0.7, 0.7, 0.7)
                    end
                end
            end
            GameTooltip:Show()
        end,
        onRowLeave = function(row)
            if row then row.bg:SetColorTexture(0, 0, 0, 0) end
            GameTooltip:Hide()
        end,
    })
    memberList:SetPoint("TOPLEFT", 0, -82)
    memberList:SetPoint("BOTTOMRIGHT", 0, 0)

    -- Empty state for center
    local centerEmpty = RF:CreateLabel(centerPanel, "Select a team from the left panel\nor create a new one", RF.FONT_SIZES.normal, "textMuted")
    centerEmpty:SetPoint("CENTER", 0, 0)
    centerEmpty:SetJustifyH("CENTER")

    ---------------------------------------------------------------------------
    -- Refresh Logic
    ---------------------------------------------------------------------------
    local function RefreshAll()
        -- Team list
        local teams = RF:GetTeamsSorted()
        local filtered = {}
        for _, t in ipairs(teams) do
            if teamSearchText == "" or t.team.name:lower():find(teamSearchText:lower(), 1, true) then
                tinsert(filtered, t)
            end
        end
        teamList:SetData(filtered)

        -- Center panel
        local team = selectedTeamID and RF:GetTeam(selectedTeamID)
        local hasTeam = team ~= nil

        teamNameLabel:SetShown(hasTeam)
        teamSubLabel:SetShown(hasTeam)
        warningLabel:SetShown(false)
        compBar:SetShown(hasTeam)
        compBar.pillFrame:SetShown(hasTeam)
        memberList:SetShown(hasTeam)
        centerEmpty:SetShown(not hasTeam)

        -- Right panel
        rightPanel:SetShown(hasTeam)
        assignEmpty:SetShown(not hasTeam)

        if hasTeam then
            local canEdit = RF:CanEditTeam(selectedTeamID)
            -- Show/hide assignment panel based on edit permission
            assignHeader:SetShown(canEdit)
            assignSearch:SetShown(canEdit)
            classDropdown:SetShown(canEdit)
            roleDropdown:SetShown(canEdit)
            assignList:SetShown(canEdit)
            assignLocked:SetShown(not canEdit)

            teamNameLabel:SetText(team.name)
            local comp = RF:GetTeamComposition(selectedTeamID)
            local typeLabel = team.customTypeLabel or team.teamType
            if not team.customTypeLabel then
                for _, tt in ipairs(RF.TEAM_TYPES) do
                    if tt.key == team.teamType then typeLabel = tt.label; break end
                end
            end
            local officerTag = team.officerOnly and "  |  |cFFFFAA00Officer Only|r" or ""
            teamSubLabel:SetText(format("%s  |  %d/%d members  |  |cFF4ADE80%d online|r%s", typeLabel, comp.total, comp.maxSize, comp.online, officerTag))

            -- Warnings
            if RF.charDB and RF.charDB.teamShowCompWarnings ~= false then
                local validation = RF:ValidateTeamComp(selectedTeamID)
                if #validation.warnings > 0 then
                    warningLabel:SetText(table.concat(validation.warnings, "  |  "))
                    warningLabel:Show()
                end
            end

            -- Comp bar
            compBar:Update(comp)

            -- Member list: build sorted array
            local members = {}
            for name, info in pairs(team.members) do
                local member = RF:GetMemberByName(name)
                tinsert(members, {
                    name = name,
                    fullName = member and member.fullName or name,
                    role = info.role or "DPS",
                    classFile = member and member.classFile or "WARRIOR",
                    classDisplayName = member and member.classDisplayName or "",
                    level = member and member.level or 0,
                    rankName = member and member.rankName or "",
                    isOnline = member and member.isOnline or false,
                })
            end
            table.sort(members, function(a, b)
                local ra = ROLE_ORDER[a.role] or 9
                local rb = ROLE_ORDER[b.role] or 9
                if ra ~= rb then return ra < rb end
                return a.name < b.name
            end)
            memberList:SetData(members)

            -- Assignment list: unassigned, filtered
            local unassigned = RF:GetUnassignedMembers(selectedTeamID)
            local assignFiltered = {}
            for _, entry in ipairs(unassigned) do
                local passSearch = assignSearchText == "" or entry.name:lower():find(assignSearchText:lower(), 1, true)
                    or (entry.classDisplayName and entry.classDisplayName:lower():find(assignSearchText:lower(), 1, true))
                local passClass = not assignClassFilter or entry.classFile == assignClassFilter
                local passOnline = not (RF.charDB and RF.charDB.teamShowOnlineOnly) or entry.isOnline
                if passSearch and passClass and passOnline then
                    tinsert(assignFiltered, entry)
                end
            end
            -- Sort online first, then by name
            table.sort(assignFiltered, function(a, b)
                if a.isOnline ~= b.isOnline then return a.isOnline end
                return a.name < b.name
            end)
            assignList:SetData(assignFiltered)
        end
    end

    -- Register callbacks
    RF:RegisterCallback("TEAMS_CHANGED", RefreshAll)
    RF:RegisterCallback("ROSTER_REFRESHED", RefreshAll)

    parent:SetScript("OnShow", RefreshAll)

    -- Initial refresh
    RefreshAll()
end
