-- New Applicants!! - Core Logic
-- Version: 1.1.1

local ADDON_NAME = "NewApplicants"
local NA = _G[ADDON_NAME] or {}
_G[ADDON_NAME] = NA

-- Default Settings
local defaults = {
    position = { point = "CENTER", x = 0, y = 200 },
    maxDisplay = 3,
    soundEnabled = true,
    showCards = true,
    playOnRaid = true,
    showCardsOnRaid = false,
    soundOnlyActive = false,
    cardOnlyActive = false,
    backgroundAlpha = 0.8,
    scale = 1.0,
    isLocked = false
}

-- Raid Abbreviations
NA.RAID_ID_ABBR = {
    [16340] = "VS/DR/MQD",
    --[16531] = "DR",
    --[16342] = "MQD",
    [16178] = "MFO",
    [15522] = "LOU", 
    [14980] = "NP",
}

-- Initialize
function NA:Initialize()
    NewApplicantsDB = NewApplicantsDB or {}
    self.db = NewApplicantsDB
    
    -- Merge defaults
    for k, v in pairs(defaults) do
        if self.db[k] == nil then
            if type(v) == "table" then
                self.db[k] = {}
                for k2, v2 in pairs(v) do
                    self.db[k][k2] = v2
                end
            else
                self.db[k] = v
            end
        end
    end
    
    self.applicantDataList = {}
    self.lastApplicantCount = 0
    
    self:RegisterEvents()
end

-- Register Events
function NA:RegisterEvents()
    local eventFrame = CreateFrame("Frame")
    eventFrame:RegisterEvent("LFG_LIST_APPLICANT_UPDATED")
    eventFrame:RegisterEvent("LFG_LIST_APPLICANT_LIST_UPDATED")
    eventFrame:RegisterEvent("PLAYER_ENTERING_WORLD")

    eventFrame:SetScript("OnEvent", function(_, event)
        if event == "LFG_LIST_APPLICANT_UPDATED" or event == "LFG_LIST_APPLICANT_LIST_UPDATED" then
            NA:UpdateApplicants()
        elseif event == "PLAYER_ENTERING_WORLD" then
            C_Timer.After(1, function()
                NA:UpdateApplicants()
            end)
        end
    end)
    
    self.eventFrame = eventFrame
end

-- Update Applicants
function NA:UpdateApplicants()
    local applicants = C_LFGList.GetApplicants() or {}
    self.applicantDataList = {}
    
    local activeEntryInfo = C_LFGList.GetActiveEntryInfo()
    local activityID = activeEntryInfo and activeEntryInfo.activityID
    
    for i, applicantID in ipairs(applicants) do
        local applicantInfo = C_LFGList.GetApplicantInfo(applicantID)
        if applicantInfo and applicantInfo.applicationStatus == "applied" then
            local data = self:ProcessApplicantData(applicantID, applicantInfo.numMembers, i, activityID)
            if data then
                table.insert(self.applicantDataList, data)
            end
        end
    end
    
    local isRaidListing = false
    if activeEntryInfo and activeEntryInfo.activityIDs and activeEntryInfo.activityIDs[1] then
        local activityInfo = C_LFGList.GetActivityInfoTable(activeEntryInfo.activityIDs[1])
        if activityInfo and activityInfo.isCurrentRaidActivity then
            isRaidListing = true
        end
    end
    self.isRaidListing = isRaidListing
    self.hasActiveListing = activeEntryInfo ~= nil

    -- Play sound if new applicants
    local soundBlocked = isRaidListing and not self.db.playOnRaid
    local soundActiveBlocked = self.db.soundOnlyActive and not self.hasActiveListing
    if self.db.soundEnabled and not soundBlocked and not soundActiveBlocked and #self.applicantDataList > self.lastApplicantCount then
        PlaySoundFile("Interface\\AddOns\\NewApplicants\\Sounds\\Xylophone_alarm.mp3", "Master")
    end
    
    self.lastApplicantCount = #self.applicantDataList
    
    -- Update UI if it exists
    if self.UpdateDisplay then
        self:UpdateDisplay()
    end
end

-- Process Applicant Data
function NA:ProcessApplicantData(applicantID, numMem, applicantIndex, activityID)
    local name, class, localizedClass, _, itemLevel, _, tank, healer, damage, _, relationship, dungeonScore, _, factionGroup =
        C_LFGList.GetApplicantMemberInfo(applicantID, 1)
    
    if not name then return nil end
    
    local charName, serverName = strsplit("-", name)
    serverName = serverName or GetRealmName()
    local fullName = charName .. "-" .. serverName
    
    local blizzardScore = 0
    if activityID and applicantIndex then
        blizzardScore = C_LFGList.GetApplicantDungeonScoreForListing(applicantID, applicantIndex, activityID) or 0
    end
    
    local finalDungeonScore = math.max(dungeonScore or 0, blizzardScore)    
    local activeFaction = (factionGroup == 1) and "alliance" or "horde"
    
    -- Get RIO data
    local rioScore = self:GetRioScore(fullName, activeFaction, finalDungeonScore)
    local rioMaxDungeon, rioMaxLevel, rioMaxChests = self:GetMaxDungeonInfo(fullName, activeFaction)
    local rioRoles = self:GetRioRoles(fullName, activeFaction)
    local raidProgress = self:GetRaidProgress(fullName, activeFaction)
    
    return {
        applicantID = applicantID,
        charName = charName,
        serverName = serverName,
        fullName = fullName,
        class = class,
        localizedClass = localizedClass,
        itemLevel = itemLevel,
        numMembers = numMem,
        tank = tank,
        healer = healer,
        damage = damage,
        relationship = relationship,
        dungeonScore = dungeonScore,
        factionGroup = factionGroup,
        activeFaction = activeFaction,
        rioScore = rioScore,
        rioMaxDungeon = rioMaxDungeon,
        rioMaxLevel = rioMaxLevel,
        rioMaxChests = rioMaxChests,
        rioRoles = rioRoles,
        raidProgress = raidProgress
    }
