local OptionsAppName = ...
local RangeDisplay = RangeDisplay
local ACR = LibStub("AceConfigRegistry-3.0")
local AceDBOptions = LibStub("AceDBOptions-3.0")
local LibDualSpec = LibStub("LibDualSpec-1.0", true)
local ACD = LibStub("AceConfigDialog-3.0")
local L = LibStub("AceLocale-3.0"):GetLocale(OptionsAppName)

local MinFontSize = 5
local MaxFontSize = 30
local MinRangeLimit = 0
local MaxRangeLimit = 100

local lastConfiguredUd -- stupid hack to remember last open config frame
local fakeUdForProfiles = {}

local _

local function printf(fmt, ...)
    return print(fmt:format(...))
end

local FontOutlines = {
    [""] = L["None"],
    ["OUTLINE"] = L["Normal"],
    ["THICKOUTLINE"] = L["Thick"],
}

local FrameStratas = {
    ["HIGH"] = L["High"],
    ["MEDIUM"] = L["Medium"],
    ["LOW"] = L["Low"],
}

local SectionNames = {
    ["crSection"] = L["Close range section"],
    ["srSection"] = L["Short range section"],
    ["mrSection"] = L["Medium range section"],
    ["lrSection"] = L["Long range section"],
    ["defaultSection"] = L["Default section"],
    ["oorSection"] = L["Out of range section"],
}

function RangeDisplay:openConfigDialog(ud)
    ud = ud or lastConfiguredUd
    if ud then
        InterfaceOptionsFrame_OpenToCategory(ud.opts)
    else
        InterfaceOptionsFrame_OpenToCategory(self.profiles) -- to expand our tree
        InterfaceOptionsFrame_OpenToCategory(self.opts)
    end
end

