-- New Applicants!! - UI Components
-- Version: 1.1.1

local NA = _G["NewApplicants"]
if not NA then return end

-- Create Main Frame
function NA:CreateMainFrame()
    local f = CreateFrame("Frame", "NewApplicantFrame", UIParent, "BackdropTemplate")
    f:SetSize(420, 300)
    f:SetPoint(self.db.position.point, UIParent, self.db.position.point, self.db.position.x, self.db.position.y)
    f:SetScale(self.db.scale)
    f:SetMovable(true)
    f:SetClampedToScreen(true)
    f:EnableMouse(true)
    f:RegisterForDrag("LeftButton")
    f:SetFrameStrata("MEDIUM")
    f:SetFrameLevel(10)
    
    f:SetBackdrop(nil)
    
    f:SetScript("OnDragStart", function(self) self:StartMoving() end)
    f:SetScript("OnDragStop", function(self)
        self:StopMovingOrSizing()
        local point, _, _, x, y = self:GetPoint()
        NA.db.position = { point = point, x = x, y = y }
    end)
    
    local header = f:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
    header:SetPoint("TOP", 0, -10)
    header:SetText("|cFFFFD100New Applicants!!|r")
    f.header = header
    
    ---- Header animation
    local animTime = 0
    local baseY = -10
    local animSpeed = 6
    local animHeight = 6
    
    f:SetScript("OnUpdate", function(self, elapsed)
        animTime = animTime + elapsed
        local offsetY = math.sin(animTime * animSpeed) * animHeight
        header:SetPoint("TOP", 0, baseY + offsetY)
    end)
    
    ---- Close Button
        local closeBtn = CreateFrame("Button", nil, f)
    closeBtn:SetSize(20, 20)
    closeBtn:SetPoint("TOPRIGHT", f, "TOPRIGHT", -30, -5)
    closeBtn:SetNormalAtlas("Radial_Wheel_Icon_Close")
    closeBtn:SetHighlightAtlas("Radial_Wheel_Icon_Close")
    closeBtn:GetNormalTexture():SetVertexColor(1, 1, 1, 0.45)
    closeBtn:GetHighlightTexture():SetVertexColor(1, 1, 1, 1.0)
    closeBtn:SetScript("OnClick", function() f:Hide() end)
    closeBtn:SetScript("OnEnter", function(self)
        GameTooltip:SetOwner(self, "ANCHOR_LEFT")
        GameTooltip:SetText(NA.L["Close"] or "Close", 1, 1, 1)
        GameTooltip:Show()
    end)
    closeBtn:SetScript("OnLeave", function() GameTooltip:Hide() end)

    ---- Setting Button
    local settingsBtn = CreateFrame("Button", nil, f)
    settingsBtn:SetSize(36, 36)
    settingsBtn:SetPoint("TOPLEFT", f, "TOPLEFT", 5, -2)
    settingsBtn:SetNormalAtlas("GM-icon-settings")
    settingsBtn:SetHighlightAtlas("GM-icon-settings")
    settingsBtn:GetNormalTexture():SetVertexColor(1, 1, 1, 0.45)
    settingsBtn:GetHighlightTexture():SetVertexColor(1, 1, 1, 1.0)
    settingsBtn:SetScript("OnClick", function() NA:ShowSettingsPanel() end)
    settingsBtn:SetScript("OnEnter", function(self)
        GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
        GameTooltip:SetText(NA.L and NA.L["Settings"] or "Settings", 1, 1, 1)
        GameTooltip:Show()
    end)
    settingsBtn:SetScript("OnLeave", function() GameTooltip:Hide() end)

    ---- Lock Button
    local lockBtn = CreateFrame("Button", nil, f)
    lockBtn:SetSize(17, 17)
    lockBtn:SetPoint("TOPLEFT", settingsBtn, "TOPRIGHT", 4, -8)
    f.lockBtn = lockBtn

    if self.db.isLocked == nil then
        self.db.isLocked = false
    end

    local function UpdateLockButton()
        if NA.db.isLocked then
            lockBtn:SetNormalAtlas("friendslist-recentallies-Pin")
            lockBtn:SetHighlightAtlas("friendslist-recentallies-Pin")
            lockBtn:GetNormalTexture():SetVertexColor(1, 1, 1, 1.0)
            lockBtn:GetHighlightTexture():SetVertexColor(1, 1, 1, 1.0)
            f:SetMovable(false)
            f:EnableMouse(false)
        else
            lockBtn:SetNormalAtlas("friendslist-recentallies-Pin-yellow")
            lockBtn:SetHighlightAtlas("friendslist-recentallies-Pin-yellow")
            lockBtn:GetNormalTexture():SetVertexColor(1, 1, 1, 0.45)
            lockBtn:GetHighlightTexture():SetVertexColor(1, 1, 1, 1.0)
            f:SetMovable(true)
            f:EnableMouse(true)
        end
    end

    lockBtn:SetScript("OnClick", function()
        NA.db.isLocked = not NA.db.isLocked
        UpdateLockButton()
    end)
    lockBtn:SetScript("OnEnter", function(self)
        GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
        if NA.db.isLocked then
            GameTooltip:SetText(NA.L["Position locked"] or "Position locked", 1, 0.2, 0.2)
            GameTooltip:AddLine(NA.L["Click to unlock"] or "Click to unlock", 0.7, 0.7, 0.7, true)
        else
            GameTooltip:SetText(NA.L["Position unlocked"] or "Position unlocked", 0.2, 1, 0.2)
            GameTooltip:AddLine(NA.L["Click to lock"] or "Click to lock", 0.7, 0.7, 0.7, true)
        end
        GameTooltip:Show()
    end)
    lockBtn:SetScript("OnLeave", function() GameTooltip:Hide() end)

    UpdateLockButton()

    ---- LFG eye 
    local eyeBtn = CreateFrame("Button", nil, f)
    eyeBtn:SetSize(24, 24)
    eyeBtn:SetPoint("TOPRIGHT", closeBtn, "TOPLEFT", -6, 0)
    
    local eyeNormal = eyeBtn:CreateTexture(nil, "ARTWORK")
    eyeNormal:SetAllPoints()
    eyeNormal:SetAtlas("groupfinder-eye-single")
    eyeBtn:SetNormalTexture(eyeNormal)
    
    local eyePushed = eyeBtn:CreateTexture(nil, "ARTWORK")
    eyePushed:SetAllPoints()
    eyePushed:SetAtlas("groupfinder-eye-single")
    eyePushed:SetVertexColor(0.7, 0.7, 0.7)
    eyeBtn:SetPushedTexture(eyePushed)
    
    local eyeHighlight = eyeBtn:CreateTexture(nil, "HIGHLIGHT")
    eyeHighlight:SetAllPoints()
    eyeHighlight:SetAtlas("groupfinder-eye-single")
    eyeHighlight:SetVertexColor(1, 1, 0.6)
    eyeHighlight:SetBlendMode("ADD")
    eyeBtn:SetHighlightTexture(eyeHighlight)
    
    eyeBtn:SetScript("OnClick", function() NA:OpenLFGFrame() end)
    eyeBtn:SetScript("OnEnter", function(self)
        GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
        GameTooltip:SetText(NA.L and NA.L["Open Group Finder"] or "Open Group Finder", 1, 1, 1)
        GameTooltip:Show()
    end)
    eyeBtn:SetScript("OnLeave", function()
        GameTooltip:Hide()
    end)
    
    ---- scroll frame
    local scroll = CreateFrame("ScrollFrame", "NewApplicantScrollFrame", f, "UIPanelScrollFrameTemplate")
    scroll:SetPoint("TOPLEFT", 10, -35)
    scroll:SetPoint("BOTTOMRIGHT", -30, 10)
    
    local content = CreateFrame("Frame", nil, scroll)
    content:SetSize(380, 400)
    scroll:SetScrollChild(content)
    
    f.scroll = scroll
    f.content = content
    self.mainFrame = f
    f:Hide()