end

-- RaiderIO Functions
function NA:GetRioScore(fullName, activeFaction, dungeonScore)
    local score = dungeonScore or 0
    
    if not RaiderIO then
        return score
    end
    
    local playerProfile = RaiderIO.GetProfile(fullName, activeFaction)
    if playerProfile and playerProfile.mythicKeystoneProfile then
        local currentScore = playerProfile.mythicKeystoneProfile.currentScore or 0
        if currentScore > score then
            score = currentScore
        end
    end
    
    return score
end

function NA:GetMaxDungeonInfo(fullName, activeFaction)
    if not RaiderIO then
        return "N/A", "", ""
    end
    
    local playerProfile = RaiderIO.GetProfile(fullName, activeFaction)
    local mplusProfile = playerProfile and playerProfile.mythicKeystoneProfile
    
    if mplusProfile and mplusProfile.maxDungeon and mplusProfile.maxDungeonLevel then
        local maxDungeonData = mplusProfile.maxDungeon
        local maxLevel = mplusProfile.maxDungeonLevel
        
        if maxDungeonData.shortNameLocale and maxLevel > 0 then
            local chests = 0
            local sortedDungeons = mplusProfile.sortedDungeons or {}
            for _, run in ipairs(sortedDungeons) do
                if run.dungeon and run.dungeon.id == maxDungeonData.id and run.level == maxLevel then
                    chests = run.chests
                    break
                end
            end
            return maxDungeonData.shortNameLocale, maxLevel, chests
        end
    end
    
    return "N/A", "", ""
end