function RangeDisplay:getOption(info)
    return self.db.profile[info[#info]]
end

function RangeDisplayLocked(value)
	RangeDisplay.db.profile["locked"] = value;
	RangeDisplay:applySettings()
end

function RangeDisplay:setOption(info, value)
    self.db.profile[info[#info]] = value
    self:applySettings()
end

local function dummy()
end

local function yes()
    return true
end

local function copyTable(src, dst)
    if type(dst) ~= "table" then dst = {} end
    if type(src) == "table" then
        for k, v in pairs(src) do
            if type(v) == "table" then
                v = copyTable(v, dst[k])
            end
            dst[k] = v
        end
    end
    return dst
end

local function getUnitOption(ud, info)
    return ud.db[info[#info]]
end

function SetRangeDisplayUnits(ud,value)


	if ud=="TARGET" then
		--print(RangeDisplay.units[1].name);
		RangeDisplay.units[1].db["enabled"]=value;
		RangeDisplay:applySettings();
	elseif ud=="FOCUS" then
		--print(RangeDisplay.units[2].name);
		RangeDisplay.units[2].db["enabled"]=value;
		RangeDisplay:applySettings();
	elseif ud=="PET" then
		--print(RangeDisplay.units[3].name);
		RangeDisplay.units[3].db["enabled"]=value;
		RangeDisplay:applySettings();
	end

end

local function setUnitOption(ud, info, value)
    ud.db[info[#info]] = value
    ud:applySettings(info[#info])
end

local function getSectionOption(ud, info)
    return ud.db[info[#info - 1]][info[#info]]
end

local function setSectionOption(ud, info, value)
    ud.db[info[#info - 1]][info[#info]] = value
    ud:applySettings()
end

local function setColor(ud, dbcolor, r, g, b, a)
    dbcolor.r, dbcolor.g, dbcolor.b, dbcolor.a = r, g, b, a
    if ud.rangeFrameText then
        ud:setDisplayColor(dbcolor)
    end
end

local function getColor(ud, dbcolor)
    return dbcolor.r, dbcolor.g, dbcolor.b, dbcolor.a
end

local function getSectionColor(ud, info)
    local dbcolor =  ud.db[info[#info - 1]][info[#info]]
    return getColor(ud, dbcolor)
end

local function setSectionColor(ud, info, r, g, b, a)
    local dbcolor =  ud.db[info[#info - 1]][info[#info]]
    setColor(ud, dbcolor, r, g, b, a)
end

local function setBGColor(ud, info, r, g, b, a)
    local dbcolor = ud.db[info[#info]]
    dbcolor.r, dbcolor.g, dbcolor.b, dbcolor.a = r, g, b, a
    if not ud.bgFrame then
         return
    end
    if ud.db.bgUseSectionColors then
        ud.rangeFrameText:SetTextColor(ud.db.bgColor.r, ud.db.bgColor.g, ud.db.bgColor.b, ud.db.bgColor.a)
    else
        ud.bgFrame:SetBackdropColor(ud.db.bgColor.r, ud.db.bgColor.g, ud.db.bgColor.b, ud.db.bgColor.a)
    end
    ud.bgFrame:SetBackdropBorderColor(ud.db.bgBorderColor.r, ud.db.bgBorderColor.g, ud.db.bgBorderColor.b, ud.db.bgBorderColor.a)
end

local function getBGColor(ud, info)
    local dbcolor = ud.db[info[#info]]
    return getColor(ud, dbcolor)
end

local function isUnitDisabled(ud, info)
    return not ud.db.enabled
end

local function isSectionDisabled(ud, info)
    return (not ud.db.enabled) or (not ud.db[info[#info - 1]].enabled)
end

function RangeDisplay:updateMainOptions()
    ACR:NotifyChange(self.AppName)
end

function InitializeRangeDisplayOptions()

	do
		local self = RangeDisplay
	if not self.units then return end
		local mainOptions = {
			type = 'group',
			childGroups = 'tab',
			inline = true,
			name = RangeDisplay.AppName,
			handler = RangeDisplay,
			get = "getOption",
			set = "setOption",
			order = 10,
			args = {
				locked = {
					type = 'toggle',
					-- width = 'full',
					name = L["Locked"],
					desc = L["Lock/Unlock display frame"],
					order = 110,
					disabled = function()
						lastConfiguredUd = nil
						return false
					end,
				},
				mute = {
					type = 'toggle',
					-- width = 'full',
					name = L["Mute"],
					desc = L["Toggle sound"],
					order = 111,
				},
			},
		}

		local function makeSectionOptions(ud, order, section)
			local isDefault = (section == "defaultSection")
			return  {
				type = 'group',
				disabled = "isSectionDisabled",
				set = "setSectionOption",
				get = "getSectionOption",
				name = SectionNames[section],
				guiInline = true,
				order = order,
				args = {
					enabled = {
						type = 'toggle',
						name = "", -- L["Enabled"],
						desc = (not isDefault) and L["Enable this color section"] or nil,
						disabled = (not isDefault) and "isUnitDisabled" or false,
						set = isDefault and dummy or nil,
						get = isDefault and yes or nil,
						width = 'half',
						order = 10,
					},
					color = {
						type = 'color',
						hasAlpha = true,
						name = L["Color"],
						--desc = L["Color"],
						set = "setSectionColor",
						get = "getSectionColor",
						width = 'half',
						order = 20,
					},
					range = {
						type = 'range',
						name = L["Range limit"],
						--desc = L["Range limit"],
						min = MinRangeLimit,
						max = MaxRangeLimit,
						set = isDefault and dummy or nil,
						get = isDefault and function() return MaxRangeLimit end or nil,
						disabled = isDefault and true or nil,
						step = 1,
						order = 30,
					},
					warnSound = {
						type = 'toggle',
						name = L["Warning Sound"],
						desc = L["Play a sound when entering this range"],
						order = 60,
					},
					warnSoundName = {
						type = "select", dialogControl = 'LSM30_Sound',
						disabled = function() return not ud.db[section].warnSound end,
						name = L["Warning Sound Name"],
						values = AceGUIWidgetLSMlists.sound,
						order = 70,
					},
					text = {
						type = 'input',
						name = L["Text"],
						desc = L["The text to display for this section"],
						-- width = 'half',
						order = 80,
					},
				},
			}
		end

		local function makeUnitOptions(ud)
			local unit = ud.unit
			local opts = {
				type = 'group',
				name = ud.name,
				handler = ud,
				get = "getUnitOption",
				set = "setUnitOption",
				disabled = "isUnitDisabled",
				args = {
					enabled = {
						type = 'toggle',
						name = L["Enabled"],
						order = 113,
						disabled = function() 
							lastConfiguredUd = ud
							return false
						end,
					},
					reverse = {
						type = 'toggle',
						name = L["Reverse"],
						desc = L["Show max-min instead of min-max"],
						order = 114,
					},
					enemyOnly = {
						type = 'toggle',
						name = L["Enemy only"],
						desc = L["Show range for enemy targets only"],
						order = 115,
					},
					warnEnemyOnly = {
						type = 'toggle',
						name = L["Enemy only sound"],
						desc = L["Use warning sound for enemy targets only"],
						order = 116,
					},
					sep1 = {
						type = 'header',
						name = "",
						order = 118,
					},
					font = {
						type = "select", dialogControl = 'LSM30_Font',
						name = L["Font"],
						--desc = L["Font"],
						values = AceGUIWidgetLSMlists.font,
						order = 135,
					},
					fontSize = {
						type = 'range',
						name = L["Font size"],
						--desc = L["Font size"],
						min = MinFontSize,
						max = MaxFontSize,
						step = 1,
						order = 140,
					},
					fontOutline = {
						type = 'select',
						name = L["Font outline"],
						--desc = L["Font outline"],
						values = FontOutlines,
						order = 150,
					},
					strata = {
						type = 'select',
						name = L["Strata"],
						desc = L["Frame strata"],
						values = FrameStratas,
						order = 155,
					},
					sepBG = {
						type = 'header',
						name = "",
						order = 157,
					},
					bg = {
						type = "group",
						name = L["Background Options"],
						disabled = function() return not ud.db.enabled or not ud.db.bgEnabled end,
						guiInline = true,
						order = 158,
						args = {
							bgEnabled = {
								type = 'toggle',
								order = 1,
								name = L["Enabled"],
								disabled = "isUnitDisabled",
							},
							frameWidth = {
								type = 'range',
								disabled = "isUnitDisabled",
								name = L["Width"],
								min = 32,
								max = 256,
								step = 1,
								order = 5,
							},
							frameHeight = {
								type = 'range',
								disabled = "isUnitDisabled",
								name = L["Height"],
								min = 16,
								max = 64,
								step = 1,
								order = 6,
							},
							bgTexture = {
								type = "select", dialogControl = 'LSM30_Background',
								order = 11,
								name = L["Background Texture"],
								desc = L["Texture to use for the frame's background"],
								values = AceGUIWidgetLSMlists.background,
							},
							bgBorderTexture = {
								type = "select", dialogControl = 'LSM30_Border',
								order = 12,
								name = L["Border Texture"],
								desc = L["Texture to use for the frame's border"],
								values = AceGUIWidgetLSMlists.border,
							},
							bgColor = {
								type = "color",
								order = 13,
								name = L["Background Color"],
								desc = L["Frame's background color"],
								hasAlpha = true,
								set = "setBGColor",
								get = "getBGColor",
							},
							bgBorderColor = {
								type = "color",
								order = 14,
								name = L["Border Color"],
								desc = L["Frame's border color"],
								hasAlpha = true,
								set = "setBGColor",
								get = "getBGColor",
							},
							bgTile = {
								type = "toggle",
								order = 2,
								name = L["Tile Background"],
								desc = L["Tile the background texture"],
							},
							bgTileSize = {
								type = "range",
								order = 16,
								name = L["Background Tile Size"],
								desc = L["The size used to tile the background texture"],
								min = 16, max = 256, step = 1,
								disabled = function() return not ud.db.enabled or not ud.db.bgEnabled or not ud.db.bgTile end,
							},
							bgEdgeSize = {
								type = "range",
								order = 17,
								name = L["Border Thickness"],
								desc = L["The thickness of the border"],
								min = 1, max = 16, step = 1,
							},
							bgAutoHide = {
								type = 'toggle',
								order = 18,
								name = L["Auto hide"],
								desc = L["Hide the background if the range display is not active"],
							},
							bgUseSectionColors = {
								type = 'toggle',
								order = 19,
								name = L["Use Section Colors"],
								desc = L["Use section colors for background and background color for text"],
							},
						},
					},
					sepSections = {
						type = 'header',
						name = "",
						order = 190,
					},
					rangeLimit = {
						type = 'range',
						name = L["Range limit"],
						desc = L["Ranges above this are not reported"],
						min = MinRangeLimit,
						max = MaxRangeLimit,
						step = 1,
						order = 191,

					},
					overLimitDisplay = {
						type = 'toggle',
						name = L["Over limit display"],
						desc = L["Show/Hide display if the target is further than range limit"],
						order = 192,
					},
					overLimitText = {
						type = 'input',
						name = L["Over limit text"],
						desc = L["The text to display when you are further than range limit"],
						order = 193,
						disabled = function() return not ud.db.enabled or not ud.db.overLimitDisplay end,
					},
					sep2 = {
						type = 'header',
						name = "",
						order = 195,
					},
					copySectionSettings = {
						type = 'execute',
						name = L["Copy section settings to other units"],
						width = 'full',
						func = function()
							for _, oud in ipairs(RangeDisplay.units) do
								if oud ~= ud and oud.db.enabled then
									copyTable(ud.db.crSection, oud.db.crSection)
									copyTable(ud.db.srSection, oud.db.srSection)
									copyTable(ud.db.mrSection, oud.db.mrSection)
									copyTable(ud.db.lrSection, oud.db.lrSection)
									copyTable(ud.db.defaultSection, oud.db.defaultSection)
									copyTable(ud.db.oorSection, oud.db.oorSection)
								end
							end
						end,
						order = 200,
					},
				},
			}

			for i, section in pairs(RangeDisplay.Sections) do
				opts.args[section] = makeSectionOptions(ud, 170 + i, section)
			end
			if ud.mouseAnchor then
				opts.args.mouseAnchor = {
					type = 'toggle',
					name = L["Anchor to Mouse"],
					order = 117,
				}
			end
			return opts
		end

		local function addConfigFunctions(units)
			for _, ud in ipairs(units) do
				ud.getUnitOption = getUnitOption
				ud.setUnitOption = setUnitOption
				ud.getSectionColor = getSectionColor
				ud.setSectionColor = setSectionColor
				ud.getSectionOption = getSectionOption
				ud.setSectionOption = setSectionOption
				ud.isUnitDisabled = isUnitDisabled
				ud.isSectionDisabled = isSectionDisabled
				ud.setBGColor = setBGColor
				ud.getBGColor = getBGColor
			end
		end

		local function registerSubOptions(name, opts)
			local appName = self.AppName .. "." .. name
			ACR:RegisterOptionsTable(appName, opts)
			return ACD:AddToBlizOptions(appName, opts.name or name, self.AppName)
		end

		-- BEGIN

		self.optionsLoaded = true

		-- remove dummy options frame, ugly hack
		if self.dummyOpts then 
			for k, f in ipairs(INTERFACEOPTIONS_ADDONCATEGORIES) do
				if f == self.dummyOpts then
					tremove(INTERFACEOPTIONS_ADDONCATEGORIES, k)
					f:SetParent(UIParent)
					break
				end
			end
			self.dummyOpts = nil
		end

		addConfigFunctions(self.units)
		ACR:RegisterOptionsTable(self.AppName, mainOptions)
		self.opts = ACD:AddToBlizOptions(self.AppName, self.AppName)

		for i, ud in ipairs(self.units) do
			local unitOpts = makeUnitOptions(ud)
			ud.opts = registerSubOptions(ud.unit, unitOpts)
		end

		local profiles =  AceDBOptions:GetOptionsTable(self.db)
		if LibDualSpec then
			LibDualSpec:EnhanceOptions(profiles, self.db)
		end

		profiles.disabled = function()
			lastConfiguredUd = fakeUdForProfiles
			return false
		end
		self.profiles = registerSubOptions('profiles', profiles)
		fakeUdForProfiles.opts = self.profiles
	 
	end

end