end

-- Create Settings Panel
function NA:ShowSettingsPanel()
    if self.settingsFrame then self.settingsFrame:Show() return end

    NA._panelCount = (NA._panelCount or 0) + 1
    local pid = NA._panelCount

    local f = CreateFrame("Frame", nil, UIParent, "BackdropTemplate")
    f:SetSize(320, 460)
    f:SetPoint("CENTER")
    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 }
    })
    f:SetBackdropColor(0, 0, 0, 0.9)
    f:SetMovable(true)
    f:EnableMouse(true)
    f:RegisterForDrag("LeftButton")
    f:SetScript("OnDragStart", f.StartMoving)
    f:SetScript("OnDragStop", f.StopMovingOrSizing)
    f:SetFrameStrata("DIALOG")
    f:SetFrameLevel(100)
    
    local title = f:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
    title:SetPoint("TOP", 0, -15)
    local settingsTitle = NA.L and NA.L["Settings"] or "Settings"
    title:SetText("|cFFF8D943New Applicants!! " .. settingsTitle .. "|r")
    
    local closeBtn = CreateFrame("Button", nil, f)
    closeBtn:SetSize(14, 14)
    closeBtn:SetPoint("TOPRIGHT", -8, -8)
    closeBtn:SetNormalAtlas("Radial_Wheel_Icon_Close")
    closeBtn:SetHighlightAtlas("Radial_Wheel_Icon_Close")
    closeBtn:GetNormalTexture():SetVertexColor(1, 1, 1, 0.45)
    closeBtn:GetHighlightTexture():SetVertexColor(1, 1, 1, 1.0)
    closeBtn:SetScript("OnClick", function() f:Hide() end)
    
    ---- 1. Background alpha
    local alphaLabel = f:CreateFontString(nil, "OVERLAY", "GameFontNormal")
    alphaLabel:SetPoint("TOPLEFT", 20, -50)
    local bgOpacityText = NA.L and NA.L["Background Opacity"] or "Background Opacity"
    alphaLabel:SetText("|cFFFFD1001. " .. bgOpacityText .. "|r")
    
    local alphaSlider = CreateFrame("Slider", "NAAlphaSlider"..pid, f, "OptionsSliderTemplate")
    alphaSlider:SetPoint("TOPLEFT", 20, -70)
    alphaSlider:SetWidth(260)
    alphaSlider:SetHeight(20)
    alphaSlider:SetMinMaxValues(0, 1)
    alphaSlider:SetValue(self.db.backgroundAlpha)
    alphaSlider:SetValueStep(0.05)
    alphaSlider:SetObeyStepOnDrag(true)
    _G[alphaSlider:GetName().."Low"]:SetText(NA.L and NA.L["slider_alpha_low"] or "0%")
    _G[alphaSlider:GetName().."High"]:SetText(NA.L and NA.L["slider_alpha_high"] or "100%")
    _G[alphaSlider:GetName().."Text"]:SetText("")
    
    local alphaValue = f:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
    alphaValue:SetPoint("TOP", alphaSlider, "BOTTOM", 0, 2)
    local currentText = NA.L and NA.L["Current:"] or "Current:"
    alphaValue:SetText(string.format(currentText .. " %.0f%%", self.db.backgroundAlpha * 100))
    
    alphaSlider:SetScript("OnValueChanged", function(self, value)
        NA.db.backgroundAlpha = value
        if NA.mainFrame and NA.mainFrame.content and NA.mainFrame.content.applicantFrames then
            for _, cardFrame in ipairs(NA.mainFrame.content.applicantFrames) do
                cardFrame:SetAlpha(value)
            end
        end
        alphaValue:SetText(string.format(currentText .. " %.0f%%", value * 100))
    end)
    
    ---- 2. Max applicants No.
    local maxLabel = f:CreateFontString(nil, "OVERLAY", "GameFontNormal")
    maxLabel:SetPoint("TOPLEFT", 20, -115)
    local maxDisplayText = NA.L and NA.L["Max Display"] or "Max Display"
    maxLabel:SetText("|cFFFFD1002. " .. maxDisplayText .. "|r")
    
    local maxSlider = CreateFrame("Slider", "NAMaxSlider"..pid, f, "OptionsSliderTemplate")
    maxSlider:SetPoint("TOPLEFT", 20, -135)
    maxSlider:SetWidth(260)
    maxSlider:SetHeight(20)
    maxSlider:SetMinMaxValues(1, 8)
    maxSlider:SetValue(self.db.maxDisplay)
    maxSlider:SetValueStep(1)
    maxSlider:SetObeyStepOnDrag(true)
    _G[maxSlider:GetName().."Low"]:SetText(NA.L and NA.L["slider_max_low"] or "1")
    _G[maxSlider:GetName().."High"]:SetText(NA.L and NA.L["slider_max_high"] or "8")
    _G[maxSlider:GetName().."Text"]:SetText("")
    
    local maxValue = f:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
    maxValue:SetPoint("TOP", maxSlider, "BOTTOM", 0, 2)
    local peopleText = NA.L and NA.L["people"] or "people"
    maxValue:SetText(string.format(currentText .. " %d" .. peopleText, self.db.maxDisplay))
    
    maxSlider:SetScript("OnValueChanged", function(self, value)
        NA.db.maxDisplay = value
        maxValue:SetText(string.format(currentText .. " %d" .. peopleText, value))
        if NA.UpdateDisplay then
            NA:UpdateDisplay()
        end
    end)
    
    ---- 3. UI scale
    local scaleLabel = f:CreateFontString(nil, "OVERLAY", "GameFontNormal")
    scaleLabel:SetPoint("TOPLEFT", 20, -180)
    local scaleText = NA.L and NA.L["Scale"] or "Scale"
    scaleLabel:SetText("|cFFFFD1003. " .. scaleText .. "|r")
    
    local scaleSlider = CreateFrame("Slider", "NAScaleSlider"..pid, f, "OptionsSliderTemplate")
    scaleSlider:SetPoint("TOPLEFT", 20, -200)
    scaleSlider:SetWidth(260)
    scaleSlider:SetHeight(20)
    scaleSlider:SetMinMaxValues(0.75, 1.25)
    scaleSlider:SetValue(self.db.scale)
    scaleSlider:SetValueStep(0.05)
    scaleSlider:SetObeyStepOnDrag(true)
    _G[scaleSlider:GetName().."Low"]:SetText(NA.L and NA.L["slider_scale_low"] or "75%")
    _G[scaleSlider:GetName().."High"]:SetText(NA.L and NA.L["slider_scale_high"] or "125%")
    _G[scaleSlider:GetName().."Text"]:SetText("")
    
    local scaleValue = f:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
    scaleValue:SetPoint("TOP", scaleSlider, "BOTTOM", 0, 2)
    scaleValue:SetText(string.format(currentText .. " %.0f%%", self.db.scale * 100))
    
    scaleSlider:SetScript("OnValueChanged", function(self, value)
        NA.db.scale = value
        if NA.mainFrame then
            NA.mainFrame:SetScale(value)
        end
        scaleValue:SetText(string.format(currentText .. " %.0f%%", value * 100))
    end)
    
    ---- 4. Notifications
    local soundLabel = f:CreateFontString(nil, "OVERLAY", "GameFontNormal")
    soundLabel:SetPoint("TOPLEFT", 20, -245)
    soundLabel:SetText("|cFFFFD1004. " .. (NA.L and NA.L["Notifications"] or "Notifications") .. "|r")

    -- 4-1. Sound (parent checkbox)
    local soundCheck = CreateFrame("CheckButton", "NASoundCheck"..pid, f, "InterfaceOptionsCheckButtonTemplate")
    soundCheck:SetPoint("TOPLEFT", 20, -263)
    soundCheck:SetSize(32, 32)
    _G[soundCheck:GetName().."Text"]:SetText(NA.L and NA.L["Play sound when new applicants arrive"] or "Play sound when new applicants arrive")
    soundCheck:SetChecked(self.db.soundEnabled)

    -- 4-1a. Sound radio: 항상
    local soundRadioAlways = CreateFrame("CheckButton", "NASoundRadioAlways"..pid, f, "UIRadioButtonTemplate")
    soundRadioAlways:SetPoint("TOPLEFT", 40, -290)
    _G[soundRadioAlways:GetName().."Text"]:SetText(NA.L and NA.L["Always"] or "Always")
    soundRadioAlways:SetChecked(not self.db.soundOnlyActive)

    -- 4-1b. Sound radio: 모집 중일 때만
    local soundRadioOnly = CreateFrame("CheckButton", "NASoundRadioOnly"..pid, f, "UIRadioButtonTemplate")
    soundRadioOnly:SetPoint("TOPLEFT", 40, -308)
    _G[soundRadioOnly:GetName().."Text"]:SetText(NA.L and NA.L["Only when I am recruiting"] or "Only when I am recruiting")
    soundRadioOnly:SetChecked(self.db.soundOnlyActive)

    soundRadioAlways:SetScript("OnClick", function()
        NA.db.soundOnlyActive = false
        soundRadioAlways:SetChecked(true)
        soundRadioOnly:SetChecked(false)
    end)
    soundRadioOnly:SetScript("OnClick", function()
        NA.db.soundOnlyActive = true
        soundRadioAlways:SetChecked(false)
        soundRadioOnly:SetChecked(true)
    end)

    -- 4-1c. Sound checkbox: 공격대 모집 제외 (inverted: checked = exclude = !playOnRaid)
    local soundExcludeRaid = CreateFrame("CheckButton", "NASoundExcludeRaid"..pid, f, "UICheckButtonTemplate")
    soundExcludeRaid:SetSize(20, 20)
    soundExcludeRaid:SetPoint("TOPLEFT", 43, -328)
    soundExcludeRaid:SetChecked(not self.db.playOnRaid)
    local soundExcludeRaidText = soundExcludeRaid:CreateFontString(nil, "OVERLAY", "GameFontNormal")
    soundExcludeRaidText:SetPoint("LEFT", soundExcludeRaid, "RIGHT", 3, 0)
    soundExcludeRaidText:SetText(NA.L and NA.L["Exclude raid listings"] or "Exclude raid listings")
    soundExcludeRaid:SetScript("OnClick", function(self)
        NA.db.playOnRaid = not self:GetChecked()
    end)

    local function UpdateSoundChildren()
        if NA.db.soundEnabled then
            soundRadioAlways:Enable()
            soundRadioOnly:Enable()
            soundExcludeRaid:Enable()
        else
            soundRadioAlways:Disable()
            soundRadioOnly:Disable()
            soundExcludeRaid:Disable()
        end
    end
    UpdateSoundChildren()

    soundCheck:SetScript("OnClick", function(self)
        NA.db.soundEnabled = self:GetChecked()
        if self:GetChecked() then
            PlaySoundFile("Interface\\AddOns\\NewApplicants\\Sounds\\Xylophone_alarm.mp3", "Master")
        end
        UpdateSoundChildren()
    end)

    -- 4-2. Cards (parent checkbox)
    local showCardsCheck = CreateFrame("CheckButton", "NAShowCardsCheck"..pid, f, "InterfaceOptionsCheckButtonTemplate")
    showCardsCheck:SetPoint("TOPLEFT", 20, -350)
    showCardsCheck:SetSize(32, 32)
    _G[showCardsCheck:GetName().."Text"]:SetText(NA.L and NA.L["Show cards when new applicants arrive"] or "Show cards when new applicants arrive")
    showCardsCheck:SetChecked(self.db.showCards)

    -- 4-2a. Cards radio: 항상
    local cardRadioAlways = CreateFrame("CheckButton", "NACardRadioAlways"..pid, f, "UIRadioButtonTemplate")
    cardRadioAlways:SetPoint("TOPLEFT", 40, -377)
    _G[cardRadioAlways:GetName().."Text"]:SetText(NA.L and NA.L["Always"] or "Always")
    cardRadioAlways:SetChecked(not self.db.cardOnlyActive)

    -- 4-2b. Cards radio: 모집 중일 때만
    local cardRadioOnly = CreateFrame("CheckButton", "NACardRadioOnly"..pid, f, "UIRadioButtonTemplate")
    cardRadioOnly:SetPoint("TOPLEFT", 40, -395)
    _G[cardRadioOnly:GetName().."Text"]:SetText(NA.L and NA.L["Only when I am recruiting"] or "Only when I am recruiting")
    cardRadioOnly:SetChecked(self.db.cardOnlyActive)

    cardRadioAlways:SetScript("OnClick", function()
        NA.db.cardOnlyActive = false
        cardRadioAlways:SetChecked(true)
        cardRadioOnly:SetChecked(false)
        if NA.UpdateDisplay then NA:UpdateDisplay() end
    end)
    cardRadioOnly:SetScript("OnClick", function()
        NA.db.cardOnlyActive = true
        cardRadioAlways:SetChecked(false)
        cardRadioOnly:SetChecked(true)
        if NA.UpdateDisplay then NA:UpdateDisplay() end
    end)

    -- 4-2c. Cards checkbox: 공격대 모집 제외 (inverted: checked = exclude = !showCardsOnRaid)
    local cardExcludeRaid = CreateFrame("CheckButton", "NACardExcludeRaid"..pid, f, "UICheckButtonTemplate")
    cardExcludeRaid:SetSize(20, 20)
    cardExcludeRaid:SetPoint("TOPLEFT", 43, -415)
    cardExcludeRaid:SetChecked(not self.db.showCardsOnRaid)
    local cardExcludeRaidText = cardExcludeRaid:CreateFontString(nil, "OVERLAY", "GameFontNormal")
    cardExcludeRaidText:SetPoint("LEFT", cardExcludeRaid, "RIGHT", 3, 0)
    cardExcludeRaidText:SetText(NA.L and NA.L["Exclude raid listings"] or "Exclude raid listings")
    cardExcludeRaid:SetScript("OnClick", function(self)
        NA.db.showCardsOnRaid = not self:GetChecked()
        if NA.UpdateDisplay then NA:UpdateDisplay() end
    end)

    local function UpdateCardChildren()
        if NA.db.showCards then
            cardRadioAlways:Enable()
            cardRadioOnly:Enable()
            cardExcludeRaid:Enable()
        else
            cardRadioAlways:Disable()
            cardRadioOnly:Disable()
            cardExcludeRaid:Disable()
        end
    end
    UpdateCardChildren()

    showCardsCheck:SetScript("OnClick", function(self)
        NA.db.showCards = self:GetChecked()
        UpdateCardChildren()
        if NA.UpdateDisplay then NA:UpdateDisplay() end
    end)

    self.settingsFrame = f
    f:Show()
