local g=game:GetService("\080\108\097\121\101\114\115")local V=g.LocalPlayer return function(g)local S=g.Util local I=require(script:WaitForChild("\087\105\110\100\111\119"))I.Cmdr=g local J=(require(script:WaitForChild("\065\117\116\111\067\111\109\112\108\101\116\101")))(g)I.AutoComplete=J function I.ProcessEntry(J)J=S.TrimString(J)if#J==0 then return end I:AddLine(I:GetLabel()..(" "..J),Color3.fromRGB(255,223,93))I:AddLine(g.Dispatcher:EvaluateAndRun(J,V,{IsHuman=true}))end function I.OnTextChanged(R)local s=g.Dispatcher:Evaluate(R,V,true)local j=S.SplitString(R)local X=table.remove(j,1)local l=false if s then j=S.MashExcessArguments(j,#s.Object.Args)l=#j==#s.Object.Args end local m=X and#j>0 if(R:sub(#R,#R)):match("\037\115")and not l then m=true j[#j+1]=""end if s and m then local g,V=s:Validate()I:SetIsValidInput(g,("\086\097\108\105\100\097\116\105\111\110 \101\114\114\111\114\115\058 \037\115"):format(V or""))local S={}local X=s:GetArgument(#j)if X then local g=X.TextSegmentInProgress local m=false if X.RawSegmentsAreAutocomplete then for g,V in ipairs(X.RawSegments)do S[g]={V,V}end else local V,I=X:GetAutocomplete()I=I or{}m=I.IsPartial or false for V,I in pairs(V)do S[V]={g,I}end end local D=true if#g>0 then D,V=X:Validate()end if not l and D then I:HideInvalidState()end return J:Show(S,{at=l and(#R-#g)+((R:sub(#R,#R)):match("\037\115")and-1 or 0);prefix=#X.RawSegments==1 and X.Prefix or"",isLast=#s.Arguments==#s.ArgumentDefinitions and#g>0,numArgs=#j;command=s,arg=X;name=X.Name..(X.Required and""or"\063");type=X.Type.DisplayName;description=D==false and V or X.Object.Description,invalid=not D;isPartial=m})end elseif X and#j==0 then I:SetIsValidInput(true)local V=g.Registry:GetCommand(X)local S if V then S={V.Name;V.Name,options={name=V.Name,description=V.Description}}local g=V.Args and V.Args[1]if type(g)=="\102\117\110\099\116\105\111\110"then g=g(s)end if g and(not g.Optional and g.Default==nil)then I:SetIsValidInput(false,"\084\104\105\115 \099\111\109\109\097\110\100 \104\097\115 \114\101\113\117\105\114\101\100 \097\114\103\117\109\101\110\116\115\046")I:HideInvalidState()end else I:SetIsValidInput(false,("\037\113 \105\115 \110\111\116 \097 \118\097\108\105\100 \099\111\109\109\097\110\100 \110\097\109\101\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"):format(X))end local R={S}for V,I in pairs(g.Registry:GetCommandNames())do if X:lower()==(I:lower()):sub(1,#X)and(S==nil or S[1]~=X)then local V=g.Registry:GetCommand(I)R[#R+1]={X,I;options={name=V.Name;description=V.Description}}end end return J:Show(R)end I:SetIsValidInput(false,"\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")J:Hide()end I:UpdateLabel()I:UpdateWindowHeight()return{Window=I;AutoComplete=J}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.TextSegmentInProgress

				local isPartial = false
				if lastArgument.RawSegmentsAreAutocomplete then
					for i, segment in ipairs(lastArgument.RawSegments) do
						acItems[i] = {segment, segment}
					end
				else
					local items, options = lastArgument:GetAutocomplete()
					options = options or {}
					isPartial = options.IsPartial or false

					for i, item in pairs(items) do
						acItems[i] = {typedText, item}
					end
				end

				local valid = true

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

				if not atEnd and valid then
					Window:HideInvalidState()
				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;
					isPartial = isPartial;
				})
			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;
				}}

				local arg = exactCommand.Args and exactCommand.Args[1]

				if type(arg) == "function" then
					arg = arg(command)
				end

				if
					arg
					and (not arg.Optional
					and arg.Default == nil)
				then
					Window:SetIsValidInput(false, "This command has required arguments.")
					Window:HideInvalidState()
				end
			else
				Window:SetIsValidInput(false, ("%q is not a valid command name. Use the help command to see all available commands."):format(commandText))
			end

			local acItems = {exactMatch}
			for _, cmd in pairs(Cmdr.Registry:GetCommandNames()) 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, "Use the help command to see all available commands.")
		AutoComplete:Hide()
	end

	Window:UpdateLabel()
	Window:UpdateWindowHeight()

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