local E, L, V, P, G = unpack(ElvUI)
local MC = E:GetModule('ModuleCopy')

local pairs, next, type = pairs, next, type
local format, error = format, error
-- GLOBALS: ElvDB

--This table to reserve settings names in E.global.profileCopy. Used in export/imports functions
--Plugins can add own values for their internal settings for safechecks here
MC.InternalOptions = {
	selected = true,
	movers = true,
}

local ToggleSkins -- so it can call itself
ToggleSkins = function(tbl, key, value)
	if key ~= 'selected' then
		local setting = tbl[key]
		if type(setting) == 'table' then
			for subkey in pairs(setting) do
				ToggleSkins(setting, subkey, value)
			end
		else
			tbl[key] = value
		end
	end
end

local function DefaultOptions(tbl, section, pluginSection)
	if pluginSection then
		if not tbl[pluginSection] then
			tbl[pluginSection] = {}
		end
		if not tbl[pluginSection][section] then
			tbl[pluginSection][section] = {}
		end
	elseif not tbl[section] then
		tbl[section] = {}
	end
end

local function DefaultMovers(tbl, section, subSection)
	if not tbl[section] then
		tbl[section] = {}
	end

	if subSection and tbl[section][subSection] == nil then
		tbl[section][subSection] = false
	end
end

