local GlobalAddonName, E = ...
local L = E.L
local EventFrame = CreateFrame("FRAME")
local Octo_DebugFrame = CreateFrame("BUTTON", "Octo_DebugFrame", UIParent, "OctoBackdropTemplate")
Octo_DebugFrame:Hide()
Octo_editFrame_scrollFrame = CreateFrame("Frame", "Octo_editFrame_scrollFrame", Octo_DebugFrame, "ScrollingEditBoxTemplate")

table.insert(E.OctoTable_ColoredFrames, Octo_DebugFrame)

local MIN_WIDTH, MIN_HEIGHT = 1920 * .2, 1080 * .2
local MAX_WIDTH, MAX_HEIGHT = 1920 * .7, 1080 * .7
local INDENT = 20
local BUTTON_WIDTH, BUTTON_HEIGHT = 80, 20
local LibStub = LibStub
local L = E.L
local LibIndentation = LibStub("LibIndentation-1.0")
function E.func_createColorScheme(themeName)
	local theme = E.editorThemes[themeName] or E.editorThemes["Twilight"]
	return {
		[LibIndentation.tokens.TOKEN_UNKNOWN] = theme["Error"],
		[LibIndentation.tokens.TOKEN_NUMBER] = theme["Number"],
		[LibIndentation.tokens.TOKEN_LINEBREAK] = theme["Foreground"],
		[LibIndentation.tokens.TOKEN_WHITESPACE] = theme["Foreground"],
		[LibIndentation.tokens.TOKEN_IDENTIFIER] = theme["Foreground"],
		[LibIndentation.tokens.TOKEN_ASSIGNMENT] = theme["Operator"],
		[LibIndentation.tokens.TOKEN_EQUALITY] = theme["Operator"],
		[LibIndentation.tokens.TOKEN_MINUS] = theme["Operator"],
		[LibIndentation.tokens.TOKEN_COMMENT_SHORT] = theme["Comment"],
		[LibIndentation.tokens.TOKEN_COMMENT_LONG] = theme["Comment"],
		[LibIndentation.tokens.TOKEN_STRING] = theme["String"],
		[LibIndentation.tokens.TOKEN_LEFTBRACKET] = theme["Bracket"],
		[LibIndentation.tokens.TOKEN_PERIOD] = theme["Operator"],
		[LibIndentation.tokens.TOKEN_DOUBLEPERIOD] = theme["Operator"],
		[LibIndentation.tokens.TOKEN_TRIPLEPERIOD] = theme["Special"],
		[LibIndentation.tokens.TOKEN_LTE] = theme["Operator"],
		[LibIndentation.tokens.TOKEN_LT] = theme["Operator"],
		[LibIndentation.tokens.TOKEN_GTE] = theme["Operator"],
		[LibIndentation.tokens.TOKEN_GT] = theme["Operator"],
		[LibIndentation.tokens.TOKEN_NOTEQUAL] = theme["Operator"],
		[LibIndentation.tokens.TOKEN_COMMA] = theme["Special"],
		[LibIndentation.tokens.TOKEN_SEMICOLON] = theme["Special"],
		[LibIndentation.tokens.TOKEN_COLON] = theme["Special"],
		[LibIndentation.tokens.TOKEN_LEFTPAREN] = theme["Bracket"],
		[LibIndentation.tokens.TOKEN_RIGHTPAREN] = theme["Bracket"],
		[LibIndentation.tokens.TOKEN_PLUS] = theme["Operator"],
		[LibIndentation.tokens.TOKEN_SLASH] = theme["Operator"],
		[LibIndentation.tokens.TOKEN_LEFTWING] = theme["Bracket"],
		[LibIndentation.tokens.TOKEN_RIGHTWING] = theme["Bracket"],
		[LibIndentation.tokens.TOKEN_CIRCUMFLEX] = theme["Operator"],
		[LibIndentation.tokens.TOKEN_ASTERISK] = theme["Operator"],
		[LibIndentation.tokens.TOKEN_RIGHTBRACKET] = theme["Bracket"],
		[LibIndentation.tokens.TOKEN_KEYWORD] = theme["Keyword"],
		[LibIndentation.tokens.TOKEN_SPECIAL] = theme["Special"],
		[LibIndentation.tokens.TOKEN_VERTICAL] = theme["Special"],
		[LibIndentation.tokens.TOKEN_TILDE] = theme["Operator"],
		[LibIndentation.tokens.TOKEN_COLORCODE_START] = theme["Special"],
		[LibIndentation.tokens.TOKEN_COLORCODE_STOP] = theme["Special"],
		[LibIndentation.tokens.TOKEN_HASH] = theme["Operator"],
		[LibIndentation.tokens.TOKEN_PERCENT] = theme["Operator"],
		["..."] = theme["Special"],
		[" .. "] = theme["Operator"],
		["|c"] = theme["Special"],
		["|r"] = theme["Special"],
		["and"] = theme["Keyword"],
		["break"] = theme["Keyword"],
		["do"] = theme["Keyword"],
		["else"] = theme["Keyword"],
		["elseif"] = theme["Keyword"],
		["end"] = theme["Keyword"],
		["false"] = theme["Constant"],
		["for"] = theme["Keyword"],
		["function"] = theme["Keyword"],
		["if"] = theme["Keyword"],
		["in"] = theme["Keyword"],
		["local"] = theme["Keyword"],
		["nil"] = theme["Constant"],
		["not"] = theme["Keyword"],
		["or"] = theme["Keyword"],
		["repeat"] = theme["Keyword"],
		["return"] = theme["Keyword"],
		["then"] = theme["Keyword"],
		["true"] = theme["Constant"],
		["until"] = theme["Keyword"],
		["while"] = theme["Keyword"],
		[0] = "|r"
	}