function NA:GetRioRoles(fullName, activeFaction)
    if not RaiderIO then return {} end
    
    local playerProfile = RaiderIO.GetProfile(fullName, activeFaction)
    local rioRoles = playerProfile and playerProfile.mythicKeystoneProfile 
        and playerProfile.mythicKeystoneProfile.mplusCurrent 
        and playerProfile.mythicKeystoneProfile.mplusCurrent.roles
    
    if type(rioRoles) ~= "table" then return {} end
    
    local specs = {}
    for i = 1, math.min(2, #rioRoles) do
        local roleInfo = rioRoles[i]
        if type(roleInfo) == "table" and roleInfo[1] and roleInfo[2] then
            table.insert(specs, { role = roleInfo[1], spec = roleInfo[2] })
        end
    end
    return specs
end

function NA:GetRaidProgress(fullName, activeFaction)
    if not RaiderIO then return nil end
    
    local progress = 0
    local difficulty = 0
    local bossCount = 0
    local raidId = nil
    
    local playerProfile = RaiderIO.GetProfile(fullName, activeFaction)
    if playerProfile and playerProfile.raidProfile and playerProfile.raidProfile.sortedProgress then
        local profileProgress = playerProfile.raidProfile.sortedProgress
        
        for i = 1, #profileProgress do
            if profileProgress[i].isMainProgress ~= true then
                local tempProg = profileProgress[i].progress
                
                local isSameDifficulty = tempProg.difficulty == difficulty
                local isProgUpgrade = tempProg.progressCount > progress and isSameDifficulty
                local isDiffUpgrade = tempProg.difficulty > difficulty
                local isNotObsolete = profileProgress[i].obsolete ~= true
                
                if (isProgUpgrade or isDiffUpgrade) and isNotObsolete then
                    progress = tempProg.progressCount or 0
                    bossCount = (tempProg.raid and tempProg.raid.bossCount) or 0
                    difficulty = tempProg.difficulty or 1
                    raidId = (tempProg.raid and (tempProg.raid.id or tempProg.raid.zoneId)) or tempProg.raidId
                end
            end
        end
    end
    
    if progress > 0 then
        return {
            progress = progress,
            bossCount = bossCount,
            difficulty = difficulty,
            raidId = raidId
        }
    end
    
    return nil
end

-- Helper Functions
function NA:GetScoreColor(score)
    local r, g, b = 1, 1, 1
    if RaiderIO then
        r, g, b = RaiderIO.GetScoreColor(score)
    else
        local color = C_ChallengeMode.GetDungeonScoreRarityColor(score)
        if color then
            r, g, b = color:GetRGB()
        end
    end
    return r, g, b
end

function NA:GetDifficultyColor(difficulty)
    local colors = {
        [1] = { r = 0, g = 0.5, b = 1 },      -- Normal (blue)
        [2] = { r = 0.78, g = 0, b = 1 },     -- Heroic (purple)
        [3] = { r = 1, g = 0.5, b = 0 },      -- Mythic (orange)
    }
    return colors[difficulty] or { r = 1, g = 1, b = 1 }
end

function NA:GetDifficultyName(difficulty)
    local L = self.L or {}
    local names = {
        [1] = L["Normal"] or "N",
        [2] = L["Heroic"] or "H",
        [3] = L["Mythic"] or "M",
    }
    return names[difficulty] or (L["Unknown"] or "LFR")
end

function NA:GetRoleAtlas(spec, role)
    local alias = (spec or "") .. (role or "")
    local atlasMap = {
        fulltank = "UI-LFG-RoleIcon-Tank",
        fulldps = "UI-LFG-RoleIcon-DPS",
        fullhealer = "UI-LFG-RoleIcon-Healer",
        partialtank = "UI-LFG-RoleIcon-Tank-Disabled",
        partialdps = "UI-LFG-RoleIcon-DPS-Disabled",
        partialhealer = "UI-LFG-RoleIcon-Healer-Disabled",
    }
    return atlasMap[alias]
end

function NA:GetClassFrameTexture(class)
    local classLower = string.lower(class or "")
    local texturePath = "Interface\\AddOns\\NewApplicants\\Textures\\Frame_" .. classLower .. ".png"
    return texturePath
end

function NA:OpenLFGFrame()
    PVEFrame_ToggleFrame("GroupFinderFrame")
    
    local function gotoPremade()
        if GroupFinderFrame and GroupFinderFrameGroupButton3 and GroupFinderFrameGroupButton3:IsEnabled() then
            GroupFinderFrameGroupButton3:Click()
            return true
        end
        return false
    end
    
    if not gotoPremade() then
        local attempts = 0
        local ticker
        ticker = C_Timer.NewTicker(0.05, function()
            attempts = attempts + 1
            if gotoPremade() or attempts >= 20 then
                ticker:Cancel()
            end
        end)
    end
end

-- Test Data
function NA:LoadTestData()
    self.applicantDataList = {
        {
            applicantID = 0,
            charName = "TestDPS",
            serverName = "Realm",
            fullName = "TestDPS-Realm",
            class = "MAGE",
            localizedClass = "Mage",
            itemLevel = 639.5,
            numMembers = 1,
            tank = false, healer = false, damage = true,
            factionGroup = 0,
            activeFaction = "horde",
            rioScore = 3250,
            rioMaxDungeon = "GB", rioMaxLevel = 12, rioMaxChests = 2,
            rioRoles = { { spec = "full", role = "dps" }, { spec = "partial", role = "healer" } },
            raidProgress = { progress = 6, bossCount = 8, difficulty = 3, raidId = 16340 },
        },
        {
            applicantID = 0,
            charName = "GroupApplicant",
            serverName = "Realm",
            fullName = "GroupApplicant-Realm",
            class = "PALADIN",
            localizedClass = "Paladin",
            itemLevel = 625.0,
            numMembers = 3,
            tank = true, healer = false, damage = false,
            factionGroup = 1,
            activeFaction = "alliance",
            rioScore = 1870,
            rioMaxDungeon = "NW", rioMaxLevel = 9, rioMaxChests = 1,
            rioRoles = { { spec = "full", role = "tank" } },
            raidProgress = { progress = 3, bossCount = 8, difficulty = 2, raidId = 16178 },
        },
        {
            applicantID = 0,
            charName = "AVeryLongCharacterName",
            serverName = "AVeryLongServerName",
            fullName = "AVeryLongCharacterName-AVeryLongServerName",
            class = "WARRIOR",
            localizedClass = "Warrior",
            itemLevel = 610.0,
            numMembers = 2,
            tank = false, healer = false, damage = true,
            factionGroup = 0,
            activeFaction = "horde",
            rioScore = 0,
            rioMaxDungeon = "N/A", rioMaxLevel = "", rioMaxChests = 0,
            rioRoles = {},
            raidProgress = nil,
        },
    }
    self.isRaidListing = false
    if self.UpdateDisplay then
        self:UpdateDisplay()
    end
end

-- Slash commands
SLASH_NEWAPPLICANT1 = "/na"
SlashCmdList["NEWAPPLICANT"] = function(msg)
    msg = string.lower(msg or "")
    if msg == "test" then
        NA:LoadTestData()
        print("|cFFFF6B6BNew Applicants!!|r Test cards loaded.")
    else
        NA:ShowSettingsPanel()
    end
end

-- Initialize on load
local initFrame = CreateFrame("Frame")
initFrame:RegisterEvent("ADDON_LOADED")
initFrame:SetScript("OnEvent", function(self, _, addon)
    if addon == ADDON_NAME then
        NA:Initialize()
        self:UnregisterEvent("ADDON_LOADED")
    end
end)