end

-- Update Display
function NA:UpdateDisplay()
    if not self.mainFrame then self:CreateMainFrame() end
    local content = self.mainFrame.content
    
    if content.applicantFrames then
        for _, frame in ipairs(content.applicantFrames) do
            frame:Hide()
            frame:SetParent(nil)
        end
    end
    content.applicantFrames = {}
    
    if #self.applicantDataList == 0 then self.mainFrame:Hide() return end

    if not self.db.showCards then
        self.mainFrame:Hide()
        return
    end

    if not self.db.showCardsOnRaid and self.isRaidListing then
        self.mainFrame:Hide()
        return
    end

    if self.db.cardOnlyActive and not self.hasActiveListing then
        self.mainFrame:Hide()
        return
    end
    
    self.mainFrame:Show()
    local displayCount = math.min(#self.applicantDataList, self.db.maxDisplay)
    local yOffset = 0
    
    for i = 1, displayCount do
        local data = self.applicantDataList[i]
        local frame = self:CreateApplicantFrame(data)
        frame:SetPoint("TOPLEFT", content, "TOPLEFT", 0, yOffset)
        frame:Show()
        table.insert(content.applicantFrames, frame)
        yOffset = yOffset - 80 
    end
    content:SetHeight(math.abs(yOffset) + 10)
    
    ---- Scroll show / hide 
    local scrollFrame = self.mainFrame.scroll
    if displayCount <= 3 then
        scrollFrame.ScrollBar:Hide()
    else
        scrollFrame.ScrollBar:Show()
    end
end

-- Create Applicant Frame
function NA:CreateApplicantFrame(data)
    local f = CreateFrame("Button", nil, self.mainFrame.content)
    f:SetSize(370, 75)
    f:SetAlpha(NA.db.backgroundAlpha)
    
    ---- Class frame
    local classTexture = self:GetClassFrameTexture(data.class)
    if classTexture then
        local bg = f:CreateTexture(nil, "BACKGROUND")
        bg:SetAllPoints()
        bg:SetTexture(classTexture)
        f.bg = bg
    end
    
    local indentX = 25 
    
    ---- role icon (Tank, Healer, Damage)
    local roleIcon = f:CreateTexture(nil, "ARTWORK")
    roleIcon:SetSize(20, 20)
    roleIcon:SetPoint("TOPLEFT", indentX, -8)
    if data.tank then
        roleIcon:SetAtlas("UI-LFG-RoleIcon-Tank")
    elseif data.healer then
        roleIcon:SetAtlas("UI-LFG-RoleIcon-Healer")
    else
        roleIcon:SetAtlas("UI-LFG-RoleIcon-DPS")
    end

    ---- character name
	local nameText = f:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
	nameText:SetPoint("LEFT", roleIcon, "RIGHT", 4, 0)
	nameText:SetWidth(120)
	nameText:SetWordWrap(false)
	nameText:SetNonSpaceWrap(false)
	nameText:SetJustifyH("LEFT")
    
    local classColor = C_ClassColor.GetClassColor(data.class)
    if classColor then
        nameText:SetTextColor(classColor.r, classColor.g, classColor.b)
    end
    
    local nameDisplay = data.charName .. "-" .. data.serverName
    if data.numMembers and data.numMembers > 1 then
        nameDisplay = nameDisplay .. " "
    end
    nameText:SetText(nameDisplay)

    if data.numMembers and data.numMembers > 1 then
        local additionalText = f:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
        additionalText:SetPoint("LEFT", nameText, "RIGHT", 2, 0)
        additionalText:SetTextColor(0.9, 0.8, 0.5) -- #e6cc80
        local additionalMembers = data.numMembers - 1
        local plusMembersFormat = self.L and self.L["plus_members"] or "+%d"
        local outsideText = string.format(plusMembersFormat, additionalMembers)
        additionalText:SetText(outsideText)
    end

    ---- Second row position
    local secondRowY = -43 

    ---- faction icon
    local factionIcon = f:CreateTexture(nil, "ARTWORK")
    factionIcon:SetSize(20, 20)
    factionIcon:SetPoint("TOPLEFT", indentX, secondRowY)
    factionIcon:SetAtlas(data.factionGroup == 1 and "QuestPortraitIcon-Alliance" or "QuestPortraitIcon-Horde")

    ---- ILV info
    local ilvlLabel = f:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
    ilvlLabel:SetPoint("BOTTOMLEFT", factionIcon, "BOTTOMRIGHT", 5, 0)
    ilvlLabel:SetTextColor(0.5, 0.5, 0.5)
    ilvlLabel:SetText("ILV")

    local ilvlValue = f:CreateFontString(nil, "OVERLAY", "GameFontHighlightHuge")
    --ilvlValue:SetPoint("BOTTOMLEFT", ilvlLabel, "BOTTOMRIGHT", 5, -2)
    ilvlValue:SetPoint("LEFT", ilvlLabel, "RIGHT", 3, 1) 
    ilvlValue:SetText(math.floor(data.itemLevel))

    ---- seperate bar 1
    local sep1 = f:CreateTexture(nil, "ARTWORK")
    sep1:SetSize(1, 30)
    sep1:SetColorTexture(1, 1, 1, 0.3)
    sep1:SetPoint("BOTTOMLEFT", factionIcon, "BOTTOMRIGHT", 82, -3)

    ---- rioRoles icon (max 2)
    if data.rioRoles and #data.rioRoles > 0 then
        local count = math.min(2, #data.rioRoles)
        local yOffsets = count == 1 and { 0 } or { 8, -8 }
        for idx = 1, count do
            local rioRoleIcon = f:CreateTexture(nil, "ARTWORK")
            rioRoleIcon:SetSize(16, 16)
            rioRoleIcon:SetPoint("CENTER", sep1, "CENTER", 13, yOffsets[idx])
            rioRoleIcon:SetAtlas(self:GetRoleAtlas(data.rioRoles[idx].spec, data.rioRoles[idx].role))
        end
    end

    
    ---- SCORE section
	local scoreLabel = f:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
    scoreLabel:SetPoint("BOTTOM", sep1, "TOPRIGHT", 50, -5)
    scoreLabel:SetText("SCORE")
    scoreLabel:SetTextColor(1, 0.8, 0)

	local scoreNum = f:CreateFontString(nil, "OVERLAY", "GameFontHighlightHuge")
    scoreNum:SetPoint("TOP", scoreLabel, "BOTTOM", 0, -7) 
    scoreNum:SetFont(scoreNum:GetFont(), 18, "OUTLINE")

    if data.rioScore and data.rioScore > 0 then
        local r, g, b = self:GetScoreColor(data.rioScore)
        scoreNum:SetTextColor(r, g, b)
        scoreNum:SetText(data.rioScore)
    else
        scoreNum:SetTextColor(0.5, 0.5, 0.5)
        local noDataText = self.L and self.L["No data"] or "No data"
        scoreNum:SetText(noDataText)
        scoreNum:SetFont(scoreNum:GetFont(), 15, "OUTLINE")
    end
    

    ---- seperate bar 2
    local sep2 = f:CreateTexture(nil, "ARTWORK")
    sep2:SetSize(1, 30)
    sep2:SetColorTexture(1, 1, 1, 0.3)
    sep2:SetPoint("BOTTOMLEFT", factionIcon, "BOTTOMRIGHT", 180, -3)

    ---- Max dungeon chests
    if data.rioMaxLevel and data.rioMaxLevel ~= "" then
        local dungeonText = f:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
        dungeonText:SetPoint("BOTTOMLEFT", sep2, "BOTTOMRIGHT", 8, 3)
        dungeonText:SetText(data.rioMaxLevel .. " " .. (data.rioMaxDungeon or ""))
        
        local chestText = f:CreateFontString(nil, "OVERLAY", "GameFontNormal")
        chestText:SetPoint("BOTTOMLEFT", dungeonText, "TOPLEFT", 0, 0)
        
        local chestPlus = ""
        if data.rioMaxChests and data.rioMaxChests > 0 then
            for _ = 1, data.rioMaxChests do
                chestPlus = chestPlus .. "+"
            end
        end
        chestText:SetText("|cffA335EE" .. chestPlus .. "|r")
    end

    ---- raid progress
    if data.raidProgress then
        local raidText = f:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
        raidText:SetPoint("TOPRIGHT", -10, -10)
        local diffColor = self:GetDifficultyColor(data.raidProgress.difficulty)
        local raidAbbr = self.RAID_ID_ABBR[data.raidProgress.raidId] or "RAID"
        local raidFont, _, raidFlags = raidText:GetFont()
        if #raidAbbr > 5 then
            raidText:SetFont(raidFont, 11.5, raidFlags)
        else
            raidText:SetFont(raidFont, 13, raidFlags)
        end
        local bossIcon = "|A:UI-HUD-UnitFrame-Target-PortraitOn-Boss-Rare:18:18|a"
        
        raidText:SetText(string.format("|cff808080[%s]|r|cff%02x%02x%02x%s|r %d/%d %s", 
            raidAbbr, diffColor.r*255, diffColor.g*255, diffColor.b*255,
            self:GetDifficultyName(data.raidProgress.difficulty),
            data.raidProgress.progress, data.raidProgress.bossCount, bossIcon))
    end
    
    local isLeader = UnitIsGroupLeader("player")

    if isLeader then
        local declineBtn = CreateFrame("Button", nil, f, "UIPanelCloseButton")
        declineBtn:SetSize(24, 24)
        declineBtn:SetPoint("BOTTOMRIGHT", -5, 8)
        declineBtn:SetScript("OnClick", function() 
            C_LFGList.DeclineApplicant(data.applicantID) 
            NA:UpdateApplicants() 
        end)
        declineBtn:SetScript("OnEnter", function(self)
            GameTooltip:SetOwner(self, "ANCHOR_TOP")
            GameTooltip:SetText(NA.L["Decline"] or "Decline", 1, 0.2, 0.2)
            GameTooltip:Show()
        end)
        declineBtn:SetScript("OnLeave", function()
            GameTooltip:Hide()
        end)

        local inviteBtn = CreateFrame("Button", nil, f, "UIPanelButtonTemplate")
        inviteBtn:SetSize(50, 22)
        inviteBtn:SetPoint("RIGHT", declineBtn, "LEFT", -2, 0)
        inviteBtn:SetText(NA.L["Invite"] or "Invite")
        inviteBtn:SetNormalFontObject("GameFontNormalSmall")
        inviteBtn:SetScript("OnClick", function() 
            C_LFGList.InviteApplicant(data.applicantID) 
            NA:UpdateApplicants() 
        end)
        inviteBtn:SetScript("OnEnter", function(self)
            GameTooltip:SetOwner(self, "ANCHOR_TOP")
            GameTooltip:SetText(NA.L["Invite to party"] or "Invite to party", 0.2, 1, 0.2)
            GameTooltip:Show()
        end)
        inviteBtn:SetScript("OnLeave", function()
            GameTooltip:Hide()
        end)
    end

    return f
end