end
local function CreateMyAddonEditFrameTemplate()
	Octo_DebugFrame:SetPoint("CENTER")
	local width = E.PHYSICAL_SCREEN_WIDTH / 2
	local height = E.PHYSICAL_SCREEN_HEIGHT / 2
	Octo_DebugFrame:SetSize(width, height)
	Octo_DebugFrame:SetResizable(true)
	Octo_DebugFrame:SetDontSavePosition(true)
	Octo_DebugFrame:SetClampedToScreen(true)
	Octo_DebugFrame:EnableMouse(true)
	Octo_DebugFrame:SetMovable(true)
	Octo_DebugFrame:RegisterForClicks("RightButtonUp")
	Octo_DebugFrame:SetScript("OnClick", Octo_DebugFrame.Hide)
	Octo_DebugFrame.scrollBar = CreateFrame("EventFrame", nil, Octo_DebugFrame, "MinimalScrollBar")
	Octo_DebugFrame.scrollBar:SetPoint("TOPRIGHT", 14, 0)
	Octo_DebugFrame.scrollBar:SetPoint("BOTTOMRIGHT", 14, 0)
	Octo_editFrame_scrollFrame:SetPoint("TOPLEFT", INDENT, -INDENT)
	Octo_editFrame_scrollFrame:SetPoint("BOTTOMRIGHT", -INDENT, INDENT * 3)
	Octo_editFrame_scrollFrame.tex = Octo_editFrame_scrollFrame:CreateTexture()
	Octo_editFrame_scrollFrame.tex:SetAllPoints(Octo_editFrame_scrollFrame)
	Octo_editFrame_scrollFrame.tex:SetColorTexture(0, 0, 0, .7)
	Octo_DebugFrame.Import = CreateFrame("Button", nil, Octo_DebugFrame, "UIPanelButtonTemplate")
	Octo_DebugFrame.Import:SetPoint("BOTTOMRIGHT", -(INDENT * 2 + BUTTON_WIDTH), INDENT)
	Octo_DebugFrame.Import:SetSize(BUTTON_WIDTH, BUTTON_HEIGHT)
	Octo_DebugFrame.Import:SetText(L["IMPORT"])
	Octo_DebugFrame.Import:SetScript(
		"OnClick",
		function(self, button, down)
			local str = Octo_editFrame_scrollFrame:GetText()
			if not str or str == "" then
				E.func_PrintMessage(E.COLOR_RED .. "No data to import|r")
				return
			end
			local data = E.getDataFromString(str, true)
			if data then
				E.func_workWitchMyTable(data)
				Octo_DebugFrame:Hide()
			end
		end
	)
	Octo_DebugFrame.Import:RegisterForClicks("AnyUp")
	Octo_DebugFrame.closeButton = CreateFrame("Button", nil, Octo_DebugFrame, "UIPanelButtonTemplate")
	Octo_DebugFrame.closeButton:SetPoint("BOTTOMRIGHT", -INDENT, INDENT)
	Octo_DebugFrame.closeButton:SetSize(BUTTON_WIDTH, BUTTON_HEIGHT)
	Octo_DebugFrame.closeButton:SetText(L["CLOSE"])
	Octo_DebugFrame.closeButton:SetScript(
		"OnClick",
		function(self, button, down)
			Octo_DebugFrame:Hide()
		end
	)
	Octo_DebugFrame.closeButton:RegisterForClicks("AnyUp")
	Octo_DebugFrame.resize = CreateFrame("BUTTON", nil, Octo_DebugFrame)
	Octo_DebugFrame.resize:SetSize(16, 16)
	Octo_DebugFrame.resize:SetPoint("BOTTOMRIGHT", 0, 0)
	Octo_DebugFrame.resize:SetNormalTexture("Interface\\ChatFrame\\UI-ChatIM-SizeGrabber-Up")
	Octo_DebugFrame.resize:SetHighlightTexture("Interface\\ChatFrame\\UI-ChatIM-SizeGrabber-Highlight")
	Octo_DebugFrame.resize:SetPushedTexture("Interface\\ChatFrame\\UI-ChatIM-SizeGrabber-Down")
	Octo_DebugFrame.resize:RegisterForDrag("LeftButton")
	Octo_DebugFrame.lineText = Octo_DebugFrame:CreateFontString()
	Octo_DebugFrame.lineText:SetFontObject(OctoFont11)
	Octo_DebugFrame.lineText:SetPoint("BOTTOMLEFT", 20, 20)
	Octo_DebugFrame.lineText:SetText(L["Line"])
	local scrollBox = Octo_editFrame_scrollFrame:GetScrollBox()
	scrollBox:SetAllPoints(Octo_editFrame_scrollFrame)
	ScrollUtil.RegisterScrollBoxWithScrollBar(scrollBox, Octo_DebugFrame.scrollBar)
	ScrollUtil.AddManagedScrollBarVisibilityBehavior(scrollBox, Octo_DebugFrame.scrollBar)
	local editBox = Octo_editFrame_scrollFrame:GetEditBox()
	editBox:HookScript("OnEnterPressed", function(self)
			self:Insert("\n")
		end
	)
	editBox:HookScript("OnEscapePressed", function(self)
			self:ClearFocus()
		end
	)
	if Octo_DevTool_DB then
		editBox:SetFont(E.Octo_font, Octo_DevTool_DB.CONFIG_DEBUG_EDITBOX_FONTSIZE, "")
	else
		editBox:SetFont(E.Octo_font, 11, "")
	end
	editBox:HookScript("OnCursorChanged", function(self)
			local text = self:GetText()
			local pos = self:GetCursorPosition()
			local next = -1
			local line = 0
			local totalLines = 1
			for _ in text:gmatch("\n") do
				totalLines = totalLines + 1
			end
			while next and pos >= next do
				next = text:find("[\n]", next + 1)
				line = line + 1
			end
			Octo_DebugFrame.lineText:SetText(L["Line"] .. ": " .. line .. "/" .. totalLines)
		end
	)
	Octo_DebugFrame:SetScript("OnMouseDown", function(_, button)
			if button == "LeftButton" then
				Octo_DebugFrame:StartMoving()
			end
		end
	)
	Octo_DebugFrame:SetScript("OnMouseUp", function(_, button)
			if button == "LeftButton" then
				Octo_DebugFrame:StopMovingOrSizing()
			end
		end
	)
	Octo_DebugFrame:SetScript("OnKeyDown", function(self, key)
			if not InCombatLockdown() then
				if key == GetBindingKey("TOGGLEGAMEMENU") then
					self:Hide()
					self:SetPropagateKeyboardInput(false)
				else
					self:SetPropagateKeyboardInput(true)
				end
			end
		end
	)
	local isResizing = false
	Octo_DebugFrame.resize:SetScript("OnDragStart", function(self)
			isResizing = true
			self:GetParent():StartSizing("BOTTOMRIGHT", true)
		end
	)
	Octo_DebugFrame.resize:SetScript("OnDragStop", function(self)
			isResizing = false
			self:GetParent():StopMovingOrSizing()
		end
	)
	Octo_DebugFrame:SetScript("OnUpdate", function(self, elapsed)
			if isResizing then
				local w, h = self:GetSize()
				self:SetSize(math.max(MIN_WIDTH, math.min(MAX_WIDTH, w)), math.max(MIN_HEIGHT, math.min(MAX_HEIGHT, h)))
			end
		end
	)
