GuildHelper = GuildHelper or {}

local addon = GuildHelper

local SAVED_DB_CANDIDATES = {
    "GH3DB",
    "GuildHelperDB",
}

local function mergeDefaults(target, defaults)
    for key, value in pairs(defaults) do
        if type(value) == "table" then
            if type(target[key]) ~= "table" then
                target[key] = {}
            end

            mergeDefaults(target[key], value)
        elseif target[key] == nil then
            target[key] = value
        end
    end
end

local function trimString(value)
    return string.match(tostring(value or ""), "^%s*(.-)%s*$") or ""
end

local function resolveSavedDatabase()
    for _, globalName in ipairs(SAVED_DB_CANDIDATES) do
        if type(_G[globalName]) == "table" then
            return _G[globalName], globalName
        end
    end

    return nil, nil
end

local function bindSavedDatabase(db)
    for _, globalName in ipairs(SAVED_DB_CANDIDATES) do
        _G[globalName] = db
    end

    return db
end

local function normalizeRealmName(value, fallbackRealm)
    local realmName = trimString(value)

    if realmName == "" then
        realmName = trimString(fallbackRealm)
    end

    if realmName == "" then
        return nil
    end

    if not realmName:find("-", 1, true) then
        return realmName
    end

    local tokens = {}

    for token in string.gmatch(realmName, "([^-]+)") do
        tokens[#tokens + 1] = token
    end

    if #tokens == 0 then
        return realmName
    end

    local collapsedRealm = tokens[1]

    for index = 2, #tokens do
        if tokens[index] ~= collapsedRealm then
            return table.concat(tokens, "-", index)
        end
    end

    return collapsedRealm
end

addon.Store = addon.Store or {}

function addon.Store:NormalizeRealmName(value, fallbackRealm)
    return normalizeRealmName(value, fallbackRealm or GetRealmName() or "Unknown")
end

function addon.Store:NormalizeFullName(fullName, fallbackRealm)
    local normalized = trimString(fullName)

    if normalized == "" then
        return ""
    end

    local name, realm = string.match(normalized, "^([^-]+)%-(.+)$")

    if not name then
        local resolvedRealm = self:NormalizeRealmName(fallbackRealm or GetRealmName() or "Unknown")
        return resolvedRealm and (normalized .. "-" .. resolvedRealm) or normalized
    end

    local resolvedRealm = self:NormalizeRealmName(realm, fallbackRealm or GetRealmName() or "Unknown")
    return resolvedRealm and (name .. "-" .. resolvedRealm) or name
end

function addon.Store:SplitFullName(fullName, fallbackRealm)
    local normalized = self:NormalizeFullName(fullName, fallbackRealm)
    local name, realm = string.match(normalized, "^([^-]+)%-(.+)$")

    return name or normalized or "Unknown", realm or self:NormalizeRealmName(fallbackRealm or GetRealmName() or "Unknown") or "Unknown"
end

function addon.Store:IsLikelyPlayerFullName(fullName, fallbackRealm)
    local normalized = self:NormalizeFullName(fullName, fallbackRealm or GetRealmName() or "Unknown")

    if normalized == "" then
        return false, normalized
    end

    local name, realm = self:SplitFullName(normalized, fallbackRealm or GetRealmName() or "Unknown")
    local normalizedName = string.lower(trimString(name))
    local normalizedRealm = string.lower(trimString(realm))

    if normalizedName == "" or normalizedName == "unknown" then
        return false, normalized
    end

    if string.find(name, "%s") then
        return false, normalized
    end

    if normalizedRealm == "" or normalizedRealm == "unknown" then
        return false, normalized
    end

    return true, normalized
end

function addon.Store:IsReady()
    local db = self.db or resolveSavedDatabase()
    return type(db) == "table" and type(db.guild) == "table" and type(db.sync) == "table" and type(db.profile) == "table"
end

function addon.Store:Initialize()
    local defaults = addon.Schema:CreateDefaults()
    local db = resolveSavedDatabase()

    if type(db) ~= "table" then
        db = defaults
    else
        mergeDefaults(db, defaults)
    end

    db.schemaVersion = defaults.schemaVersion
    self.db = bindSavedDatabase(db)
    self:EnsureHomeGuild()
end

function addon.Store:GetDB()
    local db = self.db or resolveSavedDatabase()

    if type(db) == "table" then
        self.db = bindSavedDatabase(db)
        return self.db
    end

    return self.db
end

function addon.Store:GetProfile()
    return self:GetDB().profile
end

function addon.Store:GetGuild()
    return self:GetDB().guild
end

function addon.Store:GetSync()
    return self:GetDB().sync
end

function addon.Store:GetMyToons()
    local sync = self:GetSync()

    if type(sync.mytoons) ~= "table" then
        sync.mytoons = {}
    end

    return sync.mytoons
end

function addon.Store:GetMythics()
    local sync = self:GetSync()

    if type(sync.mythics) ~= "table" then
        sync.mythics = {}
    end

    return sync.mythics
end

function addon.Store:GetBis()
    local profile = self:GetProfile()

    if type(profile.bis) ~= "table" then
        profile.bis = {}
    end

    return profile.bis
end

function addon.Store:GetPlayerName()
    local playerName = UnitName("player") or "Unknown"
    local realmName = GetRealmName() or "Unknown"

    return self:NormalizeFullName(playerName, realmName)
end

function addon.Store:GetGuildKey()
    local guildName, _, _, guildRealm = GetGuildInfo("player")
    local realmName = self:NormalizeRealmName(guildRealm, GetRealmName())

    if not guildName or guildName == "" or not realmName or realmName == "" then
        return nil
    end

    return guildName .. "-" .. realmName
end

function addon.Store:GetDisplayGuildKey()
    return self:GetGuild().federation.homeGuild
        or self:GetGuildKey()
        or ("Unguilded-" .. (GetRealmName() or "Unknown"))
end

function addon.Store:EnsureHomeGuild()
    local guildKey = self:GetGuildKey()

    if guildKey and guildKey ~= "" then
        self:GetGuild().federation.homeGuild = guildKey
        return guildKey
    end

    return self:GetGuild().federation.homeGuild
end

function addon.Store:GetActiveGuildKeys()
    local federation = self:GetGuild().federation
    local keys = {}
    local seen = {}

    if federation.homeGuild then
        seen[federation.homeGuild] = true
        table.insert(keys, federation.homeGuild)
    end

    local liveGuildKey = not federation.homeGuild and self:GetGuildKey() or nil

    if liveGuildKey and not seen[liveGuildKey] then
        seen[liveGuildKey] = true
        table.insert(keys, liveGuildKey)
    end

    for _, guildRecord in ipairs(federation.linkedGuilds) do
        local guildKey = guildRecord.guildKey or guildRecord.name

        if guildKey and not seen[guildKey] and (not addon.FederationService or not addon.FederationService.IsApprovedLinkedGuild or addon.FederationService:IsApprovedLinkedGuild(guildKey)) then
            seen[guildKey] = true
            table.insert(keys, guildKey)
        end
    end

    return keys
end
