local n=game:GetService("\080\108\097\121\101\114\115")local t=n.LocalPlayer return function(n)local H=n.Util local B=require(script:WaitForChild("\087\105\110\100\111\119"))B.Cmdr=n local S=(require(script:WaitForChild("\065\117\116\111\067\111\109\112\108\101\116\101")))(n)B.AutoComplete=S function B.ProcessEntry(S)S=H.TrimString(S)if#S==0 then return end B:AddLine(B:GetLabel()..(" "..S),Color3.fromRGB(255,223,93))B:AddLine(n.Dispatcher:EvaluateAndRun(S,t,{IsHuman=true}))end function B.OnTextChanged(Z)local I=n.Dispatcher:Evaluate(Z,t,true)local O=H.SplitString(Z)local G=table.remove(O,1)local i=false if I then O=H.MashExcessArguments(O,#I.Object.Args)i=#O==#I.Object.Args end local o=G and#O>0 if(Z:sub(#Z,#Z)):match("\037\115")and not i then o=true O[#O+1]=""end if I and o then local n,t=I:Validate()B:SetIsValidInput(n,("\086\097\108\105\100\097\116\105\111\110 \101\114\114\111\114\115\058 \037\115"):format(t or""))local H={}local G=I:GetArgument(#O)if G then local n=G.RawSegments[#G.RawSegments]local B=G:GetAutocomplete()for t,B in pairs(B)do H[t]={n,B}end local o=true if#n>0 then o,t=G:Validate()end return S:Show(H,{at=i and(#Z-#n)+((Z:sub(#Z,#Z)):match("\037\115")and-1 or 0),prefix=#G.RawSegments==1 and G.Prefix or"",isLast=#I.Arguments==#I.ArgumentDefinitions and#n>0;numArgs=#O,command=I,arg=G;name=G.Name..(G.Required and""or"\063");type=G.Type.DisplayName,description=o==false and t or G.Object.Description;invalid=not o})end elseif G and#O==0 then B:SetIsValidInput(true)local t=n.Registry:GetCommand(G)local H if t then H={t.Name,t.Name;options={name=t.Name;description=t.Description}}end local Z={H}for t,B in pairs(n.Registry:GetCommandsAsStrings())do if G:lower()==(B:lower()):sub(1,#G)and(H==nil or H[1]~=G)then local t=n.Registry:GetCommand(B)Z[#Z+1]={G;B,options={name=t.Name;description=t.Description}}end end return S:Show(Z)end B:SetIsValidInput(false,"\073\110\118\097\108\105\100 \099\111\109\109\097\110\100\046 \085\115\101 \116\104\101 \104\101\108\112 \099\111\109\109\097\110\100 \116\111 \115\101\101 \097\108\108 \097\118\097\105\108\097\098\108\101 \099\111\109\109\097\110\100\115\046")S:Hide()end B:UpdateLabel()B:UpdateWindowHeight()return{Window=B,AutoComplete=S}end


local Players = game:GetService("Players")
local Player = Players.LocalPlayer

return function (Cmdr)
	local Util = Cmdr.Util

	local Window = require(script:WaitForChild("Window"))
	Window.Cmdr = Cmdr

	local AutoComplete = require(script:WaitForChild("AutoComplete"))(Cmdr)
	Window.AutoComplete = AutoComplete


	-- Sets the Window.ProcessEntry callback so that we can dispatch our commands out
	function Window.ProcessEntry(text)
		text = Util.TrimString(text)

		if #text == 0 then return end

		Window:AddLine(Window:GetLabel() .. " " .. text, Color3.fromRGB(255, 223, 93))

		Window:AddLine(Cmdr.Dispatcher:EvaluateAndRun(text, Player, {
			IsHuman = true
		}))
	end

	-- Sets the Window.OnTextChanged callback so we can update the auto complete
	function Window.OnTextChanged (text)
		local command = Cmdr.Dispatcher:Evaluate(text, Player, true)
		local arguments = Util.SplitString(text)
		local commandText = table.remove(arguments, 1)
		local atEnd = false
		if command then
			arguments = Util.MashExcessArguments(arguments, #command.Object.Args)

			atEnd = #arguments == #command.Object.Args
		end

		local entryComplete = commandText and #arguments > 0

		if text:sub(#text, #text):match("%s") and not atEnd then
			entryComplete = true
			arguments[#arguments + 1] = ""
		end

		if command and entryComplete then
			local commandValid, errorText = command:Validate()

			Window:SetIsValidInput(commandValid, ("Validation errors: %s"):format(errorText or ""))

			local acItems = {}

			local lastArgument = command:GetArgument(#arguments)
			if lastArgument then
				local typedText = lastArgument.RawSegments[#lastArgument.RawSegments]
				local items = lastArgument:GetAutocomplete()
				for i, item in pairs(items) do
					acItems[i] = {typedText, item}
				end

				local valid = true

				if #typedText > 0 then
					valid, errorText = lastArgument:Validate()
				end

				return AutoComplete:Show(acItems, {
					at = atEnd and #text - #typedText + (text:sub(#text, #text):match("%s") and -1 or 0);
					prefix = #lastArgument.RawSegments == 1 and lastArgument.Prefix or "";
					isLast = #command.Arguments == #command.ArgumentDefinitions and #typedText > 0;
					numArgs = #arguments;
					command = command;
					arg = lastArgument;
					name = lastArgument.Name .. (lastArgument.Required and "" or "?");
					type = lastArgument.Type.DisplayName;
					description = (valid == false and errorText) or lastArgument.Object.Description;
					invalid = not valid;
				})
			end
		elseif commandText and #arguments == 0 then
			Window:SetIsValidInput(true)
			local exactCommand = Cmdr.Registry:GetCommand(commandText)
			local exactMatch
			if exactCommand then
				exactMatch = {exactCommand.Name, exactCommand.Name, options = {
					name = exactCommand.Name;
					description = exactCommand.Description;
				}}
			end

			local acItems = {exactMatch}
			for _, cmd in pairs(Cmdr.Registry:GetCommandsAsStrings()) do
				if commandText:lower() == cmd:lower():sub(1, #commandText) and (exactMatch == nil or exactMatch[1] ~= commandText) then
					local commandObject = Cmdr.Registry:GetCommand(cmd)
					acItems[#acItems + 1] = {commandText, cmd, options = {
						name = commandObject.Name;
						description = commandObject.Description;
					}}
				end
			end

			return AutoComplete:Show(acItems)
		end

		Window:SetIsValidInput(false, "Invalid command. Use the help command to see all available commands.")
		AutoComplete:Hide()
	end

	Window:UpdateLabel()
	Window:UpdateWindowHeight()

	return {
		Window = Window;
		AutoComplete = AutoComplete;
	}
end