end
function E.ShowImportExportFrame(defaultText)
	if SettingsPanel:IsVisible() then
		HideUIPanel(SettingsPanel)
	end
	if GameMenuFrame:IsVisible() then
		HideUIPanel(GameMenuFrame)
	end
	Octo_editFrame_scrollFrame:SetText(defaultText or "")
	Octo_DebugFrame:Show()
	Octo_editFrame_scrollFrame:SetFocus()
end
do
	local compressedCache, encodeForWoWAddonChannel, decodeForWoWAddonChannel
	function encodeForWoWAddonChannel(str)
		local encode_translate = {
			["\000"] = "\001\002",
			["\001"] = "\001\003"
		}
		function encodeForWoWAddonChannel(str)
			return str:gsub("[%z\001]", encode_translate)
		end
		return encodeForWoWAddonChannel(str)
	end
	function decodeForWoWAddonChannel(str)
		local decode_translate = {
			["\001\002"] = "\000",
			["\001\003"] = "\001"
		}
		function decodeForWoWAddonChannel(str)
			return str:gsub("\001[\002\003]", decode_translate)
		end
		return decodeForWoWAddonChannel(str)
	end
	function E.getStringFromData(data, forPrint)
		local serialized = C_EncodingUtil.SerializeCBOR(data)
		local ServerTime, compressed = E.TIME_SERVER()
		compressedCache = compressedCache or {}
		if compressedCache[serialized] then
			compressed = compressedCache[serialized].compressed
			compressedCache[serialized].lastAccess = ServerTime
		else
			compressed =
			C_EncodingUtil.CompressString(
				serialized,
				Enum.CompressionMethod.Deflate,
				Enum.CompressionLevel.OptimizeForSize
			)
			compressedCache[serialized] = {
				compressed = compressed,
				lastAccess = ServerTime
			}
		end
		local expiredTime = ServerTime - 300
		for k, v in next, compressedCache do
			if v.lastAccess < expiredTime then
				compressedCache[k] = nil
			end
		end
		if forPrint then
			return C_EncodingUtil.EncodeBase64(compressed, Enum.Base64Variant.StandardUrlSafe)
		else
			return encodeForWoWAddonChannel(compressed)
		end
	end
	function E.getDataFromString(str, fromPrint)
		local decoded, success, decompressed, data
		if fromPrint then
			decoded = C_EncodingUtil.DecodeBase64(str, Enum.Base64Variant.StandardUrlSafe)
		else
			decoded = decodeForWoWAddonChannel(str)
		end
		success, decompressed = pcall(C_EncodingUtil.DecompressString, decoded, Enum.CompressionMethod.Deflate)
		if not success then
			return
		end
		success, data = pcall(C_EncodingUtil.DeserializeCBOR, decompressed)
		if success then
			return data
		end
	end
	function E.func_workWitchMyTable(tbl)
		Octo_ToDo_DB_Levels = Octo_ToDo_DB_Levels or {}
		local count = 0
		local success = false
		for GUID, CharInfo in next, (tbl) do
			local pd = CharInfo.PlayerData
			local cm = CharInfo.MASLENGO
			if pd and cm and pd.Name then
				count = count + 1
				success = true
				Octo_ToDo_DB_Levels[GUID] = CharInfo
			end
		end
		if success then
			E.func_PrintMessage(E.COLOR_GREEN .. "Import successful, chars:|r", count)
		else
			E.func_PrintMessage(E.COLOR_YELLOW .. "Import failed:|r")
		end
	end
