local NS = rawget(_G, "MCDVoiceCooldownNS") or {}
_G.MCDVoiceCooldownNS = NS

NS.Core = NS.Core or {}
NS.Core.Database = NS.Core.Database or {}

local Database = NS.Core.Database
local LibStubGlobal = rawget(_G, "LibStub")

local defaults = {
    profile = {
        specConfigs = {},
        castSuccessConfigs = {},
        bloodlustConfig = {
            customSoundPaths = { "", "", "", "", "" },
        },
        minimap = {
            angle = 225,
            radius = 80,
            hide = false,
        },
        collectionData = {},
        collectionSerial = 0,
        deletedEntries = {},
    },
}

local function CopyMissingTables(target, source)
    if type(target) ~= "table" or type(source) ~= "table" then
        return
    end
    if target == source then
        return
    end

    local visited = {}
    local stack = {
        {
            target = target,
            source = source,
        },
    }

    while #stack > 0 do
        local item = table.remove(stack)
        local itemTarget = item.target
        local itemSource = item.source

        if type(itemTarget) == "table" and type(itemSource) == "table" and itemTarget ~= itemSource and not visited[itemSource] then
            visited[itemSource] = true
            for key, value in pairs(itemSource) do
                if type(value) == "table" then
                    if type(itemTarget[key]) ~= "table" then
                        itemTarget[key] = {}
                    end
                    stack[#stack + 1] = {
                        target = itemTarget[key],
                        source = value,
                    }
                elseif itemTarget[key] == nil then
                    itemTarget[key] = value
                end
            end
        end
    end
end

local function CopyKnownSavedFields(target, source)
    if type(target) ~= "table" or type(source) ~= "table" then
        return
    end

    local sourceProfile = type(source.profile) == "table" and source.profile or source
    for _, key in ipairs({ "specConfigs", "castSuccessConfigs", "bloodlustConfig", "minimap", "collectionData", "deletedEntries" }) do
        if type(sourceProfile[key]) == "table" then
            if type(target[key]) ~= "table" then
                target[key] = {}
            end
            CopyMissingTables(target[key], sourceProfile[key])
        elseif sourceProfile[key] ~= nil and target[key] == nil then
            target[key] = sourceProfile[key]
        end
    end
    if type(sourceProfile.collectionSerial) == "number" and type(target.collectionSerial) ~= "number" then
        target.collectionSerial = sourceProfile.collectionSerial
    end
end

function Database:Initialize()
    if self.initialized then
        return self.db
    end
    self.initialized = true

    local legacy = (type(MCDVoiceCooldownDB) == "table") and MCDVoiceCooldownDB or {}
    local aceDB = nil

    if type(LibStubGlobal) == "table" then
        local AceDB = LibStubGlobal:GetLibrary("AceDB-3.0", true)
        if AceDB then
            aceDB = AceDB:New("MCDVoiceCooldownDB", defaults, true)
        end
    end

    if aceDB and type(aceDB.profile) == "table" then
        CopyKnownSavedFields(aceDB.profile, legacy)
        MCDVoiceCooldownDB = aceDB.profile
        self.db = aceDB
        return aceDB
    end

    CopyMissingTables(legacy, {
        specConfigs = {},
        castSuccessConfigs = {},
        bloodlustConfig = {
            customSoundPaths = { "", "", "", "", "" },
        },
        minimap = {
            angle = 225,
            radius = 80,
            hide = false,
        },
        collectionData = {},
        collectionSerial = 0,
        deletedEntries = {},
    })
    MCDVoiceCooldownDB = legacy
    self.db = nil
    return nil
end
