--[[
	// FileName: NewChat.lua
	// Written by: Xsitsu
	// Description: Bridges the topbar in corescripts to any chat system running in the non-corescripts environment.
]]
local CoreGuiService = game:GetService("CoreGui")
local RobloxGui = CoreGuiService:WaitForChild("RobloxGui")

local StarterGui = game:GetService("StarterGui")
local GuiService = game:GetService("GuiService")

local Util = require(RobloxGui.Modules.ChatUtil)


local moduleApiTable = {}
do
		local ChatWindowState =
		{
			Visible = true,
			MessageCount = 0,
			TopbarEnabled = true,
			CoreGuiEnabled = true,
		}

		local communicationsConnections = {}
		local eventConnections = {}

		local MakeSystemMessageCache = {}

		local function FindInCollectionByKeyAndType(collection, indexName, type)
			if (collection and collection[indexName] and collection[indexName]:IsA(type)) then
				return collection[indexName]
			end
			return nil
		end

		local function DispatchEvent(eventName, ...)
			local event = FindInCollectionByKeyAndType(communicationsConnections.ChatWindow, eventName, "BindableEvent")
			if (event) then
				event:Fire(...)
				return true
			end
			return false
		end

		local function AttemptInvokeFunction(functionName, ...)
			local func = FindInCollectionByKeyAndType(communicationsConnections.ChatWindow, functionName, "BindableFunction")
			if (func) then
				return true, func:Invoke()
			end
			return false, nil
		end

		local function DoConnectGetCore(connectionName)
			StarterGui:RegisterGetCore(connectionName, function(data)
				local func = FindInCollectionByKeyAndType(communicationsConnections.GetCore, connectionName, "BindableFunction")
				local rVal = nil
				if (func) then rVal = func:Invoke(data) end
				return rVal
			end)
		end

		function moduleApiTable:ToggleVisibility()
			ChatWindowState.Visible = not ChatWindowState.Visible
			local didFire = DispatchEvent("ToggleVisibility")
			if (not didFire) then
				moduleApiTable.VisibilityStateChanged:fire(ChatWindowState.Visible)
			end
		end

		function moduleApiTable:SetVisible(visible)
			ChatWindowState.Visible = visible
			local didFire = DispatchEvent("SetVisible", ChatWindowState.Visible)
			if (not didFire) then
				moduleApiTable.VisibilityStateChanged:fire(ChatWindowState.Visible)
			end
		end

		function moduleApiTable:FocusChatBar()
			DispatchEvent("FocusChatBar")
		end

		function moduleApiTable:GetVisibility()
			local success, retVal = AttemptInvokeFunction("GetVisibility")
			if (success) then
				return retVal
			else
				return ChatWindowState.Visible
			end
		end

		function moduleApiTable:GetMessageCount()
			local success, retVal = AttemptInvokeFunction("GetMessageCount")
			if (success) then
				return retVal
			else
				return ChatWindowState.MessageCount
			end
		end

		function moduleApiTable:TopbarEnabledChanged(enabled)
			ChatWindowState.TopbarEnabled = enabled
			DispatchEvent("TopbarEnabledChanged", ChatWindowState.TopbarEnabled)
		end

		function moduleApiTable:IsFocused(useWasFocused)
			local success, retVal = AttemptInvokeFunction("IsFocused", useWasFocused)
			if (sucucess) then
				return retVal
			else
				return false
			end
		end

		moduleApiTable.ChatBarFocusChanged = Util.Signal()
		moduleApiTable.VisibilityStateChanged = Util.Signal()
		moduleApiTable.MessagesChanged = Util.Signal()



		StarterGui.CoreGuiChangedSignal:connect(function(coreGuiType, enabled)
			if (coreGuiType == Enum.CoreGuiType.All or coreGuiType == Enum.CoreGuiType.Chat) then
				ChatWindowState.CoreGuiEnabled = enabled
				DispatchEvent("CoreGuiEnabled", ChatWindowState.CoreGuiEnabled)
			end
		end)

		GuiService:AddSpecialKey(Enum.SpecialKey.ChatHotkey)
		GuiService.SpecialKeyPressed:connect(function(key, modifiers)
			DispatchEvent("SpecialKeyPressed", key, modifiers)
		end)

		StarterGui:RegisterSetCore("ChatMakeSystemMessage", function(data)
			local event = FindInCollectionByKeyAndType(communicationsConnections.SetCore, "ChatMakeSystemMessage", "BindableEvent")
			if (event) then
				event:Fire(data)
			else
				table.insert(MakeSystemMessageCache, data)
			end
		end)

		DoConnectGetCore("ChatWindowPosition")
		DoConnectGetCore("ChatWindowSize")
		DoConnectGetCore("ChatBarDisabled")

		local function RegisterCoreGuiConnections(containerTable)
			if (type(containerTable) == "table") then
				local chatWindowCollection = containerTable.ChatWindow
				local setCoreCollection = containerTable.SetCore
				local getCoreCollection = containerTable.GetCore

				if (type(chatWindowCollection) == "table") then
					for i, v in pairs(eventConnections) do
						v:disconnect()
					end

					eventConnections = {}
					communicationsConnections.ChatWindow = {}

					communicationsConnections.ChatWindow.ToggleVisibility = FindInCollectionByKeyAndType(chatWindowCollection, "ToggleVisibility", "BindableEvent")
					communicationsConnections.ChatWindow.SetVisible = FindInCollectionByKeyAndType(chatWindowCollection, "SetVisible", "BindableEvent")
					communicationsConnections.ChatWindow.FocusChatBar = FindInCollectionByKeyAndType(chatWindowCollection, "FocusChatBar", "BindableEvent")
					communicationsConnections.ChatWindow.TopbarEnabledChanged = FindInCollectionByKeyAndType(chatWindowCollection, "TopbarEnabledChanged", "BindableEvent")
					communicationsConnections.ChatWindow.IsFocused = FindInCollectionByKeyAndType(chatWindowCollection, "IsFocused", "BindableFunction")
					communicationsConnections.ChatWindow.SpecialKeyPressed = FindInCollectionByKeyAndType(chatWindowCollection, "SpecialKeyPressed", "BindableEvent")


					local function DoConnect(index)
						communicationsConnections.ChatWindow[index] = FindInCollectionByKeyAndType(chatWindowCollection, index, "BindableEvent")
						if (communicationsConnections.ChatWindow[index]) then
							local con = communicationsConnections.ChatWindow[index].Event:connect(function(...) moduleApiTable[index]:fire(...) end)
							table.insert(eventConnections, con)
						end
					end

					DoConnect("ChatBarFocusChanged")
					DoConnect("VisibilityStateChanged")
					DoConnect("MessagesChanged")

					local index = "MessagePosted"
					communicationsConnections.ChatWindow[index] = FindInCollectionByKeyAndType(chatWindowCollection, index, "BindableEvent")
					if (communicationsConnections.ChatWindow[index]) then
						local con = communicationsConnections.ChatWindow[index].Event:connect(function(message) game:GetService("Players"):Chat(message) end)
						table.insert(eventConnections, con)
					end

					moduleApiTable:SetVisible(ChatWindowState.Visible)
					moduleApiTable:TopbarEnabledChanged(ChatWindowState.TopbarEnabled)

					local event = FindInCollectionByKeyAndType(chatWindowCollection, "CoreGuiEnabled", "BindableEvent")
					if (event) then
						communicationsConnections.ChatWindow.CoreGuiEnabled = event
						event:Fire(ChatWindowState.CoreGuiEnabled)
					end

				else
					error("Table 'ChatWindow' must be provided!")

				end

				if (type(setCoreCollection) == "table" and type(getCoreCollection) == "table") then
					communicationsConnections.SetCore = {}
					communicationsConnections.GetCore = {}

					local event = FindInCollectionByKeyAndType(setCoreCollection, "ChatMakeSystemMessage", "BindableEvent")
					if (event) then
						communicationsConnections.SetCore.ChatMakeSystemMessage = event
						for i, messageData in pairs(MakeSystemMessageCache) do
							pcall(function() StarterGui:SetCore("ChatMakeSystemMessage", messageData) end)
						end
						MakeSystemMessageCache = {}
					end

					communicationsConnections.GetCore.ChatWindowPosition = FindInCollectionByKeyAndType(getCoreCollection, "ChatWindowPosition", "BindableFunction")
					communicationsConnections.GetCore.ChatWindowSize = FindInCollectionByKeyAndType(getCoreCollection, "ChatWindowSize", "BindableFunction")
					communicationsConnections.GetCore.ChatBarDisabled = FindInCollectionByKeyAndType(getCoreCollection, "ChatBarDisabled", "BindableFunction")

				elseif (type(setCoreCollection) ~= nil or type(getCoreCollection) ~= nil) then
					error("Both 'SetCore' and 'GetCore' must be tables if provided!")

				end

			end
		end

		StarterGui:RegisterSetCore("CoreGuiChatConnections", RegisterCoreGuiConnections)

end

return moduleApiTable