end
local function dumpEdit(indent, msg, tables)
	local str, indentStr, tables = "", "", tables or {}
	for i = 1, indent do
		indentStr = indentStr .. " "
	end
	for k, v in next, (msg) do
		k =
		(type(k) == "number" and "[" .. k .. "]" or type(k) == "string" and '["' .. k .. '"]' or tostringall(k)) ..
		" ="
		if type(v) == "table" and not tables[v] then
			tables[v] = true
			str = ("%s%s%s {\n"):format(str, indentStr, k)
			str = str .. dumpEdit(indent + 1, v, tables)
			str = ("%s%s},\n"):format(str, indentStr)
		else
			local vtype = type(v)
			v =
			vtype == "string" and '"' .. v:gsub('["\\]', "\\%1") .. '"' or vtype == "number" and v or
			'"' .. tostringall(v) .. '"'
			str = ("%s%s%s %s,\n"):format(str, indentStr, k, v)
		end
	end
	if indent == 0 then
		LibIndentation.enable(
			Octo_editFrame_scrollFrame:GetEditBox(),
			E.func_createColorScheme(Octo_DevTool_DB.CONFIG_DEBUG_EDITBOX_EDITORTHEME or "Twilight"),
			Octo_DevTool_DB.CONFIG_DEBUG_EDITBOX_TABSPACES
		)
		Octo_editFrame_scrollFrame:SetText(str)
		LibIndentation.indentEditbox(Octo_editFrame_scrollFrame:GetEditBox())
		Octo_DebugFrame:Show()
	else
		return str
	end
