local LibStub = LibStub
local MAJOR, MINOR = "LibAceConfigAPI", 3
local LibAceConfigAPI, oldminor = LibStub:NewLibrary(MAJOR, MINOR)

if not LibAceConfigAPI then return end

LibAceConfigAPI.optionOrder = LibAceConfigAPI.optionOrder or 0

local function getOrder()
	LibAceConfigAPI.optionOrder = LibAceConfigAPI.optionOrder + 1
	return LibAceConfigAPI.optionOrder
end

function LibAceConfigAPI:createGroup(name, desc, childGroups, disabled, hidden)
    return {
        type = "group",
        childGroups = childGroups,
        name = name,
        desc = desc,
        order = getOrder(),
        args = {},
        hidden = hidden,
        disabled = disabled,
    }
end

function LibAceConfigAPI:createHeader(name, hidden)
    return {
        type = "header",
        name = name,
        order = getOrder(),
        hidden = hidden,
    }
end

function LibAceConfigAPI:createDescription(name, hidden)
    return {
        type = "description",
        name = name,
        order = getOrder(),
        hidden = hidden,
    }
end

function LibAceConfigAPI:createInput(name, desc, arg, width, disabled, hidden)
    return {
        type = "input",
        name = name,
        desc = desc,
        order = getOrder(),
        arg = arg,
        width = width,
        disabled = disabled,
        hidden = hidden,
    }
end

function LibAceConfigAPI:createRange(name, desc, arg, mms, width, disabled, hidden)
    return {
        type = "range",
        name = name,
        desc = desc,
        order = getOrder(),
        min = mms[1], max = mms[2], step = mms[3],
        arg = arg,
        width = width,
        disabled = disabled,
        hidden = hidden,
    }
end

function LibAceConfigAPI:createSharedMediaFontSelect(name, desc, arg, values, width, disabled, hidden)
    return self:createSharedMediaSelect("LSM30_Font", name, desc, arg, values, width, disabled, hidden)
end

function LibAceConfigAPI:createSharedMediaSoundSelect(name, desc, arg, values, width, disabled, hidden)
    return self:createSharedMediaSelect("LSM30_Sound", name, desc, arg, values, width, disabled, hidden)
end

function LibAceConfigAPI:createSharedMediaStatusbarSelect(name, desc, arg, values, width, disabled, hidden)
    return self:createSharedMediaSelect("LSM30_Statusbar", name, desc, arg, values, width, disabled, hidden)
end

function LibAceConfigAPI:createSharedMediaBackgroundSelect(name, desc, arg, values, width, disabled, hidden)
    return self:createSharedMediaSelect("LSM30_Background", name, desc, arg, values, width, disabled, hidden)
end

function LibAceConfigAPI:createSharedMediaBorderSelect(name, desc, arg, values, width, disabled, hidden)
    return self:createSharedMediaSelect("LSM30_Border", name, desc, arg, values, width, disabled, hidden)
end

function LibAceConfigAPI:createSharedMediaSelect(type, name, desc, arg, values, width, disabled, hidden)
    return {
        type = "select",
        dialogControl = type,
        name = name,
        desc = desc,
        order = getOrder(),
        values = values,
        arg = arg,
        width = width,
        disabled = disabled,
        hidden = hidden,
    }
end

function LibAceConfigAPI:createSelect(name, desc, arg, values, width, disabled, hidden)
    return {
        type = "select",
        name = name,
        desc = desc,
        order = getOrder(),
        values = values,
        arg = arg,
        width = width,
        disabled = disabled,
        hidden = hidden,
    }
end

function LibAceConfigAPI:createToggle(name, desc, arg, width, disabled, hidden)
    return {
        type = "toggle",
        name = name,
        desc = desc,
        order = getOrder(),
        arg = arg,
        width = width,
        disabled = disabled,
        hidden = hidden,
    }
end

function LibAceConfigAPI:createExecute(name, desc, arg, func, confirm, width, disabled, hidden)
    return {
        type = "execute",
        name = name,
        desc = desc,
        order = getOrder(),
        arg = arg,
        func = func,
        width = width,
        disabled = disabled,
        hidden = hidden,
        confirm = confirm and true,
        confirmText = confirm,
    }
end

function LibAceConfigAPI:createColor(name, desc, arg, alpha, width, disabled, hidden)
    return {
        type = "color",
        name = name,
        desc = desc,
        order = getOrder(),
        hasAlpha = alpha,
        arg = arg,
        width = width,
        disabled = disabled,
        hidden = hidden,
    }
end

function LibAceConfigAPI:injectSetGet(obj, set, get)
    obj.set = set
    obj.get = get
end

function LibAceConfigAPI:buildSetGet(callback, obj, db, ...)
   self:injectSetGet(obj, self:buildSetter(callback, db, ...), self:buildGetter(db, ...)) 
end

local function getDB(db, path)
	local db = db.profile
	for _, value in pairs(path) do
		db = db[value]
	end
	return db
end

function LibAceConfigAPI:buildGetter(db, ...)
	local path = {...}
	return function(key)
		local db = getDB(db, path)
		if key.type == "input" then
			return tostring(db[key.arg])
		end
		return db[key.arg]
	end
end

function LibAceConfigAPI:buildSetter(callback, db, ...)
	local path = {...}
	return function (key, value)
		local db = getDB(db, path)
		if key.type == "input" then
			if not (tonumber(value) == nil) then
				value = tonumber(value)
			end
		end
		db[key.arg] = value
		if callback ~= nil then
			callback(key.arg)
		end
	end
end