--Default template for a config group for a single module.
--Contains header, general group toggle (shown only if the setting actually exists) and imports button.
--Usage as seen in ElvUI_Options\modulecopy.lua
function MC:CreateModuleConfigGroup(Name, section, pluginSection)
	local config = {
		order = 10,
		type = 'group',
		name = Name,
		args = {
			general = {
				order = 1,
				type = 'toggle',
				name = function()
					E.Options.args.profiles.args.modulecopy.args.import.func = function()
						E.PopupDialogs.MODULE_COPY_CONFIRM.text = format(L["You are going to copy settings for |cffD3CF00\"%s\"|r from |cff4beb2c\"%s\"|r profile to your current |cff4beb2c\"%s\"|r profile. Are you sure?"], Name, E.global.profileCopy.selected, ElvDB.profileKeys[E.mynameRealm])
						E.PopupDialogs.MODULE_COPY_CONFIRM.OnAccept = function()
							MC:ImportFromProfile(section, pluginSection)
						end
						E:StaticPopup_Show('MODULE_COPY_CONFIRM')
					end

					E.Options.args.profiles.args.modulecopy.args.export.func = function()
						E.PopupDialogs.MODULE_COPY_CONFIRM.text = format(L["You are going to copy settings for |cffD3CF00\"%s\"|r from your current |cff4beb2c\"%s\"|r profile to |cff4beb2c\"%s\"|r profile. Are you sure?"], Name, ElvDB.profileKeys[E.mynameRealm], E.global.profileCopy.selected)
						E.PopupDialogs.MODULE_COPY_CONFIRM.OnAccept = function()
							MC:ExportToProfile(section, pluginSection)
						end
						E:StaticPopup_Show('MODULE_COPY_CONFIRM')
					end

					local selection = (pluginSection and E.global.profileCopy[pluginSection]) or E.global.profileCopy
					E.Options.args.profiles.args.modulecopy.args.clear.func = function() ToggleSkins(selection, section, false) end
					E.Options.args.profiles.args.modulecopy.args.select.func = function() ToggleSkins(selection, section, true) end

					return L["General"]
				end,
			},
		},
	}

	DefaultOptions(G.profileCopy, section, pluginSection) -- defaults
	DefaultOptions(E.global.profileCopy, section, pluginSection) -- from profile

	if pluginSection then
		config.args.general.hidden = function(info) return E.global.profileCopy[pluginSection][section][ info[#info] ] == nil end
		config.get = function(info) return E.global.profileCopy[pluginSection][section][ info[#info] ] end
		config.set = function(info, value) E.global.profileCopy[pluginSection][section][ info[#info] ] = value end
	else
		config.args.general.hidden = function(info) return E.global.profileCopy[section][ info[#info] ] == nil end
		config.get = function(info) return E.global.profileCopy[section][ info[#info] ] end
		config.set = function(info, value) E.global.profileCopy[section][ info[#info] ] = value end
	end

	return config
end

function MC:CreateMoversConfigGroup()
	local config = {
		header = E.Libs.ACH:Header(function()
			E.Options.args.profiles.args.modulecopy.args.import.func = function()
				E.PopupDialogs.MODULE_COPY_CONFIRM.text = format(L["You are going to copy settings for |cffD3CF00\"%s\"|r from |cff4beb2c\"%s\"|r profile to your current |cff4beb2c\"%s\"|r profile. Are you sure?"], L["Movers"], E.global.profileCopy.selected, ElvDB.profileKeys[E.mynameRealm])
				E.PopupDialogs.MODULE_COPY_CONFIRM.OnAccept = function()
					MC:CopyMovers('import')
				end
				E:StaticPopup_Show('MODULE_COPY_CONFIRM')
			end

			E.Options.args.profiles.args.modulecopy.args.export.func = function()
				E.PopupDialogs.MODULE_COPY_CONFIRM.text = format(L["You are going to copy settings for |cffD3CF00\"%s\"|r from your current |cff4beb2c\"%s\"|r profile to |cff4beb2c\"%s\"|r profile. Are you sure?"], L["Movers"], ElvDB.profileKeys[E.mynameRealm], E.global.profileCopy.selected)
				E.PopupDialogs.MODULE_COPY_CONFIRM.OnAccept = function()
					MC:CopyMovers('export')
				end
				E:StaticPopup_Show('MODULE_COPY_CONFIRM')
			end

			E.Options.args.profiles.args.modulecopy.args.clear.func = function() ToggleSkins(E.global.profileCopy, 'movers', false) end
			E.Options.args.profiles.args.modulecopy.args.select.func = function() ToggleSkins(E.global.profileCopy, 'movers', true) end

			return L["On screen positions for different elements."]
		end, 0)
	}

	DefaultMovers(G.profileCopy, 'movers')
	DefaultMovers(E.global.profileCopy, 'movers')

	for moverName, data in pairs(E.CreatedMovers) do
		DefaultMovers(G.profileCopy, 'movers', moverName)
		DefaultMovers(E.global.profileCopy, 'movers', moverName)

		config[moverName] = {
			order = 1,
			type = 'toggle',
			name = data.mover.textString,
			get = function() return E.global.profileCopy.movers[moverName] end,
			set = function(_, value) E.global.profileCopy.movers[moverName] = value end
		}
	end

	for moverName, data in pairs(E.DisabledMovers) do
		DefaultMovers(G.profileCopy, 'movers', moverName)
		DefaultMovers(E.global.profileCopy, 'movers', moverName)

		config[moverName] = {
			order = 1,
			type = 'toggle',
			name = data.mover.textString,
			get = function() return E.global.profileCopy.movers[moverName] end,
			set = function(_, value) E.global.profileCopy.movers[moverName] = value end
		}
	end
	return config
end

function MC:CopyTable(CopyFrom, CopyTo, CopyDefault, module)
	for key, value in pairs(CopyTo) do
		if type(value) ~= 'table' then
			if module == true or (type(module) == 'table' and (module.general == nil or (not CopyTo.general and module.general))) then --Some dark magic of a logic to figure out stuff
				--This check is to see if the profile we are copying from has keys absent from defaults.
				--If key exists, then copy. If not, then clear obsolite key from the profile.
				if CopyDefault[key] ~= nil then
					CopyTo[key] = CopyFrom[key] or CopyDefault[key]
				else
					CopyFrom[key] = nil
				end
			end
		else
			if module == true then --Copy over entire section of profile subgroup
				E:CopyTable(CopyTo, CopyDefault)
				E:CopyTable(CopyTo, CopyFrom)
			elseif type(module) == 'table' and module[key] ~= nil then
				--Making sure tables actually exist in profiles (e.g absent values in ElvDB.profiles are for default values)
				CopyFrom[key], CopyTo[key] = MC:TablesExist(CopyFrom[key], CopyTo[key], CopyDefault[key])
				--If key exists, then copy. If not, then clear obsolite key from the profile.
				--Someone should double check this logic. Cause for single keys it is fine, but I'm no sure bout whole tables @Darth
				if CopyFrom[key] ~= nil then
					MC:CopyTable(CopyFrom[key], CopyTo[key], CopyDefault[key], module[key])
				else
					CopyTo[key] = nil
				end
			end
		end
	end
end

--[[
	* Valid copy templates should be as follows:
		E.global.profileCopy[YourOptionGroupName] = {
			[SubGroupName1] = true,
			[SubGroupName2] = true,
			...
		}
	* For example:
		E.global.profileCopy.auras = {
			general = true,
			buffs = true,
			debuffs = true,
			cooldown = true,
		}
	* 'general' key can refer to a similar named subtable or all non-table variables inside your group
	* If you leave the table as E.global.profileCopy[YourOptionGroupName] = {}, this will result in no valid copy template error.
	* If set to E.global.profileCopy[YourOptionGroupName] = true, then this will copy everything without selecting any particular subcategory from your settings table.
	* Plugins can use 'pluginSection' argument to determain their own table if they keep settings apart from core ElvUI settings.
	-- Examples S&L uses 'sle' table, MerathilisUI uses 'mui' table, BenikUI uses 'benikui' and core table
]]

function MC:TablesExist(CopyFrom, CopyTo, CopyDefault)
	if not CopyFrom then CopyFrom = CopyDefault end
	if not CopyTo then CopyTo = CopyDefault end
	return CopyFrom, CopyTo
end

function MC:ImportFromProfile(section, pluginSection)
	--Some checks for the occasion someone passes wrong stuff
	if not section then error('No profile section provided. Usage MC:ImportFromProfile("section")') end
	if not pluginSection and MC.InternalOptions[section] then error(format('Section name could not be "%s". This name is reserved for internal setting'), section) end
	if pluginSection and (MC.InternalOptions[pluginSection] and MC.InternalOptions[pluginSection][section]) then error(format('Section name for plugin group "%s" could not be "%s". This name is reserved for internal setting'), pluginSection, section) end

	local module = pluginSection and E.global.profileCopy[pluginSection][section] or E.global.profileCopy[section]
	if not module then error(format('Provided section name "%s" does not have a template for profile copy.', section)) end
	--Starting digging through the settings
	local CopyFrom = pluginSection and (ElvDB.profiles[E.global.profileCopy.selected][pluginSection] and ElvDB.profiles[E.global.profileCopy.selected][pluginSection][section] or P[pluginSection][section]) or ElvDB.profiles[E.global.profileCopy.selected][section]
	local CopyTo = pluginSection and E.db[pluginSection][section] or E.db[section]
	local CopyDefault = pluginSection and P[pluginSection][section] or P[section]
	--Making sure tables actually exist in profiles (e.g absent values in ElvDB.profiles are for default values)
	CopyFrom, CopyTo = MC:TablesExist(CopyFrom, CopyTo, CopyDefault)
	if type(module) == 'table' and next(module) then --This module is not an empty table
		MC:CopyTable(CopyFrom, CopyTo, CopyDefault, module)
	elseif type(module) == 'boolean' then --Copy over entire section of profile subgroup
		E:CopyTable(CopyTo, CopyDefault)
		E:CopyTable(CopyTo, CopyFrom)
	else
		error(format('Provided section name "%s" does not have a valid copy template.', section))
	end
	E:StaggeredUpdateAll()
end

function MC:ExportToProfile(section, pluginSection)
	--Some checks for the occasion someone passes wrong stuff
	if not section then error('No profile section provided. Usage MC:ExportToProfile("section")') end
	if not pluginSection and MC.InternalOptions[section] then error(format('Section name could not be "%s". This name is reserved for internal setting'), section) end
	if pluginSection and MC.InternalOptions[pluginSection][section] then error(format('Section name for plugin group "%s" could not be "%s". This name is reserved for internal setting'), pluginSection, section) end

	local module = pluginSection and E.global.profileCopy[pluginSection][section] or E.global.profileCopy[section]
	if not module then error(format('Provided section name "%s" does not have a template for profile copy.', section)) end
	--Making sure tables actually exist
	if not ElvDB.profiles[E.global.profileCopy.selected][section] then ElvDB.profiles[E.global.profileCopy.selected][section] = {} end
	if not E.db[section] then E.db[section] = {} end
	--Starting digging through the settings
	local CopyFrom = pluginSection and E.db[pluginSection][section] or E.db[section]
	local CopyTo = pluginSection and ElvDB.profiles[E.global.profileCopy.selected][pluginSection][section] or ElvDB.profiles[E.global.profileCopy.selected][section]
	local CopyDefault = pluginSection and P[pluginSection][section] or P[section]
	if type(module) == 'table' and next(module) then --This module is not an empty table
		MC:CopyTable(CopyFrom, CopyTo, CopyDefault, module)
	elseif type(module) == 'boolean' then --Copy over entire section of profile subgroup
		E:CopyTable(CopyTo, CopyDefault)
		E:CopyTable(CopyTo, CopyFrom)
	else
		error(format('Provided section name "%s" does not have a valid copy template.', section))
	end
end

function MC:CopyMovers(mode)
	if not E.db.movers then E.db.movers = {} end --Nothing was moved in cutrrent profile
	if not ElvDB.profiles[E.global.profileCopy.selected].movers then ElvDB.profiles[E.global.profileCopy.selected].movers = {} end --Nothing was moved in selected profile
	local CopyFrom, CopyTo
	if mode == 'export' then
		CopyFrom, CopyTo = E.db.movers, ElvDB.profiles[E.global.profileCopy.selected].movers
	else
		CopyFrom, CopyTo = ElvDB.profiles[E.global.profileCopy.selected].movers or {}, E.db.movers
	end

	for moverName in pairs(E.CreatedMovers) do
		if E.global.profileCopy.movers[moverName] then
			CopyTo[moverName] = CopyFrom[moverName]
		end
	end
	E:SetMoversPositions()
end

function MC:Initialize()
	MC.Initialized = true
end

E:RegisterModule(MC:GetName())