end
local oprintHandler = function(...)
	local function sendMessage(frame, indent, msg, allChildren)
		local indentStr = E.func_Gradient(GlobalAddonName .. ": ")
		for i = 1, indent do
			indentStr = indentStr .. " "
		end
		for k, v in next, (msg) do
			k = "[" .. tostringall(k) .. "] ="
			if type(v) == "table" then
				if allChildren or indent + 1 == 1 then
					frame:AddMessage(strjoin(" ", indentStr, k, "table: {"))
					sendMessage(frame, indent + 1, v, allChildren)
					frame:AddMessage(strjoin(" ", indentStr, " }"))
				else
					frame:AddMessage(strjoin(" ", indentStr, k, "table"))
				end
			else
				frame:AddMessage(strjoin(" ", indentStr, k, tostringall(v)))
			end
		end
	end
	local message = strjoin(" ", E.func_Gradient(GlobalAddonName .. ": "), tostringall(...))
	local mFrame = DEFAULT_CHAT_FRAME
	local i = 1
	repeat
		local frame = _G["ChatFrame" .. i]
		if frame and frame:IsShown() then
			mFrame = frame
			break
		end
		i = i + 1
	until not frame
	mFrame:AddMessage(message)
	local first = select(1, ...)
	if first == "dump" then
		local msg = {}
		for i = 2, select("#", ...) do
			local n = select(i, ...)
			tinsert(msg, n)
		end
		sendMessage(mFrame, 0, msg)
	end
	if first == dumpe then
		local msg = {}
		for i = 2, select("#", ...) do
			local n = select(i, ...)
			tinsert(msg, n)
		end
		dumpEdit(0, msg)
	end
end
local function oprint_inner(...)
	forceinsecure()
	local ok, err = pcall(oprintHandler, ...)
	if not ok then
		geterrorhandler()(err)
	end
end
dump = "dump"
dumpe = "dumpe"
if not oprint then
	function oprint(...)
		securecall(pcall, oprint_inner, ...)
	end
end
if not opd then
	function opd(...)
		oprint(dump, ...)
	end
end
if not opde then
	function opde(...)
		oprint(dumpe, ...)
	end
end
SLASH_OPRINT1 = "/oprint"
SlashCmdList["OPRINT"] = function(msg)
	local f, err = loadstring("return " .. msg) -- было load
	if err then
		oprint(err:gsub('"return ', '"'))
		return
	end
	local status, value = pcall(f)
	if status then
		oprint(dumpe, value)
	else
		oprint(value:gsub('"return ', '"'))
	end
end
local slashCommands = {
	GSEARCH = {
		commands = {"/gsearch", "/gs"},
		handler = function(msg)
			local str = ""
			local color = E.classColorHexCurrent
			DEFAULT_CHAT_FRAME:AddMessage(color .. "GSEARCH:|r " .. msg)
			for i, n in pairs(_G) do
				if type(n) == "string" and n:find(msg) then
					str = str .. color .. i .. "|r - " .. n .. "\n"
				end
			end
			Octo_editFrame_scrollFrame:SetText(str)
			Octo_DebugFrame:Show()
		end
	}
}
for name, data in pairs(slashCommands) do
	SlashCmdList[name] = data.handler
	for i, cmd in ipairs(data.commands) do
		_G["SLASH_" .. name .. i] = cmd
	end
end
local MyEventsTable = {
	"PLAYER_LOGIN"
}
E.func_RegisterEvents(EventFrame, MyEventsTable)
function EventFrame:PLAYER_LOGIN()
	CreateMyAddonEditFrameTemplate()
	E.editFrame = Octo_DebugFrame
	E.editBox = Octo_editFrame_scrollFrame
	do
		local frame = Octo_DebugFrame
		local providerfunc = nil
		local buttonName = nil
		E.func_Create_DDframe_editFrame(frame, providerfunc, buttonName)
	end
end
E.Octo_DevTool_DB_DATA = " "