local addonName, RF = ...

-------------------------------------------------------------------------------
-- AltManager: Alt/Main character linking
-- Stored per-guild: guildDB.alts.links (alt->main) and guildDB.alts.mains (main->alts[])
-------------------------------------------------------------------------------

-------------------------------------------------------------------------------
-- Link an alt to a main
-------------------------------------------------------------------------------
function RF:LinkAlt(altName, mainName)
    local guildDB = RF:GetGuildDB()
    if not guildDB then
        RF:Print("Cannot link alts - not in a guild.")
        return false
    end

    if altName == mainName then
        RF:Print("Cannot link a character to itself.")
        return false
    end

    local alts = guildDB.alts

    -- If alt was previously a main, reassign its alts
    if alts.mains[altName] then
        for _, existingAlt in ipairs(alts.mains[altName]) do
            alts.links[existingAlt] = mainName
            if not alts.mains[mainName] then
                alts.mains[mainName] = {}
            end
            -- Add to new main's list if not already there
            local found = false
            for _, n in ipairs(alts.mains[mainName]) do
                if n == existingAlt then found = true; break end
            end
            if not found then
                tinsert(alts.mains[mainName], existingAlt)
            end
        end
        alts.mains[altName] = nil
    end

    -- Remove from previous main if linked elsewhere
    local prevMain = alts.links[altName]
    if prevMain and alts.mains[prevMain] then
        for i, n in ipairs(alts.mains[prevMain]) do
            if n == altName then
                tremove(alts.mains[prevMain], i)
                break
            end
        end
        -- Clean up empty main entry
        if #alts.mains[prevMain] == 0 then
            alts.mains[prevMain] = nil
        end
    end

    -- Create the link
    alts.links[altName] = mainName

    -- Record timestamp
    if not alts.timestamps then alts.timestamps = {} end
    alts.timestamps[altName] = time()

    -- Add to main's alt list
    if not alts.mains[mainName] then
        alts.mains[mainName] = {}
    end
    local found = false
    for _, n in ipairs(alts.mains[mainName]) do
        if n == altName then found = true; break end
    end
    if not found then
        tinsert(alts.mains[mainName], altName)
    end

    RF:AddLog("ALT_LINK", altName .. " linked as alt of " .. mainName)
    RF:Print("Linked " .. altName .. " as alt of " .. mainName .. ".")
    return true
end

-------------------------------------------------------------------------------
-- Unlink an alt
-------------------------------------------------------------------------------
function RF:UnlinkAlt(altName)
    local guildDB = RF:GetGuildDB()
    if not guildDB then return false end

    local alts = guildDB.alts
    local mainName = alts.links[altName]
    if not mainName then return false end

    -- Remove from main's list
    if alts.mains[mainName] then
        for i, n in ipairs(alts.mains[mainName]) do
            if n == altName then
                tremove(alts.mains[mainName], i)
                break
            end
        end
        if #alts.mains[mainName] == 0 then
            alts.mains[mainName] = nil
        end
    end

    alts.links[altName] = nil

    -- Record timestamp
    if not alts.timestamps then alts.timestamps = {} end
    alts.timestamps[altName] = time()

    RF:AddLog("ALT_UNLINK", altName .. " unlinked from " .. mainName)
    RF:Print(altName .. " unlinked from " .. mainName .. ".")
    return true
end

-------------------------------------------------------------------------------
-- Set a character as a main (unlink it if it was an alt)
-------------------------------------------------------------------------------
function RF:SetMain(name)
    local guildDB = RF:GetGuildDB()
    if not guildDB then return false end

    local alts = guildDB.alts

    -- If currently an alt, unlink
    if alts.links[name] then
        RF:UnlinkAlt(name)
    end

    -- Ensure main entry exists
    if not alts.mains[name] then
        alts.mains[name] = {}
    end

    RF:AddLog("SET_MAIN", name .. " set as main character")
    RF:Print(name .. " set as main character.")
    return true
end

-------------------------------------------------------------------------------
-- Get the main for a character (returns nil if already a main or unlinked)
-------------------------------------------------------------------------------
function RF:GetMainFor(name)
    local guildDB = RF:GetGuildDB()
    if not guildDB then return nil end
    return guildDB.alts.links[name]
end

-------------------------------------------------------------------------------
-- Get all alts for a main
-------------------------------------------------------------------------------
function RF:GetAltsForMain(mainName)
    local guildDB = RF:GetGuildDB()
    if not guildDB then return {} end
    return guildDB.alts.mains[mainName] or {}
end

-------------------------------------------------------------------------------
-- Check if a character is a main
-------------------------------------------------------------------------------
function RF:IsMain(name)
    local guildDB = RF:GetGuildDB()
    if not guildDB then return false end
    return guildDB.alts.mains[name] ~= nil
end

-------------------------------------------------------------------------------
-- Get all alt groups (for roster grouping display)
-------------------------------------------------------------------------------
function RF:GetAltGroups()
    local guildDB = RF:GetGuildDB()
    if not guildDB then return {} end

    local groups = {}
    for mainName, altList in pairs(guildDB.alts.mains) do
        groups[mainName] = { main = mainName, alts = altList }
    end
    return groups
end

-------------------------------------------------------------------------------
-- Get unlinked members at the configured alt rank
-------------------------------------------------------------------------------
function RF:GetUnlinkedAltRankMembers()
    local altRankIdx = RF.charDB and RF.charDB.altAutoRankIndex
    if not altRankIdx or not RF.rosterData then return {} end

    local guildDB = RF:GetGuildDB()
    if not guildDB then return {} end

    local alts = guildDB.alts
    local unlinked = {}
    for _, member in ipairs(RF.rosterData) do
        if member.rankIndex == altRankIdx then
            local name = member.name
            if not alts.links[name] and not alts.mains[name] then
                tinsert(unlinked, name)
            end
        end
    end
    return unlinked
end

-------------------------------------------------------------------------------
-- Auto-link all members at the alt rank by note matching
-- Scans public notes for main character names and links automatically.
-- Returns count of newly linked alts.
-------------------------------------------------------------------------------
function RF:AutoLinkByAltRank()
    local altRankIdx = RF.charDB and RF.charDB.altAutoRankIndex
    if not altRankIdx or not RF.rosterData then return 0 end

    local guildDB = RF:GetGuildDB()
    if not guildDB then return 0 end

    -- Build lookup of all roster names (case-insensitive)
    local nameLookup = {}
    for _, member in ipairs(RF.rosterData) do
        nameLookup[member.name:lower()] = member.name
    end

    local alts = guildDB.alts
    local linked = 0

    for _, member in ipairs(RF.rosterData) do
        if member.rankIndex == altRankIdx then
            local name = member.name
            -- Skip if already linked
            if not alts.links[name] and not alts.mains[name] then
                -- Try to find main name in public note
                local note = member.note or ""
                -- Match patterns like "Alt of Playername", "Main: Playername", or just a bare name
                local mainRef = note:match("[Aa]lt%s+of%s+(%S+)")
                    or note:match("[Mm]ain%s*:%s*(%S+)")
                    or note:match("[Mm]ain%s+(%S+)")
                if mainRef then
                    local mainName = nameLookup[mainRef:lower()]
                    if mainName and mainName ~= name then
                        RF:LinkAlt(name, mainName)
                        linked = linked + 1
                    end
                end
            end
        end
    end

    return linked
end
