---@class SUI
local SUI = SUI
local L = SUI.L

---@class SUI.DBM
local DBManager = {}
SUI.DBM = DBManager

---Calculate wildcard depth needed for nested defaults
---@param defaults table The defaults table to analyze
---@param maxDepth? number Maximum depth to check (default 10)
---@return number depth The nesting depth required
local function CalculateWildcardDepth(defaults, maxDepth)
	maxDepth = maxDepth or 10
	local function getDepth(tbl, currentDepth)
		if currentDepth >= maxDepth then
			return currentDepth
		end
		local maxChildDepth = currentDepth
		for _, v in pairs(tbl) do
			if type(v) == 'table' then
				local childDepth = getDepth(v, currentDepth + 1)
				maxChildDepth = math.max(maxChildDepth, childDepth)
			end
		end
		return maxChildDepth
	end
	return getDepth(defaults, 0)
end

---Build AceDB defaults table with wildcard nesting
---@param depth number Nesting depth (0-10)
---@return table wildcardTable The nested wildcard structure
local function BuildWildcardTable(depth)
	if depth <= 0 then
		return {}
	end
	return { ['**'] = BuildWildcardTable(depth - 1) }
end

---Setup a module's database with Configuration Override Pattern
---@param module table The module to setup DB for
---@param defaults table Default values (flat or nested)
---@param globalDefaults? table Global defaults (optional)
---@param options? table Options: { maxDepth: number, autoCalculateDepth: boolean }
function DBManager:SetupModule(module, defaults, globalDefaults, options)
	options = options or {}
	globalDefaults = globalDefaults or {}

	-- Calculate or use provided depth for profile
	local depth = options.maxDepth
	if not depth and options.autoCalculateDepth ~= false then
		depth = CalculateWildcardDepth(defaults)
		if module.logger then
			module.logger.debug('Auto-calculated profile wildcard depth: ' .. depth)
		end
	end
	depth = depth or 0

	-- Calculate depth for global defaults (if provided)
	local globalDepth = 0
	if next(globalDefaults) then
		globalDepth = CalculateWildcardDepth(globalDefaults)
		if module.logger then
			module.logger.debug('Auto-calculated global wildcard depth: ' .. globalDepth)
		end
	end

	-- Build AceDB registration structure with wildcards
	local aceDefaults = {
		profile = depth > 0 and BuildWildcardTable(depth) or {},
		global = globalDepth > 0 and BuildWildcardTable(globalDepth) or {},
	}

	-- Register namespace
	local moduleName = type(module.GetName) == 'function' and module:GetName() or module.moduleName or 'Unknown'
	module.Database = SUI.SpartanUIDB:RegisterNamespace(moduleName, aceDefaults)

	module.DB = module.Database.profile
	module.DBG = module.Database.global
	module.DBDefaults = defaults
	module.DBGlobalDefaults = globalDefaults
	module.CurrentSettings = {}

	-- Initialize global defaults (ensure tables exist)
	for key, defaultValue in pairs(globalDefaults) do
		if module.DBG[key] == nil and type(defaultValue) == 'table' then
			module.DBG[key] = {}
		end
	end

	-- Initial load
	self:RefreshSettings(module)
end

---Refresh CurrentSettings by merging defaults with user changes
---@param module table The module to refresh
function DBManager:RefreshSettings(module)
	-- Start with copy of defaults
	module.CurrentSettings = SUI:CopyData({}, module.DBDefaults)
	-- Merge user settings over defaults (override mode)
	module.CurrentSettings = SUI:MergeData(module.CurrentSettings, module.DB, true)
end

---Standard setter for options - writes to DB and refreshes
---@param module table The module
---@param key string|string[] DB key to set (can be nested path like "minimap.hide")
---@param value any Value to set
---@param callback? function Optional callback after refresh
function DBManager:Set(module, key, value, callback)
	-- Handle nested keys: "minimap.hide" -> DB.minimap.hide
	if type(key) == 'string' and key:find('%.') then
		local keys = {}
		for k in key:gmatch('[^%.]+') do
			table.insert(keys, k)
		end

		local target = module.DB
		for i = 1, #keys - 1 do
			local k = keys[i]
			if not target[k] then
				target[k] = {}
			end
			target = target[k]
		end
		target[keys[#keys]] = value
	else
		module.DB[key] = value
	end

	self:RefreshSettings(module)
	if callback then
		callback()
	end
end

---Get a value from CurrentSettings (convenience helper)
---@param module table The module
---@param key string|string[] Setting key (can be nested path)
---@return any value The setting value
function DBManager:Get(module, key)
	if type(key) == 'string' and key:find('%.') then
		local target = module.CurrentSettings
		for k in key:gmatch('[^%.]+') do
			if type(target) ~= 'table' then
				return nil
			end
			target = target[k]
		end
		return target
	else
		return module.CurrentSettings[key]
	end
end
